/* * The University of Wales, Cardiff Triana Project Software License (Based * on the Apache Software License Version 1.1) * * Copyright (c) 2007 University of Wales, Cardiff. All rights reserved. * * Redistribution and use of the software in source and binary forms, with * or without modification, are permitted provided that the following * conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 3. The end-user documentation included with the redistribution, if any, * must include the following acknowledgment: "This product includes * software developed by the University of Wales, Cardiff for the Triana * Project (http://www.trianacode.org)." Alternately, this * acknowledgment may appear in the software itself, if and wherever * such third-party acknowledgments normally appear. * * 4. The names "Triana" and "University of Wales, Cardiff" must not be * used to endorse or promote products derived from this software * without prior written permission. For written permission, please * contact triana@trianacode.org. * * 5. Products derived from this software may not be called "Triana," nor * may Triana appear in their name, without prior written permission of * the University of Wales, Cardiff. * * 6. This software may not be sold, used or incorporated into any product * for sale to third parties. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN * NO EVENT SHALL UNIVERSITY OF WALES, CARDIFF OR ITS CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * * ------------------------------------------------------------------------ * * This software consists of voluntary contributions made by many * individuals on behalf of the Triana Project. For more information on the * Triana Project, please see. http://www.trianacode.org. * * This license is based on the BSD license as adopted by the Apache * Foundation and is governed by the laws of England and Wales. * */ package org.trianacode.gui.hci.tools; import java.awt.Component; import java.util.ArrayList; import java.util.Hashtable; import javax.swing.Action; import javax.swing.Icon; import javax.swing.JMenu; import javax.swing.JPopupMenu; import javax.swing.SwingUtilities; import javax.swing.event.PopupMenuEvent; import javax.swing.event.PopupMenuListener; import org.trianacode.gui.components.triana.OpenGroupComponentModel; import org.trianacode.gui.extensions.ExtensionManager; import org.trianacode.gui.main.TaskComponent; import org.trianacode.gui.main.TaskGraphPanel; import org.trianacode.taskgraph.RenderingHint; import org.trianacode.taskgraph.Task; import org.trianacode.taskgraph.TaskGraph; import org.trianacode.taskgraph.service.TrianaClient; import org.trianacode.taskgraph.tool.Tool; /** * A ToolComponentModel maintains a list to ToolComponentModels, each of which controls how a particular tool appears in * the tool tree/workspace. */ public class TaskGraphView { /** * The name of the mode */ private String name; /** * A hashtable of the ToolComponentModels keyed by tool class */ private Hashtable toolmodels = new Hashtable(); /** * A hashtable of the OpenGroupComponentModels keyed by tool class */ private Hashtable groupmodels = new Hashtable(); /** * A cache of the tool item model for each tool */ private Hashtable toolcache = new Hashtable(); /** * A cache of the open group model for each taskgraph */ private Hashtable groupcache = new Hashtable(); /** * A list of the classes in order of registration */ private ArrayList classorder = new ArrayList(); private ArrayList groupclassorder = new ArrayList(); /** * The parent tool component mode (null if root) */ private TaskGraphView parentmode; /** * The default tool component model */ private ToolComponentModel defaulttool; /** * The default open group component model */ private OpenGroupComponentModel defaultgroup; /** * Constructs a root tool component mode * * @param name the name of the mode */ public TaskGraphView(String name) { this.name = name; } /** * Constructs a child tool component mode * * @param name the name of the mode * @param parentmode the parent tool component mode */ public TaskGraphView(String name, TaskGraphView parentmode) { this.name = name; this.parentmode = parentmode; } /** * @return the name of this mode */ public String getViewName() { return name; } /** * @return the parent tool mode (null if root) */ private TaskGraphView getParentToolMode() { return parentmode; } /** * @return the default tool item model */ public ToolComponentModel getDefaultToolModel() { return defaulttool; } /** * Sets the default tool item model */ public void setDefaultToolModel(ToolComponentModel model) { defaulttool = model; toolcache.clear(); } /** * @return the default tool item model */ public OpenGroupComponentModel getDefaultOpenGroupModel() { return defaultgroup; } /** * Sets the default tool item model */ public void setDefaultOpenGroupModel(OpenGroupComponentModel model) { defaultgroup = model; groupcache.clear(); } /** * Registers a ToolComponentModel for a particular tool class. Note that if a tool has two component models then the * later registered takes precedence. */ public void registerToolModel(String toolclass, ToolComponentModel model) { toolmodels.put(toolclass, model); classorder.remove(toolclass); classorder.add(toolclass); toolcache.clear(); } /** * Unregisters the ToolComponentModel for a particular tool class */ public void unregisterToolModel(String toolclass) { toolmodels.remove(toolclass); classorder.remove(toolclass); toolcache.clear(); } /** * Registers a OpenGroupComponentModel for a particular tool class */ public void registerOpenGroupModel(String toolclass, OpenGroupComponentModel model) { groupmodels.put(toolclass, model); groupclassorder.remove(toolclass); groupclassorder.add(toolclass); groupcache.clear(); } /** * Unregisters the OpenGroupComponentModel for a particular tool class */ public void unregisterOpenGroupModel(String toolclass) { groupmodels.remove(toolclass); groupclassorder.remove(toolclass); groupcache.clear(); } /** * @return the tree icon for the specified tool (if null is returned then the default leaf icon is used) */ public Icon getTreeIcon(Tool tool) { ToolComponentModel model = getToolComponentModel(tool); Icon icon = null; if (model != null) { icon = model.getTreeIcon(tool); } if ((icon == null) && (getDefaultToolModel() != null)) { icon = getDefaultToolModel().getTreeIcon(tool); } if (icon != null) { return icon; } else if (getParentToolMode() != null) { return getParentToolMode().getTreeIcon(tool); } else { return null; } } /** * @return the tool tip for the specified tool when in the tree */ public String getTreeToolTip(Tool tool, boolean extended) { ToolComponentModel model = getToolComponentModel(tool); String tip = null; if (model != null) { tip = model.getTreeToolTip(tool, extended); } if ((tip == null) && (getDefaultToolModel() != null)) { tip = getDefaultToolModel().getTreeToolTip(tool, extended); } if (tip != null) { return tip; } else if (getParentToolMode() != null) { return getParentToolMode().getTreeToolTip(tool, extended); } else { throw (new RuntimeException( "Tool Component Model not set for " + tool.getToolName() + " in " + getViewName())); } } /** * @return the right-click popup for the specified tool when in the tree */ public JPopupMenu getTreePopup(Tool tool) { ToolComponentModel model = getToolComponentModel(tool); JPopupMenu menu = null; if (model != null) { menu = model.getTreePopup(tool); } if ((menu == null) && (getDefaultToolModel() != null)) { menu = getDefaultToolModel().getTreePopup(tool); } if (menu != null) { addTreeExtensions(menu, tool); return menu; } else if (getParentToolMode() != null) { return getParentToolMode().getTreePopup(tool); } else { throw (new RuntimeException( "Tool Component Model not set for " + tool.getToolName() + " in " + getViewName())); } } /** * Adds a tree extensions menu dor the specified tool */ private void addTreeExtensions(JPopupMenu menu, Tool tool) { Action[] actions = ExtensionManager.getTreeExtensions(tool); if (actions.length > 0) { final JMenu extmenu = new JMenu("Extensions"); for (int count = 0; count < actions.length; count++) { extmenu.add(actions[count]); } menu.addSeparator(); menu.add(extmenu); } } /** * @return the tool tip for the specified task when on the workspace */ public String getWorkspaceToolTip(Task task, boolean extended) { ToolComponentModel model = getToolComponentModel(task); String tip = null; if (model != null) { tip = model.getWorkspaceToolTip(task, extended); } if ((tip == null) && (getDefaultToolModel() != null)) { tip = getDefaultToolModel().getWorkspaceToolTip(task, extended); } if (tip != null) { return tip; } else if (getParentToolMode() != null) { return getParentToolMode().getWorkspaceToolTip(task, extended); } else { throw (new RuntimeException( "Tool Component Model not set for " + task.getToolName() + " in " + getViewName())); } } /** * @return the right-click popup for the specified task when on the workspace */ public JPopupMenu getWorkspacePopup(Task task) { ToolComponentModel model = getToolComponentModel(task); JPopupMenu menu = null; if (model != null) { menu = model.getWorkspacePopup(task); } if ((menu == null) && (getDefaultToolModel() != null)) { menu = getDefaultToolModel().getWorkspacePopup(task); } if (menu != null) { addWorkspaceExtensions(menu, task); return menu; } else if (getParentToolMode() != null) { return getParentToolMode().getWorkspacePopup(task); } else { throw (new RuntimeException( "Tool Component Model not set for " + task.getToolName() + " in " + getViewName())); } } /** * Adds a workspace extensions menu for the specified tool */ private void addWorkspaceExtensions(final JPopupMenu menu, Task task) { Action[] actions = ExtensionManager.getWorkspaceExtensions(task); if (actions.length > 0) { JMenu extmenu = new JMenu("Extensions"); for (int count = 0; count < actions.length; count++) { extmenu.add(actions[count]); } menu.addSeparator(); menu.add(extmenu); Component separator = menu.getComponent(menu.getComponentCount() - 2); menu.addPopupMenuListener(new RemoveExtensionMenuListener(menu, extmenu, separator)); } } /** * @return the right-click popup menu for an open group (right-click on workspace background) */ public JPopupMenu getOpenGroupPopup(TaskGraph taskgraph) { OpenGroupComponentModel model = getOpenGroupComponentModel(taskgraph); JPopupMenu menu = null; if (model != null) { menu = model.getOpenGroupPopup(taskgraph); } if ((menu == null) && (getDefaultOpenGroupModel() != null)) { menu = getDefaultOpenGroupModel().getOpenGroupPopup(taskgraph); } if (menu != null) { return menu; } else if (getParentToolMode() != null) { return getParentToolMode().getOpenGroupPopup(taskgraph); } else { throw (new RuntimeException( "Open Group Component Model not set for " + taskgraph + " in " + getViewName())); } } /** * @return the right-click popup menu for an multiple selected tasks. */ public JPopupMenu getMultipleSelectionPopup(TaskGraph taskgraph, Task[] tasks) { OpenGroupComponentModel model = getOpenGroupComponentModel(taskgraph); JPopupMenu menu = null; if (model != null) { menu = model.getMultipleSelectedPopup(tasks); } if ((menu == null) && (getDefaultOpenGroupModel() != null)) { menu = getDefaultOpenGroupModel().getMultipleSelectedPopup(tasks); } if (menu != null) { return menu; } else if (getParentToolMode() != null) { return getParentToolMode().getMultipleSelectionPopup(taskgraph, tasks); } else { throw (new RuntimeException( "Open Group Component Model not set for " + taskgraph + " in " + getViewName())); } } /** * @return the action that is invoked when the task is activated (e.g. double-clicked). */ public Action getTaskAction(Task task) { ToolComponentModel model = getToolComponentModel(task); Action action = null; if (model != null) { action = model.getTaskAction(task); } if ((action == null) && (getDefaultToolModel() != null)) { action = getDefaultToolModel().getTaskAction(task); } if (action != null) { return action; } else if (getParentToolMode() != null) { return getParentToolMode().getTaskAction(task); } else { throw (new RuntimeException( "Tool Component Model not set for " + task.getToolName() + " in " + getViewName())); } } /** * @return the task component used to represent the specified task */ public TaskComponent getTaskComponent(Task task) { ToolComponentModel model = getToolComponentModel(task); TaskComponent comp = null; if (model != null) { comp = model.getTaskComponent(task); } if ((comp == null) && (getDefaultToolModel() != null)) { comp = getDefaultToolModel().getTaskComponent(task); } if (comp != null) { return comp; } else if (getParentToolMode() != null) { return getParentToolMode().getTaskComponent(task); } else { throw (new RuntimeException( "Tool Component Model not set for " + task.getToolName() + " in " + getViewName())); } } /** * @param action the update action (e.g. INCREASE_INPUT_NODES_ACTION as defined in UpdateActionConstants) * @return true if the update action icon should be shown for the specified action */ public boolean isUpdateIcon(Task task, String action) { ToolComponentModel model = getToolComponentModel(task); int isicon = ToolComponentModel.UNKNOWN_ACTION; if (model != null) { isicon = model.isUpdateIcon(task, action); } if ((isicon == ToolComponentModel.UNKNOWN_ACTION) && (getDefaultToolModel() != null)) { isicon = getDefaultToolModel().isUpdateIcon(task, action); } if (isicon == ToolComponentModel.DISPLAY_ICON) { return true; } else if (getParentToolMode() != null) { return getParentToolMode().isUpdateIcon(task, action); } else { return false; } } /** * @param action the update action (e.g. INCREASE_INPUT_NODES_ACTION as defined in UpdateActionConstants) * @return the action associated with the specified update action. */ public Action getUpdateAction(Task task, String action) { ToolComponentModel model = getToolComponentModel(task); Action act = null; if (model != null) { act = model.getUpdateAction(task, action); } if ((act == null) && (getDefaultToolModel() != null)) { act = getDefaultToolModel().getUpdateAction(task, action); } if (act != null) { return act; } else if (getParentToolMode() != null) { return getParentToolMode().getUpdateAction(task, action); } else { return null; } } /** * The task component used to represent the specified task */ public TaskGraphPanel getTaskGraphPanel(TaskGraph taskgraph, TrianaClient client) { OpenGroupComponentModel model = getOpenGroupComponentModel(taskgraph); TaskGraphPanel comp = null; if (model != null) { comp = model.getOpenGroupComponent(taskgraph, client); } if ((comp == null) && (getDefaultOpenGroupModel() != null)) { comp = getDefaultOpenGroupModel().getOpenGroupComponent(taskgraph, client); } if (comp != null) { return comp; } else if (getParentToolMode() != null) { return getParentToolMode().getTaskGraphPanel(taskgraph, client); } else { throw (new RuntimeException( "Open Group Component Model not set for " + taskgraph + " in " + getViewName())); } } /** * @return the tool component model applicable to the specfied tool */ private ToolComponentModel getToolComponentModel(Tool tool) { ToolComponentModel model; if (toolcache.containsKey(tool)) { model = (ToolComponentModel) toolcache.get(tool); } else { model = locateToolComponentModel(tool); if (model != null) { toolcache.put(tool, model); } } return model; } /** * @return the open group component model applicable to the specfied taskgraph */ private OpenGroupComponentModel getOpenGroupComponentModel(TaskGraph taskgraph) { OpenGroupComponentModel model; if (groupcache.containsKey(taskgraph)) { model = (OpenGroupComponentModel) groupcache.get(taskgraph); } else { model = locateOpenGroupComponentModel(taskgraph); if (model != null) { groupcache.put(taskgraph, model); } } return model; } /** * @return the tool component model used for the specified tool */ private ToolComponentModel locateToolComponentModel(Tool tool) { RenderingHint[] hints = tool.getRenderingHints(); String hint; ToolComponentModel model = null; int priority = -1; for (int count = 0; count < hints.length; count++) { hint = hints[count].getRenderingHint(); if (toolmodels.containsKey(hint)) { if ((model == null) || (classorder.indexOf(hint) > priority)) { model = (ToolComponentModel) toolmodels.get(hint); priority = classorder.indexOf(hint); } } } if ((model == null) && (getDefaultToolModel() != null)) { model = getDefaultToolModel(); } return model; } /** * @return the open group component model used for the specified taskgraph */ private OpenGroupComponentModel locateOpenGroupComponentModel(TaskGraph taskgraph) { RenderingHint[] hints = taskgraph.getRenderingHints(); String hint; OpenGroupComponentModel model = null; int priority = -1; for (int count = 0; count < hints.length; count++) { hint = hints[count].getRenderingHint(); if (groupmodels.containsKey(hint)) { if ((model == null) || (groupclassorder.indexOf(hint) > priority)) { model = (OpenGroupComponentModel) groupmodels.get(hint); priority = groupclassorder.indexOf(hint); } } } if ((model == null) && (getDefaultOpenGroupModel() != null)) { model = getDefaultOpenGroupModel(); } return model; } private class RemoveExtensionMenuListener implements PopupMenuListener { private JPopupMenu menu; private JMenu extmenu; private Component separator; public RemoveExtensionMenuListener(JPopupMenu menu, JMenu extmenu, Component separator) { this.menu = menu; this.extmenu = extmenu; this.separator = separator; } public void popupMenuCanceled(PopupMenuEvent e) { } public void popupMenuWillBecomeInvisible(PopupMenuEvent event) { final PopupMenuListener listener = this; SwingUtilities.invokeLater(new Runnable() { public void run() { menu.removePopupMenuListener(listener); menu.remove(extmenu); menu.remove(separator); } }); } public void popupMenuWillBecomeVisible(PopupMenuEvent e) { } } }