001 002package org.opencms.ui.client.contextmenu; 003 004import com.google.gwt.user.client.DOM; 005import com.google.gwt.user.client.Event; 006import com.google.gwt.user.client.ui.FlowPanel; 007import com.google.gwt.user.client.ui.FocusWidget; 008import com.google.gwt.user.client.ui.Label; 009import com.vaadin.client.ui.Icon; 010 011/** 012 * ContextMenuItemWidget is client side widget that represents one menu item in 013 * context menu.<p> 014 * 015 * Adapted from ContextMenu by Peter Lehto / Vaadin Ltd.<p> 016 */ 017public class CmsContextMenuItemWidget extends FocusWidget { 018 019 /** The icon. */ 020 protected Icon m_icon; 021 022 /** The icon container. */ 023 private final FlowPanel m_iconContainer; 024 025 /** The id. */ 026 private String m_id; 027 028 /** The overlay. */ 029 private CmsContextMenuOverlay m_overlay; 030 031 /** The parent item. */ 032 private CmsContextMenuItemWidget m_parentItem; 033 034 /** The root panel. */ 035 private final FlowPanel m_root; 036 037 /** The root component. */ 038 private CmsContextMenuWidget m_rootComponent; 039 040 /** The sub menu. */ 041 private CmsContextMenuOverlay m_subMenu; 042 043 /** The text label. */ 044 private final Label m_text; 045 046 /** 047 * Constructor.<p> 048 */ 049 @SuppressWarnings("deprecation") 050 public CmsContextMenuItemWidget() { 051 052 m_root = new FlowPanel(); 053 m_root.setStylePrimaryName("v-context-menu-item-basic"); 054 055 setElement(m_root.getElement()); 056 057 m_root.addStyleName("v-context-submenu"); 058 059 m_iconContainer = new FlowPanel(); 060 m_iconContainer.setStyleName("v-context-menu-item-basic-icon-container"); 061 062 m_text = new Label(); 063 m_text.setStyleName("v-context-menu-item-basic-text"); 064 065 m_root.add(m_iconContainer); 066 m_root.add(m_text); 067 } 068 069 /** 070 * Adds given context menu item into the sub menu of this item.<p> 071 * 072 * @param contextMenuItem the menu item 073 */ 074 public void addSubMenuItem(CmsContextMenuItemWidget contextMenuItem) { 075 076 if (!hasSubMenu()) { 077 m_subMenu = new CmsContextMenuOverlay(); 078 m_subMenu.setOwner(m_rootComponent.getExtensionTarget()); 079 setStylePrimaryName("v-context-menu-item-basic-submenu"); 080 } 081 082 contextMenuItem.setParentItem(this); 083 m_subMenu.addMenuItem(contextMenuItem); 084 } 085 086 /** 087 * Removes all the items from the submenu of this item. If this menu item 088 * does not have a sub menu, this call has no effect.<p> 089 */ 090 public void clearItems() { 091 092 if (hasSubMenu()) { 093 m_subMenu.clearItems(); 094 } 095 } 096 097 /** 098 * Closes the sibling menu.<p> 099 */ 100 public void closeSiblingMenus() { 101 102 m_overlay.closeSubMenus(); 103 } 104 105 /** 106 * Checks whether the given event targets the menu popup.<p> 107 * 108 * @param nativeEvent the event to check 109 * 110 * @return <code>true</code> if given event targets the overlay of this menu item or 111 * overlay of any of this item's child item. 112 */ 113 public boolean eventTargetsPopup(Event nativeEvent) { 114 115 if (m_overlay.eventTargetsPopup(nativeEvent)) { 116 return true; 117 } 118 119 if (hasSubMenu()) { 120 for (CmsContextMenuItemWidget item : m_subMenu.getMenuItems()) { 121 if (item.eventTargetsPopup(nativeEvent)) { 122 return true; 123 } 124 } 125 } 126 127 return false; 128 } 129 130 /** 131 * Returns the id.<p> 132 * 133 * @return the id 134 */ 135 public String getId() { 136 137 return m_id; 138 } 139 140 /** 141 * Returns the parent item.<p> 142 * 143 * @return menu item that opened the menu to which this item belongs 144 */ 145 public CmsContextMenuItemWidget getParentItem() { 146 147 return m_parentItem; 148 } 149 150 /** 151 * Returns if the item has a sub menu.<p> 152 * 153 * @return <code>true</code> if this item has a sub menu 154 */ 155 public boolean hasSubMenu() { 156 157 return (m_subMenu != null) && (m_subMenu.getNumberOfItems() > 0); 158 } 159 160 /** 161 * Hides the sub menu that's been opened from this item.<p> 162 */ 163 public void hideSubMenu() { 164 165 if (hasSubMenu()) { 166 m_subMenu.hide(); 167 removeStyleName("v-context-menu-item-basic-open"); 168 } 169 } 170 171 /** 172 * Returns whether this is the root item.<p> 173 * 174 * @return <code>true</code> if this item is an item in the root menu 175 */ 176 public boolean isRootItem() { 177 178 return m_parentItem == null; 179 } 180 181 /** 182 * Returns if the sub menu is open.<p> 183 * 184 * @return <code>true</code> if this menu has a sub menu and it's open 185 */ 186 public boolean isSubmenuOpen() { 187 188 return hasSubMenu() && m_subMenu.isShowing(); 189 } 190 191 /** 192 * Sets the caption.<p> 193 * 194 * @param caption the caption to set 195 */ 196 public void setCaption(String caption) { 197 198 m_text.setText(caption); 199 } 200 201 /** 202 * @see com.google.gwt.user.client.ui.FocusWidget#setEnabled(boolean) 203 */ 204 @Override 205 public void setEnabled(boolean enabled) { 206 207 super.setEnabled(enabled); 208 if (enabled) { 209 m_root.removeStyleName("v-context-menu-item-disabled"); 210 } else { 211 m_root.addStyleName("v-context-menu-item-disabled"); 212 } 213 } 214 215 /** 216 * @see com.google.gwt.user.client.ui.FocusWidget#setFocus(boolean) 217 */ 218 @Override 219 public void setFocus(boolean focused) { 220 221 if (hasSubMenu()) { 222 m_subMenu.setFocus(false); 223 } 224 225 super.setFocus(focused); 226 227 if (!focused) { 228 DOM.releaseCapture(getElement()); 229 } 230 } 231 232 /** 233 * Sets the icon.<p> 234 * 235 * @param icon the icon 236 */ 237 public void setIcon(Icon icon) { 238 239 if (icon == null) { 240 m_iconContainer.clear(); 241 this.m_icon = null; 242 } else { 243 m_iconContainer.getElement().appendChild(icon.getElement()); 244 this.m_icon = icon; 245 } 246 } 247 248 /** 249 * Sets the id.<p> 250 * 251 * @param id the id 252 */ 253 public void setId(String id) { 254 255 this.m_id = id; 256 } 257 258 /** 259 * Sets the menu component to which this item belongs to.<p> 260 * 261 * @param owner the owner 262 */ 263 public void setOverlay(CmsContextMenuOverlay owner) { 264 265 this.m_overlay = owner; 266 } 267 268 /** 269 * Sets parent item meaning that this item is in the sub menu of given parent item.<p> 270 * 271 * @param parentItem the parent item 272 */ 273 public void setParentItem(CmsContextMenuItemWidget parentItem) { 274 275 this.m_parentItem = parentItem; 276 } 277 278 /** 279 * Sets the root component.<p> 280 * 281 * @param rootComponent the root component 282 */ 283 public void setRootComponent(CmsContextMenuWidget rootComponent) { 284 285 this.m_rootComponent = rootComponent; 286 } 287 288 /** 289 * Sets the separator visibility.<p> 290 * 291 * @param separatorVisible <code>true</code> to set the separator visible 292 */ 293 public void setSeparatorVisible(boolean separatorVisible) { 294 295 if (separatorVisible) { 296 m_root.addStyleName("v-context-menu-item-separator"); 297 } else { 298 m_root.removeStyleName("v-context-menu-item-separator"); 299 } 300 } 301 302 /** 303 * Closes this item and selects the parent.<p> 304 */ 305 protected void closeThisAndSelectParent() { 306 307 if (!isRootItem()) { 308 setFocus(false); 309 m_parentItem.hideSubMenu(); 310 m_parentItem.setFocus(true); 311 } 312 } 313 314 /** 315 * Called when context menu item is clicked or is focused and enter is 316 * pressed.<p> 317 * 318 * @return <code>true</code> if context menu was closed after the click 319 */ 320 protected boolean onItemClicked() { 321 322 if (isEnabled()) { 323 m_overlay.closeSubMenus(); 324 325 if (hasSubMenu()) { 326 openSubMenu(); 327 return false; 328 } else { 329 if (m_rootComponent.isHideAutomatically()) { 330 closeContextMenu(); 331 return true; 332 } 333 return false; 334 } 335 } 336 337 return false; 338 } 339 340 /** 341 * Selects the next sibling.<p> 342 */ 343 protected void selectLowerSibling() { 344 345 setFocus(false); 346 m_overlay.selectItemAfter(CmsContextMenuItemWidget.this); 347 348 } 349 350 /** 351 * Selects the previous sibling.<p> 352 */ 353 protected void selectUpperSibling() { 354 355 setFocus(false); 356 m_overlay.selectItemBefore(CmsContextMenuItemWidget.this); 357 } 358 359 /** 360 * Closes the menu.<p> 361 */ 362 private void closeContextMenu() { 363 364 if (isRootItem()) { 365 m_rootComponent.hide(); 366 } else { 367 m_parentItem.closeContextMenu(); 368 } 369 } 370 371 /** 372 * Programmatically opens the sub menu of this item.<p> 373 */ 374 private void openSubMenu() { 375 376 if (isEnabled() && hasSubMenu() && !m_subMenu.isShowing()) { 377 m_overlay.closeSubMenus(); 378 379 setFocus(false); 380 addStyleName("v-context-menu-item-basic-open"); 381 m_subMenu.openNextTo(this); 382 } 383 } 384}