View Javadoc
1   /*
2    * Copyright 2000-2013 Vaadin Ltd.
3    * 
4    * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5    * use this file except in compliance with the License. You may obtain a copy of
6    * the License at
7    * 
8    * http://www.apache.org/licenses/LICENSE-2.0
9    * 
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13   * License for the specific language governing permissions and limitations under
14   * the License.
15   */
16  package com.vaadin.client.ui.panel;
17  
18  import com.google.gwt.dom.client.NativeEvent;
19  import com.google.gwt.dom.client.Style;
20  import com.google.gwt.dom.client.Style.Unit;
21  import com.vaadin.client.ApplicationConnection;
22  import com.vaadin.client.ComponentConnector;
23  import com.vaadin.client.ConnectorHierarchyChangeEvent;
24  import com.vaadin.client.LayoutManager;
25  import com.vaadin.client.Paintable;
26  import com.vaadin.client.Profiler;
27  import com.vaadin.client.UIDL;
28  import com.vaadin.client.ui.AbstractSingleComponentContainerConnector;
29  import com.vaadin.client.ui.ClickEventHandler;
30  import com.vaadin.client.ui.PostLayoutListener;
31  import com.vaadin.client.ui.ShortcutActionHandler;
32  import com.vaadin.client.ui.SimpleManagedLayout;
33  import com.vaadin.client.ui.VPanel;
34  import com.vaadin.client.ui.layout.MayScrollChildren;
35  import com.vaadin.shared.MouseEventDetails;
36  import com.vaadin.shared.ui.ComponentStateUtil;
37  import com.vaadin.shared.ui.Connect;
38  import com.vaadin.shared.ui.panel.PanelServerRpc;
39  import com.vaadin.shared.ui.panel.PanelState;
40  import com.vaadin.ui.Panel;
41  
42  @Connect(Panel.class)
43  public class PanelConnector extends AbstractSingleComponentContainerConnector
44          implements Paintable, SimpleManagedLayout, PostLayoutListener,
45          MayScrollChildren {
46  
47      private Integer uidlScrollTop;
48  
49      private ClickEventHandler clickEventHandler = new ClickEventHandler(this) {
50  
51          @Override
52          protected void fireClick(NativeEvent event,
53                  MouseEventDetails mouseDetails) {
54              getRpcProxy(PanelServerRpc.class).click(mouseDetails);
55          }
56      };
57  
58      private Integer uidlScrollLeft;
59  
60      @Override
61      public void init() {
62          super.init();
63          VPanel panel = getWidget();
64          LayoutManager layoutManager = getLayoutManager();
65  
66          layoutManager.registerDependency(this, panel.captionNode);
67          layoutManager.registerDependency(this, panel.bottomDecoration);
68          layoutManager.registerDependency(this, panel.contentNode);
69      }
70  
71      @Override
72      public void onUnregister() {
73          VPanel panel = getWidget();
74          LayoutManager layoutManager = getLayoutManager();
75  
76          layoutManager.unregisterDependency(this, panel.captionNode);
77          layoutManager.unregisterDependency(this, panel.bottomDecoration);
78          layoutManager.unregisterDependency(this, panel.contentNode);
79      }
80  
81      @Override
82      public boolean delegateCaptionHandling() {
83          return false;
84      }
85  
86      @Override
87      public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
88          if (isRealUpdate(uidl)) {
89  
90              // Handle caption displaying and style names, prior generics.
91              // Affects size calculations
92  
93              // Restore default stylenames
94              getWidget().contentNode.setClassName(VPanel.CLASSNAME + "-content");
95              getWidget().bottomDecoration.setClassName(VPanel.CLASSNAME
96                      + "-deco");
97              getWidget().captionNode.setClassName(VPanel.CLASSNAME + "-caption");
98              boolean hasCaption = false;
99              if (getState().caption != null && !"".equals(getState().caption)) {
100                 getWidget().setCaption(getState().caption);
101                 hasCaption = true;
102             } else {
103                 getWidget().setCaption("");
104                 getWidget().captionNode.setClassName(VPanel.CLASSNAME
105                         + "-nocaption");
106             }
107 
108             // Add proper stylenames for all elements. This way we can prevent
109             // unwanted CSS selector inheritance.
110             final String captionBaseClass = VPanel.CLASSNAME
111                     + (hasCaption ? "-caption" : "-nocaption");
112             final String contentBaseClass = VPanel.CLASSNAME + "-content";
113             final String decoBaseClass = VPanel.CLASSNAME + "-deco";
114             String captionClass = captionBaseClass;
115             String contentClass = contentBaseClass;
116             String decoClass = decoBaseClass;
117             if (ComponentStateUtil.hasStyles(getState())) {
118                 for (String style : getState().styles) {
119                     captionClass += " " + captionBaseClass + "-" + style;
120                     contentClass += " " + contentBaseClass + "-" + style;
121                     decoClass += " " + decoBaseClass + "-" + style;
122                 }
123             }
124             getWidget().captionNode.setClassName(captionClass);
125             getWidget().contentNode.setClassName(contentClass);
126             getWidget().bottomDecoration.setClassName(decoClass);
127 
128             getWidget().makeScrollable();
129         }
130 
131         if (!isRealUpdate(uidl)) {
132             return;
133         }
134 
135         clickEventHandler.handleEventHandlerRegistration();
136 
137         getWidget().client = client;
138         getWidget().id = uidl.getId();
139 
140         if (getIcon() != null) {
141             getWidget().setIconUri(getIcon(), client);
142         } else {
143             getWidget().setIconUri(null, client);
144         }
145 
146         getWidget().setErrorIndicatorVisible(null != getState().errorMessage);
147 
148         // We may have actions attached to this panel
149         if (uidl.getChildCount() > 0) {
150             final int cnt = uidl.getChildCount();
151             for (int i = 0; i < cnt; i++) {
152                 UIDL childUidl = uidl.getChildUIDL(i);
153                 if (childUidl.getTag().equals("actions")) {
154                     if (getWidget().shortcutHandler == null) {
155                         getWidget().shortcutHandler = new ShortcutActionHandler(
156                                 getConnectorId(), client);
157                     }
158                     getWidget().shortcutHandler.updateActionMap(childUidl);
159                 }
160             }
161         }
162 
163         if (getState().scrollTop != getWidget().scrollTop) {
164             // Sizes are not yet up to date, so changing the scroll position
165             // is deferred to after the layout phase
166             uidlScrollTop = getState().scrollTop;
167         }
168 
169         if (getState().scrollLeft != getWidget().scrollLeft) {
170             // Sizes are not yet up to date, so changing the scroll position
171             // is deferred to after the layout phase
172             uidlScrollLeft = getState().scrollLeft;
173         }
174 
175         // And apply tab index
176         getWidget().contentNode.setTabIndex(getState().tabIndex);
177     }
178 
179     @Override
180     public void updateCaption(ComponentConnector component) {
181         // NOP: layouts caption, errors etc not rendered in Panel
182     }
183 
184     @Override
185     public VPanel getWidget() {
186         return (VPanel) super.getWidget();
187     }
188 
189     @Override
190     public void layout() {
191         updateSizes();
192     }
193 
194     void updateSizes() {
195         VPanel panel = getWidget();
196 
197         LayoutManager layoutManager = getLayoutManager();
198         Profiler.enter("PanelConnector.layout getHeights");
199         int top = layoutManager.getOuterHeight(panel.captionNode);
200         int bottom = layoutManager.getInnerHeight(panel.bottomDecoration);
201         Profiler.leave("PanelConnector.layout getHeights");
202 
203         Profiler.enter("PanelConnector.layout modify style");
204         Style style = panel.getElement().getStyle();
205         panel.captionNode.getParentElement().getStyle()
206                 .setMarginTop(-top, Unit.PX);
207         panel.bottomDecoration.getStyle().setMarginBottom(-bottom, Unit.PX);
208         style.setPaddingTop(top, Unit.PX);
209         style.setPaddingBottom(bottom, Unit.PX);
210         Profiler.leave("PanelConnector.layout modify style");
211 
212         // Update scroll positions
213         Profiler.enter("PanelConnector.layout update scroll positions");
214         panel.contentNode.setScrollTop(panel.scrollTop);
215         panel.contentNode.setScrollLeft(panel.scrollLeft);
216         Profiler.leave("PanelConnector.layout update scroll positions");
217 
218         // Read actual value back to ensure update logic is correct
219         Profiler.enter("PanelConnector.layout read scroll positions");
220         panel.scrollTop = panel.contentNode.getScrollTop();
221         panel.scrollLeft = panel.contentNode.getScrollLeft();
222         Profiler.leave("PanelConnector.layout read scroll positions");
223     }
224 
225     @Override
226     public void postLayout() {
227         VPanel panel = getWidget();
228         if (uidlScrollTop != null) {
229             panel.contentNode.setScrollTop(uidlScrollTop.intValue());
230             // Read actual value back to ensure update logic is correct
231             // TODO Does this trigger reflows?
232             panel.scrollTop = panel.contentNode.getScrollTop();
233             uidlScrollTop = null;
234         }
235 
236         if (uidlScrollLeft != null) {
237             panel.contentNode.setScrollLeft(uidlScrollLeft.intValue());
238             // Read actual value back to ensure update logic is correct
239             // TODO Does this trigger reflows?
240             panel.scrollLeft = panel.contentNode.getScrollLeft();
241             uidlScrollLeft = null;
242         }
243     }
244 
245     @Override
246     public PanelState getState() {
247         return (PanelState) super.getState();
248     }
249 
250     @Override
251     public void onConnectorHierarchyChange(ConnectorHierarchyChangeEvent event) {
252         // We always have 1 child, unless the child is hidden
253         getWidget().setWidget(getContentWidget());
254     }
255 
256 }