View Javadoc
1   /*
2    * Copyright 2000-2014 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.Element;
19  import com.google.gwt.dom.client.NativeEvent;
20  import com.google.gwt.dom.client.Style;
21  import com.google.gwt.dom.client.TextAreaElement;
22  import com.google.gwt.dom.client.Style.Unit;
23  import com.google.gwt.event.dom.client.KeyCodes;
24  import com.google.gwt.user.client.DOM;
25  import com.google.gwt.user.client.Event;
26  import com.vaadin.client.ApplicationConnection;
27  import com.vaadin.client.ComponentConnector;
28  import com.vaadin.client.ConnectorHierarchyChangeEvent;
29  import com.vaadin.client.LayoutManager;
30  import com.vaadin.client.Paintable;
31  import com.vaadin.client.Profiler;
32  import com.vaadin.client.UIDL;
33  import com.vaadin.client.ui.AbstractSingleComponentContainerConnector;
34  import com.vaadin.client.ui.ClickEventHandler;
35  import com.vaadin.client.ui.PostLayoutListener;
36  import com.vaadin.client.ui.ShortcutActionHandler;
37  import com.vaadin.client.ui.SimpleManagedLayout;
38  import com.vaadin.client.ui.VPanel;
39  import com.vaadin.client.ui.layout.MayScrollChildren;
40  import com.vaadin.client.ui.panel.PanelConnector;
41  import com.vaadin.shared.MouseEventDetails;
42  import com.vaadin.shared.ui.ComponentStateUtil;
43  import com.vaadin.shared.ui.Connect;
44  import com.vaadin.shared.ui.panel.PanelServerRpc;
45  import com.vaadin.shared.ui.panel.PanelState;
46  import com.vaadin.ui.Panel;
47  
48  @Connect(Panel.class)
49  public class EnterFriendlyPanelConnector extends PanelConnector
50          implements Paintable, SimpleManagedLayout, PostLayoutListener,
51          MayScrollChildren {
52  
53      private Integer uidlScrollTop;
54  
55      private ClickEventHandler clickEventHandler = new ClickEventHandler(this) {
56  
57          @Override
58          protected void fireClick(NativeEvent event,
59                  MouseEventDetails mouseDetails) {
60              getRpcProxy(PanelServerRpc.class).click(mouseDetails);
61          }
62      };
63  
64      private Integer uidlScrollLeft;
65  
66      @Override
67      public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
68          if (isRealUpdate(uidl)) {
69  
70              // Handle caption displaying and style names, prior generics.
71              // Affects size calculations
72  
73              // Restore default stylenames
74              getWidget().contentNode.setClassName(VPanel.CLASSNAME + "-content");
75              getWidget().bottomDecoration.setClassName(VPanel.CLASSNAME
76                      + "-deco");
77              getWidget().captionNode.setClassName(VPanel.CLASSNAME + "-caption");
78              boolean hasCaption = false;
79              if (getState().caption != null && !"".equals(getState().caption)) {
80                  getWidget().setCaption(getState().caption);
81                  hasCaption = true;
82              } else {
83                  getWidget().setCaption("");
84                  getWidget().captionNode.setClassName(VPanel.CLASSNAME
85                          + "-nocaption");
86              }
87  
88              // Add proper stylenames for all elements. This way we can prevent
89              // unwanted CSS selector inheritance.
90              final String captionBaseClass = VPanel.CLASSNAME
91                      + (hasCaption ? "-caption" : "-nocaption");
92              final String contentBaseClass = VPanel.CLASSNAME + "-content";
93              final String decoBaseClass = VPanel.CLASSNAME + "-deco";
94              String captionClass = captionBaseClass;
95              String contentClass = contentBaseClass;
96              String decoClass = decoBaseClass;
97              if (ComponentStateUtil.hasStyles(getState())) {
98                  for (String style : getState().styles) {
99                      captionClass += " " + captionBaseClass + "-" + style;
100                     contentClass += " " + contentBaseClass + "-" + style;
101                     decoClass += " " + decoBaseClass + "-" + style;
102                 }
103             }
104             getWidget().captionNode.setClassName(captionClass);
105             getWidget().contentNode.setClassName(contentClass);
106             getWidget().bottomDecoration.setClassName(decoClass);
107 
108             getWidget().makeScrollable();
109         }
110 
111         if (!isRealUpdate(uidl)) {
112             return;
113         }
114 
115         clickEventHandler.handleEventHandlerRegistration();
116 
117         getWidget().client = client;
118         getWidget().id = uidl.getId();
119 
120         if (getIconUri() != null) {
121             getWidget().setIconUri(getIconUri(), client);
122         } else {
123             getWidget().setIconUri(null, client);
124         }
125 
126         getWidget().setErrorIndicatorVisible(null != getState().errorMessage);
127 
128         // We may have actions attached to this panel
129         if (uidl.getChildCount() > 0) {
130             final int cnt = uidl.getChildCount();
131             for (int i = 0; i < cnt; i++) {
132                 UIDL childUidl = uidl.getChildUIDL(i);
133                 if (childUidl.getTag().equals("actions")) {
134                     if (getWidget().shortcutHandler == null) {
135                         getWidget().shortcutHandler = new EnterFriendlyShortcutActionHandler(
136                                 getConnectorId(), client);
137                     }
138                     getWidget().shortcutHandler.updateActionMap(childUidl);
139                 }
140             }
141         }
142 
143         if (getState().scrollTop != getWidget().scrollTop) {
144             // Sizes are not yet up to date, so changing the scroll position
145             // is deferred to after the layout phase
146             uidlScrollTop = getState().scrollTop;
147         }
148 
149         if (getState().scrollLeft != getWidget().scrollLeft) {
150             // Sizes are not yet up to date, so changing the scroll position
151             // is deferred to after the layout phase
152             uidlScrollLeft = getState().scrollLeft;
153         }
154 
155         // And apply tab index
156         getWidget().contentNode.setTabIndex(getState().tabIndex);
157     }
158 
159     @Override
160     public void postLayout() {
161         VPanel panel = getWidget();
162         if (uidlScrollTop != null) {
163             panel.contentNode.setScrollTop(uidlScrollTop.intValue());
164             // Read actual value back to ensure update logic is correct
165             // TODO Does this trigger reflows?
166             panel.scrollTop = panel.contentNode.getScrollTop();
167             uidlScrollTop = null;
168         }
169 
170         if (uidlScrollLeft != null) {
171             panel.contentNode.setScrollLeft(uidlScrollLeft.intValue());
172             // Read actual value back to ensure update logic is correct
173             // TODO Does this trigger reflows?
174             panel.scrollLeft = panel.contentNode.getScrollLeft();
175             uidlScrollLeft = null;
176         }
177     }
178 
179     /**
180      * We override default {@link ShortcutActionHandler} to bypass shortcut handling when an 'ENTER' keyboard event comes from a text area.
181      */
182     private static class EnterFriendlyShortcutActionHandler extends ShortcutActionHandler {
183 
184         public EnterFriendlyShortcutActionHandler(String pid, ApplicationConnection c) {
185             super(pid, c);
186     }
187 
188     @Override
189         public void handleKeyboardEvent(Event event) {
190             // ignore keyboard shortcut if enter was pressed within a textarea
191             int keyCode = DOM.eventGetKeyCode(event);
192             if (keyCode == KeyCodes.KEY_ENTER) {
193                 Element el = DOM.eventGetTarget(event);
194                 if (el.getTagName().equalsIgnoreCase(TextAreaElement.TAG)) {
195                     return;
196                 }
197             }
198             super.handleKeyboardEvent(event);
199         }
200 
201     }
202 
203 }