View Javadoc
1   package org.vaadin.peter.contextmenu.client;
2   
3   import java.util.LinkedList;
4   import java.util.List;
5   
6   import com.google.gwt.dom.client.Element;
7   import com.google.gwt.dom.client.EventTarget;
8   import com.google.gwt.dom.client.NativeEvent;
9   import com.google.gwt.event.logical.shared.CloseEvent;
10  import com.google.gwt.event.logical.shared.CloseHandler;
11  import com.google.gwt.user.client.Window;
12  import com.google.gwt.user.client.ui.FlowPanel;
13  import com.google.gwt.user.client.ui.PopupPanel;
14  import com.vaadin.client.ui.VOverlay;
15  
16  /**
17   * Menu is a visible item of ContextMenu component. For every child menu new
18   * instance of Menu class will be instantiated.
19   * 
20   * @author Peter Lehto / IT Mill Oy Ltd
21   */
22  class ContextMenuOverlay extends VOverlay {
23  	private final FlowPanel root;
24  
25  	private final List<ContextMenuItemWidget> menuItems;
26  
27  	private final CloseHandler<PopupPanel> closeHandler = new CloseHandler<PopupPanel>() {
28  
29  		@Override
30  		public void onClose(CloseEvent<PopupPanel> event) {
31  			unfocusAll();
32  		}
33  	};
34  
35  	public ContextMenuOverlay() {
36  		super(false, false, true);
37  
38  		addCloseHandler(closeHandler);
39  		setStyleName("v-context-menu-container");
40  
41  		root = new FlowPanel();
42  		root.setStyleName("v-context-menu");
43  
44  		menuItems = new LinkedList<ContextMenuItemWidget>();
45  
46  		add(root);
47  	}
48  
49  	public boolean isSubmenuOpen() {
50  		for (ContextMenuItemWidget item : menuItems) {
51  			if (item.isSubmenuOpen()) {
52  				return true;
53  			}
54  		}
55  
56  		return false;
57  	}
58  
59  	private void focusFirstItem() {
60  		if (menuItems.size() > 0) {
61  			menuItems.iterator().next().setFocus(true);
62  		}
63  	}
64  
65  	public void setFocus(boolean focused) {
66  		unfocusAll();
67  
68  		if (focused) {
69  			focusFirstItem();
70  		}
71  	}
72  
73  	private void unfocusAll() {
74  		for (ContextMenuItemWidget item : menuItems) {
75  			item.setFocus(false);
76  		}
77  	}
78  
79  	protected void normalizeItemWidths() {
80  		int widestItemWidth = getWidthOfWidestItem();
81  
82  		for (ContextMenuItemWidget item : menuItems) {
83  			if (item.getOffsetWidth() <= widestItemWidth) {
84  				item.setWidth(widestItemWidth + "px");
85  			}
86  		}
87  	}
88  
89  	protected boolean eventTargetsPopup(NativeEvent event) {
90  		EventTarget target = event.getEventTarget();
91  		if (Element.is(target)) {
92  			return getElement().isOrHasChild(Element.as(target));
93  		}
94  		return false;
95  	}
96  
97  	private int getWidthOfWidestItem() {
98  		int maxWidth = 0;
99  
100 		for (ContextMenuItemWidget item : menuItems) {
101 			int itemWidth = item.getOffsetWidth() + 1;
102 
103 			if (itemWidth > maxWidth) {
104 				maxWidth = itemWidth;
105 			}
106 		}
107 
108 		return maxWidth;
109 	}
110 
111 	@Override
112 	public void hide() {
113 		unfocusAll();
114 		closeSubMenus();
115 		super.hide();
116 	}
117 
118 	public List<ContextMenuItemWidget> getMenuItems() {
119 		return menuItems;
120 	}
121 
122 	/**
123 	 * @return number of visible items in this menu
124 	 */
125 	public int getNumberOfItems() {
126 		return this.menuItems.size();
127 	}
128 
129 	public void openNextTo(ContextMenuItemWidget parentMenuItem) {
130 		int left = parentMenuItem.getAbsoluteLeft()
131 				+ parentMenuItem.getOffsetWidth();
132 		int top = parentMenuItem.getAbsoluteTop();
133 
134         showAt(left, top);
135 	}
136 
137 	public void closeSubMenus() {
138 		for (ContextMenuItemWidget child : menuItems) {
139 			child.hideSubMenu();
140 		}
141 	}
142 
143 	public void selectItemBefore(ContextMenuItemWidget item) {
144 		int index = menuItems.indexOf(item);
145 
146 		index -= 1;
147 
148 		if (index < 0) {
149 			index = menuItems.size() - 1;
150 		}
151 
152 		ContextMenuItemWidget itemToSelect = menuItems.get(index);
153 		itemToSelect.setFocus(true);
154 	}
155 
156 	public void selectItemAfter(ContextMenuItemWidget item) {
157 		int index = menuItems.indexOf(item);
158 
159 		index += 1;
160 
161 		if (index >= menuItems.size()) {
162 			index = 0;
163 		}
164 
165 		ContextMenuItemWidget itemToSelect = menuItems.get(index);
166 		itemToSelect.setFocus(true);
167 	}
168 
169 	public void addMenuItem(ContextMenuItemWidget menuItem) {
170 		menuItem.setOverlay(this);
171 
172 		menuItems.add(menuItem);
173 		root.add(menuItem);
174 	}
175 
176 	public void clearItems() {
177 		menuItems.clear();
178 		root.clear();
179 	}
180 
181     public void showAt(final int x, final int y) {
182         setPopupPositionAndShow(new PopupPanel.PositionCallback() {
183             @Override
184             public void setPosition(int offsetWidth, int offsetHeight) {
185                 int left = x + Window.getScrollLeft();
186                 int top = y + Window.getScrollTop();
187 
188                 int exceedingWidth = (offsetWidth + left) - (Window.getClientWidth() + Window.getScrollLeft());
189                 if (exceedingWidth > 0) {
190                     left -= exceedingWidth;
191                     if (left < 0) {
192                         left = 0;
193                     }
194                 }
195 
196                 int exceedingHeight = (offsetHeight + top) - (Window.getClientHeight() + Window.getScrollTop());
197                 if (exceedingHeight > 0) {
198                     top -= exceedingHeight;
199                     if (top < 0) {
200                         top = 0;
201                     }
202                 }
203 
204                 setPopupPosition(left, top);
205             }
206         });
207 
208         normalizeItemWidths();
209     }
210 }