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     * &amp; transparency in Firefox/Mac:
056     * 
057     * <pre>
058     * <b>Java</b>
059     * GlassPanel gp = new GlassPanel();
060     * Label content = new Label();
061     * content.setStyleName(&quot;Content&quot;);
062     * content.setSize(&quot;100%&quot;, &quot;100%&quot;);
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    }