/* * Copyright (c) 2003,2009 Declarative Engineering LLC. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Declarative Engineering LLC * verson 1 which accompanies this distribution, and is available at * http://declarativeengineering.com/legal/DE_Developer_License_v1.txt */ package com.foundation.tcv.swt.client; import org.eclipse.swt.SWT; import org.eclipse.swt.events.*; import org.eclipse.swt.widgets.Shell; import com.common.util.*; import com.common.debug.*; import com.foundation.tcv.client.view.ResourceHolder; import com.foundation.tcv.model.LinkInfo; import com.foundation.tcv.swt.*; import com.foundation.tcv.view.*; import com.foundation.view.JefImage; import com.foundation.view.LinkData; public class Menu extends AbstractComponent implements SelectionListener, IMenu, IAbstractMenu { /** The menu style. */ private int style = 0; /** The menu's parent component. */ private AbstractComponent parent = null; /** An internal flag to assist in determining whether this menu is allowed to have sub-menus. */ private boolean canHaveSubMenus = false; /** A collection of sub menus. */ private IList subMenus = null; /** Non-null if the menu is a bar, pop up, or cascade type menu. */ private org.eclipse.swt.widgets.Menu swtMenu = null; /** Non-null if the menu is a cascade, push, radio, check, or separator type menu. */ private org.eclipse.swt.widgets.MenuItem swtMenuItem = null; /** Whether the menu item supports a selection state. If this is false then selections are sent immediatly to the server. */ private boolean isStateful = false; /** Whether the method called when the menu is pressed should be performed on the UI thread. */ private boolean synchronousSelection = false; /** The linkage for the selection. */ private Linkage selectionLinkage = new Linkage(); /** A holder for the value of the text. */ private ResourceHolder textHolder = new ResourceHolder(this); /** A holder for the value of the image. */ private ResourceHolder imageHolder = new ResourceHolder(this); /** A holder for the value of the visibility flag. */ private ResourceHolder isVisibleHolder = new ResourceHolder(this); /** A holder for the value of the enabled state flag. */ private ResourceHolder isEnabledHolder = new ResourceHolder(this); /** The current value for the visibility of the menu. This stores the visiblity even if the menu control is not currently created. */ private boolean isVisibleValue = true; /** The current value for the enabled state of the menu. This stores the enabled state even if the menu control is not currently created. */ private boolean isEnabledValue = true; /** The current value for the selection state of the menu. This stores the selection state even if the menu control is not currently created. */ private boolean isSelectedValue = false; /** The current value for the menu's text. This stores the text even if the menu control is not currently created. */ private String textValue = null; /** The current value for the menu's image. This stores the image even if the menu control is not currently created. */ private JefImage imageValue = null; /** The accelerator for the menu item. */ private int acceleratorValue = 0; /** * Menu constructor. */ public Menu() { }//Menu()// /** * Gets the collection of all sub menus. * @return A collection of menus, or null if this menu cannot hold other menus. */ private IList getSubMenus() { if((canHaveSubMenus) && (subMenus == null)) { subMenus = new LiteList(10, 30); }//if// return subMenus; }//getSubMenus()// /** * Adds a sub menu to this menu. * @param subMenu The sub menu to be added. Must also implement IAbstractMenu. */ public void addSubMenu(AbstractComponent subMenu) { if(!isInitialized()) { if(subMenu instanceof IAbstractMenu) { getSubMenus().add(subMenu); }//if// else { throw new RuntimeException(); }//else// }//if// }//addSubMenu()// /** * Gets the SWT menu item that represents this menu. * @return The SWT menu item providing visualization for this menu. */ public org.eclipse.swt.widgets.MenuItem getSwtMenuItem() { return (org.eclipse.swt.widgets.MenuItem) swtMenuItem; }//getSwtMenuItem()// /** * Gets the SWT menu that represents this menu. * @return The SWT menu providing visualization for this menu. */ public org.eclipse.swt.widgets.Menu getSwtMenu() { return (org.eclipse.swt.widgets.Menu) swtMenu; }//getSwtMenu()// /** * Gets the parent component for this component. * @return The view component containing this component. This will not be null, and may be a Component or another Menu instance. */ public AbstractComponent getParent() { return parent; }//getParent()// /* (non-Javadoc) * @see com.foundation.tcv.swt.client.AbstractComponent#getShell() */ public Shell getShell() { return getParent() != null ? getParent().getShell() : null; }//getShell()// /** * Gets the container nearest the menu. * @return The nearest container to this menu. */ /* (non-Javadoc) * @see com.foundation.tcv.swt.client.AbstractComponent#getContainer() */ public Container getContainer() { AbstractComponent component = getParent(); while(!(component instanceof Component)) { component = ((Menu) component).getParent(); }//while// return component instanceof Container ? (Container) component : ((Component) component).getContainer(); }//getContainer()// /* (non-Javadoc) * @see com.foundation.tcv.swt.client.AbstractComponent#internalProcessMessage(com.foundation.tcv.model.ViewMessage) */ public Object internalProcessMessage(ViewMessage viewMessage) { Object result = null; switch(viewMessage.getMessageNumber()) { case MESSAGE_INITIALIZE: { if((getSwtMenu() == null) && (getSwtMenuItem() == null)) { style = viewMessage.getMessageSecondaryInteger(); parent = getComponent(viewMessage.getMessageInteger()); if((style & STYLE_CASCADE) > 0) { canHaveSubMenus = true; ((Menu) getParent()).addSubMenu(this); if(getParent() instanceof Menu && (((Menu) getParent()).style & STYLE_BAR) > 0) { loadMenu(); swtMenu.addMenuListener(new MenuListener() { boolean isLoaded = false; public void menuShown(MenuEvent e) { if(isLoaded) { unloadMenuChildren(); }//if// loadMenuChildren(); }//menuShown()// public void menuHidden(MenuEvent e) { isLoaded = true; }//menuHidden()// }); }//if// }//if// else if((style & STYLE_BAR) > 0) { org.eclipse.swt.widgets.Control parentControl = getParent() instanceof Component ? ((Component) getParent()).getSwtControl() : ((AbstractComponent) getParent()).getShell(); //Setup the popup menu or menu bar depending on the style.// if(parentControl instanceof org.eclipse.swt.widgets.Decorations) { swtMenu = new org.eclipse.swt.widgets.Menu((org.eclipse.swt.widgets.Decorations) parentControl, SWT.BAR); //(style ^ STYLE_BAR) | ((org.eclipse.swt.widgets.Decorations) parentControl).setMenuBar(swtMenu); canHaveSubMenus = true; swtMenu.setData(this); setSwtWidget(swtMenu); if(getParent() instanceof IDecoration) { ((IDecoration) getParent()).setMenuBar(this); }//if// else { Debug.log("Error: The component must be an IDecoration to have a menu bar: " + getParent().getClass().getName()); }//else// }//if// else { Debug.log("Error: Cannot have a menu bar in a control that does not inherit from SWT's Decorations class."); }//else// }//else if// else if((style & STYLE_POPUP) > 0) { org.eclipse.swt.widgets.Control control = getParent() instanceof Component ? ((Component) getParent()).getSwtControl() : ((AbstractComponent) getParent()).getShell(); swtMenu = new org.eclipse.swt.widgets.Menu(control); canHaveSubMenus = true; swtMenu.setData(this); swtMenu.addMenuListener(new MenuListener() { boolean isLoaded = false; public void menuShown(MenuEvent e) { if(isLoaded) { unloadMenuChildren(); }//if// loadMenuChildren(); }//menuShown()// public void menuHidden(MenuEvent e) { isLoaded = true; }//menuHidden()// }); setSwtWidget(swtMenu); ((AbstractComponent) getParent()).setMenu(this); }//else if// else { ((Menu) getParent()).addSubMenu(this); isStateful = ((style & Menu.STYLE_CHECK) > 0) || ((style & Menu.STYLE_RADIO) > 0); }//else// }//if// break; }//case// case MESSAGE_SET_TEXT: { textHolder.setValue(viewMessage.getMessageData()); break; }//case// case MESSAGE_SET_IMAGE: { imageHolder.setValue(viewMessage.getMessageData()); break; }//case// case MESSAGE_SET_ACCELERATOR: { acceleratorValue = ((Integer) viewMessage.getMessageData()).intValue(); if(getSwtMenuItem() != null) { getSwtMenuItem().setAccelerator(acceleratorValue); }//if// break; }//case// case MESSAGE_SET_IS_SELECTED: { Boolean isSelected = (Boolean) viewMessage.getMessageData(); isSelectedValue = isSelected != null ? isSelected.booleanValue() : false; //Only set the selection if it has changed.// if((getSwtMenuItem() != null) && (!getSwtMenuItem().isDisposed()) && (getSwtMenuItem().getSelection() != isSelectedValue)) { getSwtMenuItem().setSelection(isSelectedValue); //Send feedback to the server updating its state. This is necessary to avoid data corruption given the client and server run on different threads.// sendMessage(MESSAGE_VIEW_SYNCHRONIZE_SELECTION, isSelectedValue ? Boolean.TRUE : Boolean.FALSE); selectionLinkage.invoke(isSelected); }//if// break; }//case// case MESSAGE_SET_LOCATION: { int[] point = (int[]) viewMessage.getMessageData(); //Note: This is safe since this should only ever be performed on a floating menu.// if(getSwtMenu() != null && !getSwtMenu().isDisposed()) { getSwtMenu().setLocation(point[0], point[1]); }//if// break; }//case// case MESSAGE_SET_IS_VISIBLE: { isVisibleHolder.setValue(viewMessage.getMessageData()); break; }//case// case MESSAGE_SET_IS_ENABLED: { isEnabledHolder.setValue(viewMessage.getMessageData()); break; }//case// case MESSAGE_SET_SYNCHRONOUS_SELECTION: { synchronousSelection = ((Boolean) viewMessage.getMessageData()).booleanValue(); break; }//case// case MESSAGE_ADD_SELECTION_LINK: { LinkInfo info = (LinkInfo) viewMessage.getMessageData(); selectionLinkage.add(new LinkData(getComponent(info.getComponent()), info.getTarget(), info.getData(), info.isBoolean(), info.invertLogic(), info.nullValue())); break; }//case// default: { result = super.internalProcessMessage(viewMessage); }//default// }//switch// return result; }//internalProcessMessage()// /* (non-Javadoc) * @see com.foundation.tcv.swt.client.AbstractComponent#internalViewInitializeAll() */ protected void internalViewInitializeAll() { super.internalViewInitializeAll(); //Initialize sub-menus.// if((getSubMenus() != null) && (getSubMenus().getSize() > 0)) { IIterator iterator = getSubMenus().iterator(); while(iterator.hasNext()) { Menu next = (Menu) iterator.next(); next.internalViewInitializeAll(); }//while// }//if// }//internalViewInitializeAll()// /* (non-Javadoc) * @see com.foundation.tcv.swt.client.AbstractComponent#internalViewReleaseAll() */ protected void internalViewReleaseAll() { //Release sub-menus.// if((getSubMenus() != null) && (getSubMenus().getSize() > 0)) { IIterator iterator = getSubMenus().iterator(); while(iterator.hasNext()) { Menu next = (Menu) iterator.next(); next.internalViewReleaseAll(); }//while// }//if// super.internalViewReleaseAll(); }//internalViewReleaseAll()// /* (non-Javadoc) * @see com.foundation.tcv.swt.client.AbstractComponent#internalViewSynchronizeAll() */ protected void internalViewSynchronizeAll() { super.internalViewSynchronizeAll(); //Synchronize sub-menus.// if((getSubMenus() != null) && (getSubMenus().getSize() > 0)) { IIterator iterator = getSubMenus().iterator(); while(iterator.hasNext()) { Menu next = (Menu) iterator.next(); next.internalViewSynchronizeAll(); }//while// }//if// }//internalViewSynchronizeAll()// /* (non-Javadoc) * @see com.foundation.tcv.swt.client.AbstractComponent#internalViewInitialize() */ protected void internalViewInitialize() { super.internalViewInitialize(); }//internalViewInitialize()// /* (non-Javadoc) * @see com.foundation.tcv.swt.client.AbstractComponent#internalViewRelease() */ protected void internalViewRelease() { textHolder.release(); imageHolder.release(); isVisibleHolder.release(); isEnabledHolder.release(); if(imageValue != null && getSwtMenuItem() != null) { destroyImage(imageValue); imageValue = null; }//if// if(getSwtMenu() != null && !getSwtMenu().isDisposed()) { getSwtMenu().dispose(); }//if// if(getSwtMenuItem() != null && !getSwtMenuItem().isDisposed()) { getSwtMenuItem().removeSelectionListener(this); getSwtMenuItem().dispose(); }//if// super.internalViewRelease(); }//internalViewRelease()// /* (non-Javadoc) * @see com.foundation.tcv.swt.client.AbstractComponent#internalViewSynchronize() */ protected void internalViewSynchronize() { super.internalViewSynchronize(); }//internalViewSynchronize()// /* (non-Javadoc) * @see com.foundation.tcv.swt.client.AbstractComponent#internalOnLinkInvoked(int, java.lang.Object) */ protected void internalOnLinkInvoked(int linkTarget, Object data) { switch(linkTarget) { case LINK_TARGET_IS_VISIBLE: { isVisibleValue = data != null && data instanceof Boolean ? ((Boolean) data).booleanValue() : false; if(getSwtMenu() != null && !getSwtMenu().isDisposed()) { getSwtMenu().setVisible(isVisibleValue); }//if// break; }//case// case LINK_TARGET_IS_ENABLED: { isEnabledValue = data != null && data instanceof Boolean ? ((Boolean) data).booleanValue() : false; if(getSwtMenu() != null && !getSwtMenu().isDisposed()) { getSwtMenu().setEnabled(isEnabledValue); }//if// if(getSwtMenuItem() != null && !getSwtMenuItem().isDisposed()) { getSwtMenuItem().setEnabled(isEnabledValue); }//if// break; }//case// case LINK_TARGET_SELECTION: { isSelectedValue = data instanceof Boolean ? ((Boolean) data).booleanValue() : false; if(getSwtMenuItem() != null && !getSwtMenuItem().isDisposed()) { if((isStateful) && (isSelectedValue != getSwtMenuItem().getSelection())) { getSwtMenuItem().setSelection(isSelectedValue); selectionChanged(isSelectedValue); }//if// else { selectionChanged(true); }//else// }//if// break; }//case// case LINK_TARGET_IMAGE: { if(data instanceof JefImage) { imageValue = (JefImage) data; if(getSwtMenuItem() != null && !getSwtMenuItem().isDisposed()) { destroyImage(getSwtMenuItem().getImage()); getSwtMenuItem().setImage(createImage(imageValue)); }//if// }//if// break; }//case// case LINK_TARGET_TEXT: { textValue = data instanceof String ? (String) data : ""; if(getSwtMenuItem() != null && !getSwtMenuItem().isDisposed()) { getSwtMenuItem().setText(textValue); }//if// break; }//case// default: { super.internalOnLinkInvoked(linkTarget, data); break; }//default// }//switch// }//internalOnLinkInvoked()// /* (non-Javadoc) * @see com.foundation.tcv.swt.client.AbstractComponent#internalResourceHolderChanged(com.foundation.tcv.client.view.ResourceHolder, java.lang.Object, java.lang.Object, int) */ protected void internalResourceHolderChanged(ResourceHolder resource, Object oldValue, Object newValue, int flags) { if(resource == textHolder) { textValue = newValue != null ? (String) newValue : ""; if(getSwtMenuItem() != null && !getSwtMenuItem().isDisposed()) { getSwtMenuItem().setText(textValue); }//if// }//if// else if(resource == imageHolder) { imageValue = (JefImage) newValue; if(getSwtMenuItem() != null && !getSwtMenuItem().isDisposed()) { destroyImage(getSwtMenuItem().getImage()); getSwtMenuItem().setImage(createImage(imageValue)); }//if// }//else if// else if(resource == isVisibleHolder) { isVisibleValue = ((Boolean) newValue).booleanValue(); if(getSwtMenuItem() != null && !getSwtMenuItem().isDisposed()) { //getSwtMenuItem().setVisible(isVisibleValue); }//if// if(getSwtMenu() != null && !getSwtMenu().isDisposed()) { getSwtMenu().setVisible(isVisibleValue); }//if// }//else if// else if(resource == isEnabledHolder) { isEnabledValue = ((Boolean) newValue).booleanValue(); if(getSwtMenuItem() != null && !getSwtMenuItem().isDisposed()) { getSwtMenuItem().setEnabled(isEnabledValue); }//if// if(getSwtMenu() != null && !getSwtMenu().isDisposed()) { getSwtMenu().setEnabled(isEnabledValue); }//if// }//else if// else { super.internalResourceHolderChanged(resource, oldValue, newValue, flags); }//else// }//internalOnAssociationChanged()// /* (non-Javadoc) * @see org.eclipse.swt.events.SelectionListener#widgetDefaultSelected(org.eclipse.swt.events.SelectionEvent) */ public void widgetDefaultSelected(SelectionEvent event) { widgetSelected(event); }//widgetDefaultSelected()// /* (non-Javadoc) * @see org.eclipse.swt.events.SelectionListener#widgetSelected(org.eclipse.swt.events.SelectionEvent) */ public void widgetSelected(SelectionEvent event) { selectionChanged(getSwtMenuItem().getSelection()); }//widgetSelected()// /** * Called when the selection is changed in the view control. * This method updates all bindings and * @param isSelected Whether the control is selected (stateful controls only). */ protected void selectionChanged(boolean isSelected) { if(synchronousSelection) { sendRoundTripMessage(MESSAGE_VIEW_SYNCHRONIZE_SELECTION, isSelected ? Boolean.TRUE : Boolean.FALSE, null); }//if// else { sendMessage(MESSAGE_VIEW_SYNCHRONIZE_SELECTION, isSelected ? Boolean.TRUE : Boolean.FALSE); }//else// selectionLinkage.invoke(isStateful ? isSelected ? Boolean.TRUE : Boolean.FALSE : null); }//selectionChanged()// /* (non-Javadoc) * @see com.foundation.view.swt.IAbstractMenu#loadMenu() */ public void loadMenu() { if((style & STYLE_CASCADE) > 0) { //Setup both a menu and menu item since they work as one in SWT.// swtMenuItem = new org.eclipse.swt.widgets.MenuItem((org.eclipse.swt.widgets.Menu) ((Menu) getParent()).getSwtMenu(), SWT.CASCADE); //style swtMenu = new org.eclipse.swt.widgets.Menu(swtMenuItem); swtMenuItem.setMenu(swtMenu); swtMenu.setData(this); swtMenuItem.setData(this); setSwtWidget(swtMenuItem); }//if// else if(isVisibleValue) { swtMenuItem = new org.eclipse.swt.widgets.MenuItem(((Menu) getParent()).getSwtMenu(), style); swtMenuItem.setData(this); setSwtWidget(swtMenuItem); swtMenuItem.addSelectionListener(this); }//else if// if(getSwtMenu() != null) { getSwtMenu().setVisible(isVisibleValue); getSwtMenu().setEnabled(isEnabledValue); }//if// if(getSwtMenuItem() != null) { getSwtMenuItem().setText(textValue == null ? "" : textValue); getSwtMenuItem().setImage(createImage(imageValue)); getSwtMenuItem().setSelection(isSelectedValue); getSwtMenuItem().setEnabled(isEnabledValue); getSwtMenuItem().setAccelerator(acceleratorValue); }//if// }//loadMenu()// /* (non-Javadoc) * @see com.foundation.view.swt.IAbstractMenu#unloadMenu() */ public void unloadMenu() { if(getSwtMenuItem() != null && imageValue != null) { destroyImage(imageValue); }//if// if(getSwtMenu() != null && !getSwtMenu().isDisposed()) { getSwtMenu().dispose(); swtMenu = null; }//if// if(getSwtMenuItem() != null && !getSwtMenuItem().isDisposed()) { getSwtMenuItem().dispose(); swtMenuItem = null; }//if// }//loadMenu()// /* (non-Javadoc) * @see com.foundation.view.swt.IAbstractMenu#loadMenuChildren() */ public void loadMenuChildren() { if(getSubMenus() != null) { for(int index = 0; index < getSubMenus().getSize(); index++) { IAbstractMenu menu = (IAbstractMenu) getSubMenus().get(index); menu.loadMenu(); menu.loadMenuChildren(); }//for// }//if// }//loadMenuChildren()// /* (non-Javadoc) * @see com.foundation.view.swt.IAbstractMenu#unloadMenuChildren() */ public void unloadMenuChildren() { if(getSubMenus() != null) { for(int index = 0; index < getSubMenus().getSize(); index++) { IAbstractMenu menu = (IAbstractMenu) getSubMenus().get(index); menu.unloadMenuChildren(); menu.unloadMenu(); }//for// }//if// }//unloadMenuChildren()// }//Menu()//