/*
* JBoss, Home of Professional Open Source
* Copyright 2006, Red Hat Middleware LLC, and individual contributors
* as indicated by the @author tags.
* See the copyright.txt in the distribution for a
* full listing of individual contributors.
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU Lesser General Public License, v. 2.1.
* This program is distributed in the hope that it will be useful, but WITHOUT A
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General Public License,
* v.2.1 along with this distribution; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*
* (C) 2005-2006,
* @author JBoss Inc.
*/
/*
* Copyright (C) 1998, 1999, 2000, 2001, 2002
*
* Arjuna Technologies Ltd.
* Newcastle upon Tyne,
* Tyne and Wear,
* UK.
*
* $Id: ArjunaToolsFramework.java 2342 2006-03-30 13:06:17Z $
*/
package com.arjuna.ats.tools.toolsframework;
import com.arjuna.ats.tools.toolsframework.plugin.ToolPlugin;
import com.arjuna.ats.tools.toolsframework.plugin.ToolPluginException;
import com.arjuna.ats.tools.toolsframework.plugin.ToolPluginInformation;
import com.arjuna.ats.tools.toolsframework.dialogs.AboutDialog;
import com.arjuna.ats.tools.toolsframework.dialogs.SettingsDialog;
import javax.swing.*;
import javax.swing.event.MenuListener;
import javax.swing.event.MenuEvent;
import javax.xml.parsers.DocumentBuilderFactory;
import java.util.Properties;
import java.util.ArrayList;
import java.awt.event.*;
import java.io.InputStream;
import java.beans.PropertyVetoException;
import java.net.URL;
import org.w3c.dom.*;
/**
* Top level frame for running jbosstm tools
*/
public class ArjunaToolsFramework extends JFrame implements ActionListener, MenuListener, ToolsFramework
{
private final static String CONFIGURATION_FILENAME = "toolsframework.xml";
private final static String LOOK_AND_FEEL_NODE = "look-and-feel";
private final static String TITLE_NODE = "title";
private final static String FRAME_PROPERTIES_NODE = "frame-properties";
private final static String PLUGIN_CONFIGURATIONS_NODE = "plugins";
private final static String PROPERTIES_CONFIGURATION_NODE = "properties";
private final static String PROPERTY_CONFIGURATION_NODE = "property";
private final static String PROPERTY_NAME_ATTRIBUTE = "name";
private final static String PROPERTY_VALUE_ATTRIBUTE = "value";
private final static String PLUGIN_CLASSNAME_ATTRIBUTE = "classname";
private final static String WIDTH_ATTRIBUTE = "width";
private final static String HEIGHT_ATTRIBUTE = "height";
private final static String FILE_MENU = "File";
private final static String SETTINGS_MENU_ITEM = "Settings";
private final static String EXIT_MENU_ITEM = "Exit";
private final static String HELP_MENU = "Help";
private final static String ABOUT_MENU_ITEM = "About";
private final static String WINDOW_MENU = "Window";
private final static String CASCADE_MENU_ITEM = "Cascade Windows";
private final static String ACTION_COMMAND_PREFIX = "WINDOW_ACTION_COMMAND_";
private final static float CASCADE_WINDOW_PERCENTAGE = 0.75f;
private final static int CASCADE_WINDOW_INCREMENT = 25;
private ToolsClassLoader _classLoader = null;
private ArrayList _plugins = new ArrayList();
private JDesktopPane _desktop = null;
private JMenuBar _menuBar = null;
private boolean _hasSettings = false;
private boolean _disposed = false;
private boolean _isEmbedded = false;
public ArjunaToolsFramework()
{
this(false);
}
public ArjunaToolsFramework(boolean isEmbedded)
{
/** Is the application embedded? **/
_isEmbedded = isEmbedded;
/** Create tools classloader **/
_classLoader = new ToolsClassLoader();
/** Create JMenuBar **/
this.setJMenuBar(_menuBar = createBasicMenuBar());
/** Create the desktop **/
this.setContentPane(_desktop = new JDesktopPane());
/** Load plugins and configuration **/
loadConfiguration();
/** Add the File menu items **/
addFileMenuItems(_menuBar);
/** Add the Window menu **/
addWindowMenu(_menuBar);
/** Add the help menu **/
addHelpMenu(_menuBar);
/** Add window event handler **/
this.addWindowListener(new WindowAdapter()
{
/**
* Invoked when a window has been closed.
*/
public void windowClosed(WindowEvent e)
{
windowClosing(e);
}
/**
* Invoked when a window is in the process of being closed.
* The close operation can be overridden at this point.
*/
public void windowClosing(WindowEvent e)
{
disposePlugins();
exitApplication(0);
}
});
/** Display the frame **/
setVisible(true);
/** Show the about dialog and allow to automatically close **/
new AboutDialog(this, true);
}
public synchronized void disposePlugins()
{
if ( !_disposed )
{
_disposed = true;
for (int count = 0; count < _plugins.size(); count++)
{
try
{
ToolPlugin plugin = (ToolPlugin) _plugins.get(count);
plugin.dispose();
}
catch (ToolPluginException e)
{
System.err.println("An error occurred while trying to dispose of the plugs: " + e);
}
}
}
}
public synchronized void exitApplication(int status)
{
if (!_isEmbedded)
{
System.exit(status);
}
}
private JMenuBar createBasicMenuBar()
{
JMenuBar menubar = new JMenuBar();
JMenu menu = null;
menubar.add(menu = new JMenu(FILE_MENU));
menu.setMnemonic(KeyEvent.VK_F);
return menubar;
}
/**
* Invoked when a menu is selected.
*
* @param e a MenuEvent object
*/
public void menuSelected(MenuEvent e)
{
JMenuItem item;
JMenu menu = (JMenu) e.getSource();
JInternalFrame[] frames = _desktop.getAllFrames();
menu.removeAll();
menu.add(item = new JMenuItem(CASCADE_MENU_ITEM));
item.setMnemonic(KeyEvent.VK_C);
item.addActionListener(this);
menu.addSeparator();
for (int count = 0; count < frames.length; count++)
{
JMenuItem menuItem;
menu.add(menuItem = new JMenuItem((count + 1) + ". " + frames[count].getTitle()));
menuItem.setActionCommand(ACTION_COMMAND_PREFIX + frames[count].getTitle());
menuItem.addActionListener(this);
}
}
/**
* Invoked when the menu is deselected.
*
* @param e a MenuEvent object
*/
public void menuDeselected(MenuEvent e)
{
}
/**
* Invoked when the menu is canceled.
*
* @param e a MenuEvent object
*/
public void menuCanceled(MenuEvent e)
{
}
private void addFileMenuItems(JMenuBar menuBar)
{
/** Find File menu **/
JMenu menu = ToolPlugin.getMenu(menuBar, FILE_MENU);
JMenuItem item;
/** Add menu separator **/
menu.addSeparator();
/** Add settings menu item **/
menu.add(item = new JMenuItem(SETTINGS_MENU_ITEM));
item.setMnemonic(KeyEvent.VK_S);
item.addActionListener(this);
item.setEnabled( _hasSettings );
/** Add exit menu item **/
menu.add(item = new JMenuItem(EXIT_MENU_ITEM));
item.setMnemonic(KeyEvent.VK_X);
item.addActionListener(this);
}
private void addWindowMenu(JMenuBar menubar)
{
JMenu menu = null;
menubar.add(Box.createHorizontalGlue());
menubar.add(menu = new JMenu(WINDOW_MENU));
menu.addMenuListener(this);
menu.setMnemonic(KeyEvent.VK_W);
}
private void addHelpMenu(JMenuBar menubar)
{
JMenu menu = null;
JMenuItem item = null;
menubar.add(menu = new JMenu(HELP_MENU));
menu.setMnemonic(KeyEvent.VK_H);
menu.add(item = new JMenuItem(ABOUT_MENU_ITEM));
item.setMnemonic(KeyEvent.VK_A);
item.addActionListener(this);
}
/**
* Invoked when an action occurs.
*/
public void actionPerformed(ActionEvent e)
{
String actionCommand = e.getActionCommand();
if (actionCommand.startsWith(ACTION_COMMAND_PREFIX))
{
JInternalFrame[] frames = _desktop.getAllFrames();
for (int count = 0; count < frames.length; count++)
{
if (frames[count].getTitle().equals(actionCommand.substring(ACTION_COMMAND_PREFIX.length())))
{
try
{
frames[count].setSelected(true);
}
catch (PropertyVetoException ex)
{
// Ignore
}
_desktop.getDesktopManager().activateFrame(frames[count]);
}
}
}
else if (actionCommand.equals(EXIT_MENU_ITEM))
{
dispose();
}
else if (actionCommand.equals(ABOUT_MENU_ITEM))
{
showAboutDialog();
}
else if (actionCommand.equals(SETTINGS_MENU_ITEM))
{
showSettingsDialog();
}
else if (actionCommand.equals(CASCADE_MENU_ITEM))
{
cascadeWindows();
}
}
private void cascadeWindows()
{
JInternalFrame[] frames = _desktop.getAllFrames();
int offset = 0;
for (int count = 0; count < frames.length; count++)
{
frames[count].setLocation(offset, offset);
frames[count].setSize((int) (this.getWidth() * CASCADE_WINDOW_PERCENTAGE),
(int) (this.getHeight() * CASCADE_WINDOW_PERCENTAGE));
offset += CASCADE_WINDOW_INCREMENT;
}
}
private void showSettingsDialog()
{
SettingsDialog dlg = new SettingsDialog(this, _plugins);
int x = (int) this.getLocation().getX() + (this.getWidth() / 2) - (dlg.getWidth() / 2);
int y = (int) this.getLocation().getY() + (this.getHeight() / 2) - (dlg.getHeight() / 2);
dlg.setLocation(x, y);
}
private void showAboutDialog()
{
new AboutDialog(this, false);
}
/**
* Retrieve a specific named child node of the given node.
* @param configRoot The node whose children need seraching.
* @param nodeName The name of the node to find.
* @return The child node matching the node name.
*/
private Node getChildNode(Node configRoot, String nodeName)
{
NodeList nodeList = configRoot.getChildNodes();
for (int count=0;count<nodeList.getLength();count++)
{
if ( nodeList.item(count).getNodeName().equals( nodeName ) )
{
return nodeList.item(count);
}
}
return null;
}
private boolean loadConfiguration()
{
boolean success = true;
try
{
ToolPlugin plugin;
InputStream configStream = _classLoader.getResourceAsStream(CONFIGURATION_FILENAME);
if (configStream == null)
{
System.err.println("Cannot find the configuration file '" + CONFIGURATION_FILENAME + "' in the tests/config directory");
exitApplication(1);
}
/** Parse the configuration document **/
Document configDoc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(configStream);
Element configRoot = configDoc.getDocumentElement();
/** Retrieve and parse the look-and-feel node **/
Node lookAndFeelNode = getChildNode(configRoot, LOOK_AND_FEEL_NODE);
if ( lookAndFeelNode != null )
{
/** Set the tool title **/
String title = getChildNode(lookAndFeelNode, TITLE_NODE).getFirstChild().getNodeValue();
if (title != null)
{
this.setTitle(title);
}
/** Set the frame properties **/
Node frameProperties = getChildNode(lookAndFeelNode, FRAME_PROPERTIES_NODE);
if ( frameProperties != null )
{
int width = Integer.parseInt( frameProperties.getAttributes().getNamedItem(WIDTH_ATTRIBUTE).getNodeValue() );
int height = Integer.parseInt( frameProperties.getAttributes().getNamedItem(HEIGHT_ATTRIBUTE).getNodeValue() );
this.setSize(width, height);
}
}
/** Retrieve the plugin configuration nodes **/
Node pluginConfigs = getChildNode(configRoot, PLUGIN_CONFIGURATIONS_NODE);
/** Retrieve the tool plugin information classes for the JARs in the tool lib directory **/
ToolPluginInformation[] plugins = _classLoader.getToolsInformation();
for (int pluginCount=0;pluginCount<plugins.length;pluginCount++)
{
String[] pluginClassname = plugins[pluginCount].getClassnames();
for (int classnameCount=0;classnameCount<pluginClassname.length;classnameCount++)
{
/** Instantiate plugin and add to list **/
plugin = (ToolPlugin) _classLoader.loadClass(pluginClassname[classnameCount]).newInstance();
plugin.setToolsFramework(this);
/** Call initialisers **/
plugin.initialisePlugin(_menuBar, _desktop, plugins[pluginCount].getIcon16(), plugins[pluginCount].getIcon32());
/** Retrieve the tool properties and then override any locally defined properties **/
Properties toolProps = plugins[pluginCount].getProperties();
Properties localProps = getLocalPluginProperties(pluginConfigs, pluginClassname[classnameCount]);
if ( localProps != null )
{
toolProps.putAll( localProps );
}
try
{
plugin.initialise( toolProps );
_plugins.add(plugin);
}
catch (Throwable e)
{
e.printStackTrace();
System.err.println("Error initialising plugin " + plugin.getName());
}
/** See if this plugin has a settings panel, if it does ensure we enable all setting functionality **/
if ( plugin.createSettingsPanel() != null )
{
_hasSettings = true;
}
}
}
}
catch (Exception e)
{
e.printStackTrace();
System.err.println("An error occurred while initialising plugins: " + e);
success = false;
}
return success;
}
/**
* Retrieve from the given XML node the local plugin properties for the given plugin.
*
* @param pluginConfigsNode
* @param pluginClassname
* @return
*/
private Properties getLocalPluginProperties(Node pluginConfigsNode, String pluginClassname)
{
if ( pluginConfigsNode != null )
{
Properties props = new Properties();
NodeList pluginNodes = pluginConfigsNode.getChildNodes();
for (int count=0;count<pluginNodes.getLength();count++)
{
Node pluginNode = pluginNodes.item(count);
if ( pluginNode != null )
{
NamedNodeMap attrs = pluginNode.getAttributes();
if ( attrs != null )
{
Node classNameNode = attrs.getNamedItem(PLUGIN_CLASSNAME_ATTRIBUTE);
if ( ( classNameNode != null ) && ( classNameNode.getNodeValue().equals( pluginClassname ) ) )
{
Node propertiesNode = getChildNode(pluginNode, PROPERTIES_CONFIGURATION_NODE);
NodeList propertyNodes = propertiesNode.getChildNodes();
for (int propCount=0;propCount<propertyNodes.getLength();propCount++)
{
Node propertyNode = propertyNodes.item(propCount);
if ( propertyNode.getNodeName().equals(PROPERTY_CONFIGURATION_NODE) )
{
String propName = propertyNode.getAttributes().getNamedItem(PROPERTY_NAME_ATTRIBUTE).getNodeValue();
String propValue = propertyNode.getAttributes().getNamedItem(PROPERTY_VALUE_ATTRIBUTE).getNodeValue();
props.put(propName, propValue);
}
}
return props;
}
}
}
}
}
return null;
}
public static void main(String[] args)
{
new ArjunaToolsFramework();
}
public URL getToolsDir()
{
return _classLoader.getToolsDir();
}
}