/******************************************************************************* * Copyright (c) 2002-2006 Innoopract Informationssysteme GmbH. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Innoopract Informationssysteme GmbH - initial API and implementation ******************************************************************************/ package com.w4t.custom; import java.text.MessageFormat; import java.util.Hashtable; import java.util.Map; import org.eclipse.rwt.internal.resources.ResourceManagerImpl; import org.eclipse.rwt.internal.util.Assert; import org.eclipse.rwt.resources.IResourceManager; import com.w4t.*; import com.w4t.dhtml.*; import com.w4t.dhtml.menustyle.*; import com.w4t.event.WebActionEvent; import com.w4t.event.WebActionListener; import com.w4t.types.LocalPath; /** <p>A convenience component that consists of a menu which can be configured * declaratively in an XML file.</p> * * <p>The menu configuration (names of the menu items, their respective * menus, and commands which are triggered by these items) is read * from an XML file which can be set by {@link #setConfigFile(LocalPath) * setConfigFile(LocalPath)} or {@link #setConfigResource(String) * setConfigResource(String)}.</p> * * <p>A configuration file for CMenu should look like this: * <pre> * <CMenu> * * <menuEntry> * <!-- entry for a menu item in Menu 'File' --> * <menu>File</menu> * <label>File</label> * <id>FILE_QUIT</id> * <command>com.and.go.FileQuitCommand</command> * </menuEntry> * * <!-- more entries go here --> * * </CMenu> * </pre> * * <p>Specifying an <strong><id></strong> is obligatory. On click the * CMenu invokes the <code>execute</code> method on a new instance of the * class that was specified in <command>. This class must implement * the <code>ICustomAction</code> interface. To notify the action about which * <strong><id></strong> is to be executed the * <code>ICustomAction</code>s <code>init</code> method is invoked in advance. * </p> * <p>The following example shows how an <code>ICustomAction</code> * implementation could look like * <pre> * public class MyAction implements ICustomAction { * * private String commandToExecute; * * public void init( String commandId ) { * commandToExecute = commandId; * } * * public void execute() { * if( "org.demo.openAction".equals( commandToExecute ) { * // open something * } else if( "org.demo.closeAction".equals( commandToExecute ) { * // close something * } * // ... * } * } * </pre></p> * * <p>Specifying a <strong><command></strong> is optional. If none is * specified, clicking the menu will do nothing.</p> * @see org.eclipse.rwt.custom.ICustomAction */ public class CMenu extends WebPanel implements Concealer { /** <p>the encapsulated menu bar instance.</p>*/ private MenuBar menuBar; /** <p>Container for currently loaded menus.</p>*/ private Map menuList; /** <p>the file that contains the menu configuration.</p> */ private LocalPath configFile; private String configResource; /** <p>Constructs a new CMenu.</p> */ public CMenu() throws Exception { menuList = new Hashtable(); setWebComponents(); } public Object clone() throws CloneNotSupportedException { CMenu result = ( CMenu )super.clone(); result.menuList = new Hashtable(); result.menuBar = ( MenuBar )this.menuBar.clone(); try { if( configFile != null ) { result.setConfigFile( this.configFile ); } if( configResource != null ) { result.setConfigResource( this.configResource ); } } catch( Exception shouldNotHappen ) { // as shouldNotHappen should not happen, we do nothing when it not happens } return result; } /** <p>Returns a path to an image that represents this WebComponent * (widget icon).</p> */ public static String retrieveIconName() { return "resources/images/icons/menubar.gif"; } private void setWebComponents() throws Exception { instanceWebComponents(); initialiseMenuBar1(); } private void instanceWebComponents() { menuBar = new MenuBar(); } private void initialiseMenuBar1() { this.add( menuBar ); menuBar.setName( "menuBar" ); } // helping methods ////////////////// private void initialiseMenus() throws Exception { menuBar.removeAllItems(); menuList.clear(); MenuEntry[] menuEntries = getMenuEntries(); for( int i = 0; i < menuEntries.length; i++ ) { Menu menu = initialiseMenu( menuEntries[ i ].getMenu() ); addMenuItem( menu, menuEntries[ i ] ); } } private Menu initialiseMenu( final String menuName ) { Menu result = ( Menu )menuList.get( menuName ); if( result == null ) { result = new Menu( menuName ); menuBar.addItem( result ); menuList.put( menuName, result ); } return result; } private void addMenuItem( final Menu menu, final MenuEntry entry ) { Item item; if( entry.getLabel().equals( "separator" ) ) { item = new MenuItemSeparator(); } else { item = createMenuItem( entry ); } menu.addItem( item ); } private MenuItem createMenuItem( final MenuEntry entry ) { final MenuItem result = new MenuItem( entry.getLabel() ); if( !entry.getId().equals( "" ) ) { final String className = entry.getCommand().trim(); IResourceManager manager = ResourceManagerImpl.getInstance(); final ClassLoader contextLoader = manager.getContextLoader(); result.addWebActionListener( new WebActionListener() { public void webActionPerformed( final WebActionEvent evt ) { ICustomAction command; try { Class clazz; if( contextLoader == null ) { clazz = Class.forName( className ); } else { clazz = contextLoader.loadClass( className ); } command = ( ICustomAction )clazz.newInstance(); } catch( final Exception ex ) { String msg = "ICustomAction not found: {0} [{1}]\nfor menu item {2}."; Object[] params = new Object[] { entry.getId(), className, W4TContext.resolve( result.getLabel() ) }; String txt = MessageFormat.format( msg, params ); throw new RuntimeException( txt, ex ); } command.init( entry.getId() ); command.execute(); } } ); } return result; } private MenuEntry[] getMenuEntries() throws Exception { String fileName; if( getConfigFile() != null ) { fileName = getConfigFile().toFile().toString(); } else { fileName = configResource; } InitialisationReader reader = new InitialisationReader( fileName ); int count = reader.selectContent( "menuItem" ); MenuEntry[] result = new MenuEntry[ count ]; for( int i = 0; i < count; i++ ) { String menu = reader.getAttribute( "menu" ); String label = reader.getAttribute( "label" ); String id = reader.getAttribute( "id" ); String command = reader.getAttribute( "command" ); result[ i ] = new MenuEntry( menu, label, id, command ); reader.nextContent(); } return result; } // attribute getters and setters //////////////////////////////// /** <p>Sets the file from which the configuration of this CMenu is * read.</p> * * <p>Note: Using <code>setConfigFile</code> to initialize this * <code>CMenu</code> instance, discards the <code>setConfigResource</code> * initializations.</p> */ public void setConfigFile( final LocalPath configFile ) { Assert.isNotNull( configFile ); Assert.isTrue( configFile.toFile().exists() ); this.configFile = configFile; this.configResource = null; try { initialiseMenus(); } catch( final Exception ex ) { String txt = "The file \"{0}\" does not exist or is not a " + "valid configuration file."; Object[] param = new Object[]{ configFile.toFile().toString() }; String msg = MessageFormat.format( txt, param ); throw new IllegalArgumentException( msg ); } } /** <p>Returns the file from which the configuration of this CMenu is * read.</p> */ public LocalPath getConfigFile() { return configFile; } /** * <p>Loads the given configuration resource from the application's * classpath.</p> * <p>Note: Using <code>setConfigResource</code> to initialize this * <code>CMenu</code> instance, discards the <code>setConfigFile</code> * initializations.</p> * @param configResource the path to an menu configuration file that is * available on the application's classpath. */ public void setConfigResource( final String configResource ) { Assert.isNotNull( configResource ); this.configResource = configResource; this.configFile = null; try { initialiseMenus(); } catch( final Exception ex ) { String txt = "The file \"{0}\" does not exist or is not a " + "valid configuration file."; String msg = MessageFormat.format( txt, new Object[]{ configResource } ); throw new IllegalArgumentException( msg ); } } /** * <p>Returns the configuration resource available on the application's * classpath that was used to initialize this <code>CMenu</code> or * <code>null</code>, if not available.</p> */ public String getConfigResource() { return configResource; } // attribute delegations to the menuBar /////////////////////////////////////// /** <p>Sets the passed MenuBarStyle to the MenuBar in this CMenu.</p> * * @see MenuBar#setMenuBarStyle( MenuBarStyle ) */ public void setMenuBarStyle( final MenuBarStyle menuBarStyle ) { menuBar.setMenuBarStyle( menuBarStyle ); } /** <p>Returns the MenuBarStyle which is set on the MenuBar in this * CMenu.</p> * * @see MenuBar#getMenuBarStyle() */ public MenuBarStyle getMenuBarStyle() { return menuBar.getMenuBarStyle(); } /** <p>Sets the passed MenuButtonActiveStyle to the MenuBar in this * CMenu.</p> * * @see MenuBar#setButtonActiveStyle( MenuButtonActiveStyle ) */ public void setButtonActiveStyle( final MenuButtonActiveStyle buttonActiveStyle ) { menuBar.setButtonActiveStyle( buttonActiveStyle ); } /** <p>Returns the MenuButtonActiveStyle which is set on the MenuBar in this * CMenu.</p> * * @see MenuBar#getButtonActiveStyle() */ public MenuButtonActiveStyle getButtonActiveStyle() { return menuBar.getButtonActiveStyle(); } /** <p>Sets the passed MenuButtonDisabledStyle to the MenuBar in this * CMenu.</p> * * @see MenuBar#setButtonDisabledStyle( MenuButtonDisabledStyle ) */ public void setButtonDisabledStyle( final MenuButtonDisabledStyle buttonDisabledStyle ) { menuBar.setButtonDisabledStyle( buttonDisabledStyle ); } /** <p>Returns the MenuButtonDisabledStyle which is set on the MenuBar in * this CMenu.</p> * * @see MenuBar#getButtonDisabledStyle() */ public MenuButtonDisabledStyle getButtonDisabledStyle() { return menuBar.getButtonDisabledStyle(); } /** <p>sets the passed MenuButtonEnabledStyle to the MenuBar in this * CMenu.</p> * * @see MenuBar#setButtonEnabledStyle( MenuButtonEnabledStyle ) */ public void setButtonEnabledStyle( final MenuButtonEnabledStyle buttonEnabledStyle ) { menuBar.setButtonEnabledStyle( buttonEnabledStyle ); } /** <p>returns the MenuButtonEnabledStyle which is set on the MenuBar * in this CMenu.</p> * * @see MenuBar#getButtonEnabledStyle() */ public MenuButtonEnabledStyle getButtonEnabledStyle() { return menuBar.getButtonEnabledStyle(); } /** <p>sets the passed MenuButtonHoverStyle to the MenuBar in this * CMenu.</p> * * @see MenuBar#setButtonHoverStyle( MenuButtonHoverStyle ) */ public void setButtonHoverStyle( final MenuButtonHoverStyle buttonHoverStyle ) { menuBar.setButtonHoverStyle( buttonHoverStyle ); } /** <p>returns the MenuButtonHoverStyle which is set on the MenuBar in this * CMenu.</p> * * @see MenuBar#getButtonHoverStyle() */ public MenuButtonHoverStyle getButtonHoverStyle() { return menuBar.getButtonHoverStyle(); } /** <p>sets the passed MenuItemHoverStyle to the MenuBar in this * CMenu.</p> * * @see MenuBar#osetItemHoverStyle( MenuItemHoverStyle ) */ public void setItemHoverStyle( final MenuItemHoverStyle itemHoverStyle ) { menuBar.setItemHoverStyle( itemHoverStyle ); } /** <p>returns the MenuItemHoverStyle which is set on the MenuBar in this * CMenu.</p> * * @see MenuBar#getItemHoverStyle() */ public MenuItemHoverStyle getItemHoverStyle() { return menuBar.getItemHoverStyle(); } /** <p>sets the passed MenuItemEnabledStyle to the MenuBar in this * CMenu.</p> * * @see MenuBar#setItemEnabledStyle( MenuItemEnabledStyle ) */ public void setItemEnabledStyle( final MenuItemEnabledStyle itemEnabledStyle ) { menuBar.setItemEnabledStyle( itemEnabledStyle ); } /** <p>returns the MenuItemEnabledStyle which is set on the MenuBar in this * CMenu.</p> * * @see MenuBar#getItemEnabledStyle() */ public MenuItemEnabledStyle getItemEnabledStyle() { return menuBar.getItemEnabledStyle(); } /** <p>sets the passed MenuItemDisabledStyle to the MenuBar in this * CMenu.</p> * * @see MenuBar#setItemDisabledStyle( MenuItemDisabledStyle ) */ public void setItemDisabledStyle( final MenuItemDisabledStyle itemDisabledStyle ) { menuBar.setItemDisabledStyle( itemDisabledStyle ); } /** <p>returns the MenuItemDisabledStyle which is set on the MenuBar in this * CMenu.</p> * * @see MenuBar#getItemDisabledStyle() */ public MenuItemDisabledStyle getItemDisabledStyle() { return menuBar.getItemDisabledStyle(); } /** <p>sets the passed MenuPopupStyle to the MenuBar in this * CMenu.</p> * * @see MenuBar#setMenuPopupStyle( MenuPopupStyle ) */ public void setMenuPopupStyle( final MenuPopupStyle menuPopupStyle ) { menuBar.setMenuPopupStyle( menuPopupStyle ); } /** <p>returns the MenuPopupStyle which is set on the MenuBar in this * CMenu.</p> * * @see MenuBar#getMenuPopupStyle() */ public MenuPopupStyle getMenuPopupStyle() { return menuBar.getMenuPopupStyle(); } //////////////// // inner classes /** <p>encapsulates information about menu items, as specified in the * custom menu configuration file (which is an xml file that contains * information about the menu items, their name, to which CMenu they belong, * and which command is triggered by them).</p> */ private static class MenuEntry { private String menu; private String label; private String id; private String command; /** Creates a new instance of MenuEntry. */ private MenuEntry( final String menu, final String label, final String id, final String command ) { this.menu = menu; this.label = label; this.id = id; this.command = command; } // attribute getters and setters //////////////////////////////// private String getCommand() { return command; } private String getLabel() { return label; } private String getMenu() { return menu; } private String getId() { return id; } } }