001 /*
002 * Copyright 2006 Mat Gessel <mat.gessel@gmail.com>
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
005 * use this file except in compliance with the License. You may obtain a copy of
006 * the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
012 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
013 * License for the specific language governing permissions and limitations under
014 * the License.
015 */
016 package asquare.gwt.tk.client.ui;
017
018 import java.util.List;
019 import java.util.Vector;
020
021 import asquare.gwt.tk.client.ui.behavior.GlassPanelController;
022 import asquare.gwt.tk.client.util.DomUtil;
023
024 import com.google.gwt.core.client.GWT;
025 import com.google.gwt.user.client.DOM;
026 import com.google.gwt.user.client.Element;
027 import com.google.gwt.user.client.ui.RootPanel;
028 import com.google.gwt.user.client.ui.Widget;
029 import com.google.gwt.user.client.ui.impl.PopupImpl;
030
031 /**
032 * A panel which covers the entire viewport or document, whichever is larger.
033 * The GlassPanel prevents interaction with the document. Useful for modal
034 * dialogs and the "lightbox" effect. Window resizing logic is handled in a
035 * pluggable controller whose implementation varies by platform. When the
036 * GlassPanel is shown, a style name is applied to the body element; the style
037 * name is removed when the GlassPanel is hidden.
038 * <h3>CSS Style Rules</h3>
039 * <ul class='css'>
040 * <li>.tk-GlassPanel { }</li>
041 * <li>.body-GlassPanelShowing { added to the BODY element when a GlassPanel is
042 * shown }</li>
043 * </ul>
044 * CSS Example
045 *
046 * <pre>
047 * .tk-GlassPanel {
048 * background: black;
049 * opacity: 0.2;
050 * filter: alpha(opacity=20);
051 * }
052 * </pre>
053 *
054 * This example uses a transparent PNG background to workaround a bug with Flash
055 * & transparency in Firefox/Mac:
056 *
057 * <pre>
058 * <b>Java</b>
059 * GlassPanel gp = new GlassPanel();
060 * Label content = new Label();
061 * content.setStyleName("Content");
062 * content.setSize("100%", "100%");
063 * gp.add(content);
064 * gp.show();
065 * </pre>
066 *
067 * <pre>
068 * <b>CSS</b>
069 * .tk-GlassPanel {
070 * filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='Gray20.png', sizingMethod='scale');
071 * }
072 * .tk-GlassPanel .Content
073 * background: url('Gray20.png');
074 * filter: alpha(opacity=0);
075 * }
076 * </pre>
077 *
078 * The filter rule applies transparency in IE.
079 *
080 * @see <a href="http://www.quirksmode.org/css/opacity.html">opacity on
081 * quirksmode</a>
082 * @see <a href="http://msdn2.microsoft.com/en-us/library/ms532853.aspx">Filters
083 * for IE</a>
084 */
085 public class GlassPanel extends CComplexPanel
086 {
087 public static final String DEFAULT_BODY_STYLENAME = "body-GlassPanelShowing";
088
089 private static final PopupImpl m_impl = (PopupImpl) GWT.create(PopupImpl.class);
090
091 private String m_bodyStyleName;
092
093 /**
094 * Creates a GlassPanel based on a div.
095 */
096 public GlassPanel()
097 {
098 this(DEFAULT_BODY_STYLENAME);
099 }
100
101 /**
102 * Creates a GlassPanel based the specified element.
103 */
104 public GlassPanel(Element element)
105 {
106 this(element, DEFAULT_BODY_STYLENAME);
107 }
108
109 /**
110 * Creates a GlassPanel based on a div. If not null,
111 * <code>bodyStyleName</code> will applied to the body element for the
112 * duration that the GlassPanel is visible.
113 *
114 * @param bodyStyleName a CSS class name, or <code>null</code>
115 */
116 public GlassPanel(String bodyStyleName)
117 {
118 this(DOM.createDiv(), bodyStyleName);
119 }
120
121 /**
122 * Creates a GlassPanel based the specified element. If not null,
123 * <code>bodyStyleName</code> will applied to the body element for the
124 * duration that the GlassPanel is visible.
125 *
126 * @param element an element
127 * @param bodyStyleName a CSS class name, or <code>null</code>
128 */
129 public GlassPanel(Element element, String bodyStyleName)
130 {
131 super(element);
132 m_bodyStyleName = bodyStyleName;
133 setStyleName("tk-GlassPanel");
134 }
135
136 /*
137 * (non-Javadoc)
138 * @see asquare.gwt.tk.client.ui.CComplexPanel#createControllers()
139 */
140 protected List createControllers()
141 {
142 List result = new Vector();
143 result.add(GWT.create(GlassPanelController.class));
144 return result;
145 }
146
147 /**
148 * Gets the style name which will be applied to the body element while the
149 * GlassPanel is shown.
150 *
151 * @return a String or <code>null</code>
152 */
153 public String getBodyStyleName()
154 {
155 return m_bodyStyleName;
156 }
157
158 /**
159 * Sets the style name which will be applied to the body element while the
160 * GlassPanel is shown.
161 *
162 * @param bodyStyleName a CSS class name, or <code>null</code>
163 */
164 public void setBodyStyleName(String bodyStyleName)
165 {
166 m_bodyStyleName = bodyStyleName;
167 }
168
169 /*
170 * (non-Javadoc)
171 * @see com.google.gwt.user.client.ui.HasWidgets#add(com.google.gwt.user.client.ui.Widget)
172 */
173 public void add(Widget w)
174 {
175 add(w, getElement());
176 }
177
178 /**
179 * Positions the GlassPanel, then makes it visible by appending it to the
180 * RootPanel.
181 */
182 public void show()
183 {
184 if (m_bodyStyleName != null)
185 {
186 RootPanel.get().addStyleName(m_bodyStyleName);
187 }
188 /*
189 * Need to set the position to (0,0) first, so that the panel itself does
190 * not alter document size measurements made later.
191 */
192 DomUtil.setStyleAttribute(this, "position", "absolute");
193 DomUtil.setStyleAttribute(this, "left", "0px");
194 DomUtil.setStyleAttribute(this, "top", "0px");
195 RootPanel.get().add(this);
196 m_impl.onShow(getElement());
197 }
198
199 /**
200 * Hides the GlassPanel by detaching it from the RootPanel.
201 */
202 public void hide()
203 {
204 m_impl.onHide(getElement());
205 RootPanel.get().remove(this);
206 if (m_bodyStyleName != null)
207 {
208 RootPanel.get().removeStyleName(m_bodyStyleName);
209 }
210 }
211 }