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
18
19
20
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
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 }