/*
* 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.panels;
import org.trianacode.gui.Display;
import org.trianacode.gui.builder.GUICreaterPanel;
import org.trianacode.gui.hci.GUIEnv;
import org.trianacode.gui.util.Env;
import org.trianacode.gui.windows.ErrorDialog;
import org.trianacode.gui.windows.ParameterWindow;
import org.trianacode.taskgraph.Task;
import org.trianacode.taskgraph.TaskGraph;
import org.trianacode.taskgraph.event.*;
import org.trianacode.taskgraph.service.TrianaClient;
import org.trianacode.taskgraph.tool.ClassLoaders;
import org.trianacode.taskgraph.tool.Tool;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import java.awt.*;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.Vector;
/**
* The parameter panel manager keeps a hashtable of parameter panels for each task. It monitors all open taskgraphs, and
* if a task is created with its paramPanelInstantiate parameter set to true, the parameter panel for that task is
* immediately instantiated. If a parameter panel is not immediately instantiated then it is instantiated when it is
* first accessed.
*
* @author Ian Wang
* @version $Revision: 4048 $
*/
public class ParameterPanelManager implements TaskGraphListener, TaskListener {
private static ParameterPanelManager disposemanager = new ParameterPanelManager();
/**
* a hashtable of parameter panels keyed task
*/
private static Hashtable paneltable = new Hashtable();
/**
* A hashtable of the open windows, keyed by task
*/
private static Hashtable windowtable = new Hashtable();
/**
* A hashtable of tasks, keyed by their window
*/
private static Hashtable tasktable = new Hashtable();
/**
* Notifies the parameter panel manager to monitor the specified taskgraph
*/
public void monitorTaskGraph(TaskGraph taskgraph) {
handleTaskCreated(taskgraph);
taskgraph.addTaskGraphListener(this);
}
/**
* Notifies the parameter panel manager to stop monitoring the specified taskgraph
*/
public void unmonitorTaskGraph(TaskGraph taskgraph) {
taskgraph.removeTaskGraphListener(this);
}
/**
* @return the parameter panel for the specified task (or null if none)
*/
public static ParameterPanel getParameterPanel(Task task) {
instantiatePanel(task);
if (paneltable.containsKey(task)) {
ParameterPanel paramPanel = (ParameterPanel) paneltable.get(task);
if (isAlreadyInWindow(paramPanel)) {
paramPanel = new MessagePanel(
"Properties for " + task.getToolName() + " already visible in existing window");
paramPanel.setTask(task);
paramPanel.init();
}
return paramPanel;
} else if (task instanceof TaskGraph) {
return initGroupPanel((TaskGraph) task);
} else {
return null;
}
}
private static boolean isAlreadyInWindow(ParameterPanel paramPanel) {
Container cont = paramPanel.getParent();
while ((cont != null) && (!(cont instanceof Window))) {
cont = cont.getParent();
}
return (cont instanceof Window);
}
/**
* @return true if the specified task has a parameter panel
*/
public static boolean isParameterPanel(Task task) {
return (task.isParameterName(Tool.PARAM_PANEL_CLASS) ||
task.isParameterName(Tool.GUI_BUILDER) ||
task.isParameterName(Tool.OLD_GUI_BUILDER) ||
(task instanceof TaskGraph));
}
/**
* @return true if the panel for the class is instantiate on task creation
*/
public static boolean isInstantiatePanel(Task task) {
return (task.isParameterName(Tool.PARAM_PANEL_CLASS) &&
((!task.isParameterName(Tool.PARAM_PANEL_INSTANTIATE) ||
(task.getParameter(Tool.PARAM_PANEL_INSTANTIATE).equals(Tool.ON_TASK_INSTANTIATION)))));
}
private static Component getRegisterPanel(Task task) {
Object c = task.getParameter(Tool.PANEL_INSTANCE);
if (c != null && c instanceof Component) {
return (Component) c;
}
return null;
}
private void handleTaskCreated(Task task) {
Component c = getRegisterPanel(task);
if (c != null) {
try {
registerComponent(c, task);
} catch (Exception e) {
e.printStackTrace();
}
} else {
if (isInstantiatePanel(task)) {
instantiatePanel(task);
}
if (task instanceof TaskGraph) {
Task[] tasks = ((TaskGraph) task).getTasks(true);
for (int count = 0; count < tasks.length; count++) {
handleTaskCreated(tasks[count]);
}
}
}
}
private static void instantiatePanel(Task task) {
if (!paneltable.containsKey(task)) {
ParameterPanel paramPanel = null;
if (task.isParameterName(Tool.GUI_BUILDER)) {
paramPanel = initGUIBuilderV2Panel((String) task.getParameter(Tool.GUI_BUILDER), task);
} else if (task.isParameterName(Tool.PARAM_PANEL_CLASS)) {
paramPanel = initParameterPanel(task);
} else if (task.isParameterName(Tool.OLD_GUI_BUILDER)) {
throw (new RuntimeException("Deprecated GUI Builder information in " + task.getToolName()
+ ": Tool XML must be be regenrated"));
}
if (paramPanel != null) {
paneltable.put(task, paramPanel);
task.addTaskListener(disposemanager);
}
}
}
public static void registerComponent(Component panel, Task task) throws Exception {
if (!paneltable.containsKey(task)) {
ParameterPanel paramPanel = null;
if (panel instanceof ParameterPanel) {
paramPanel = (ParameterPanel) panel;
} else if (panel instanceof Window) {
throw new Exception("You Cannot use a Window as a Triana GUI Component!");
} else {
paramPanel = new PanelHolder(panel);
}
paneltable.put(task, paramPanel);
task.addTaskListener(disposemanager);
}
}
/**
* Initialises a parameter panel containing sub-parameter panels for all tasks in the group.
*/
private static ParameterPanel initGroupPanel(TaskGraph taskgraph) {
Task[] tasks = taskgraph.getTasks(true);
ParameterPanel paramPanel;
ArrayList panels = new ArrayList();
for (int count = 0; count < tasks.length; count++) {
paramPanel = getParameterPanel(tasks[count]);
if (paramPanel != null) {
panels.add(paramPanel);
}
}
ParameterPanel groupPanel = new GroupParameterPanel(
(ParameterPanel[]) panels.toArray(new ParameterPanel[panels.size()]));
groupPanel.setTask(taskgraph);
groupPanel.init();
return groupPanel;
}
/**
* Initializes a GUI Builder V2 parameter panel for the task.
*/
protected static ParameterPanel initGUIBuilderV2Panel(String fullline, Task task) {
Vector<String> guilines = GUICreaterPanel.splitLine(fullline);
ParameterPanel paramPanel = new GUICreaterPanel(guilines);
paramPanel.setTask(task);
paramPanel.init();
GUICreaterPanel panel = ((GUICreaterPanel) paramPanel);
for (int i = 0; i < panel.getRows(); ++i) {
Object rowValue = task.getParameter(panel.getRow(i).getParameterName());
if (rowValue != null) {
panel.getRow(i).setValue(rowValue.toString());
} else {
String msg = "Error generating panel for: " + task.getToolName() + "\n"
+ "Unit: " + task.getProxy().toString() + "\n"
+ "Unit does not have a corresponding parameter for the GUI element: "
+ panel.getRow(i).getParameterName() + "\n"
+ "recompile/regenerate unit may fix";
new ErrorDialog("GUI Builder Error", msg);
}
}
return paramPanel;
}
/**
* Initializes a parameter panel interface for the task.
*/
protected static ParameterPanel initParameterPanel(Task task) {
ParameterPanel paramPanel = null;
try {
TrianaClient client = GUIEnv.getTrianaClientFor(task);
//TODO - removed necessity for TrianaClient. Not sure why this would be needed
//if (client != null) {
paramPanel = createPanel(task);
paramPanel.setTask(task);
paramPanel.init();
//}
}
catch (ClassNotFoundException except) {
new ErrorDialog(Env.getString("panelNotFoundError"),
Env.getString("panelNotFoundError") + ": " + task.getParameter(Tool.PARAM_PANEL_CLASS));
}
catch (Exception except) {
new ErrorDialog(Env.getString("panelInstantiationError"),
Env.getString("panelInstantiationError") + ": " + task.getParameter(Tool.PARAM_PANEL_CLASS));
except.printStackTrace();
}
return paramPanel;
}
/**
* Attempt to find and load the ParameterPanel specified by this classname and task.
*/
public static ParameterPanel createPanel(Task task) throws Exception {
if (!task.isParameterName(Tool.PARAM_PANEL_CLASS)) {
throw (new Exception("Error Instantiating Parameter Panel For " + task.getToolName()
+ " : Parameter panel class not specified"));
}
String classname = (String) task.getParameter(Tool.PARAM_PANEL_CLASS);
Class paramClass;
try {
paramClass = ClassLoaders.forName(classname);
}
catch (ClassNotFoundException e) {
throw (new Exception(Env.getString("panelNotFoundError") + ": " + classname));
}
JPanel panel;
try {
panel = (JPanel) paramClass.newInstance();
}
catch (Exception e) {
e.printStackTrace();
throw (new Exception(Env.getString("panelInstantiationError") + ": " + classname));
}
if (!(panel instanceof ParameterPanel)) {
panel = new PanelHolder(panel);
}
return (ParameterPanel) panel;
}
/**
* Called when a new task is created in a taskgraph.
*/
public void taskCreated(TaskGraphTaskEvent event) {
if (event.getTask() instanceof TaskGraph) {
monitorTaskGraph((TaskGraph) event.getTask());
} else {
handleTaskCreated(event.getTask());
}
}
/**
* Called when a task is removed from a taskgraph. Note that this method is called when tasks are removed from a
* taskgraph due to being grouped (they are place in the groups taskgraph).
*/
public void taskRemoved(TaskGraphTaskEvent event) {
if (event.getTask() instanceof TaskGraph) {
unmonitorTaskGraph((TaskGraph) event.getTask());
}
}
/**
* Called before the task is disposed
*/
public void taskDisposed(TaskDisposedEvent event) {
if (paneltable.contains(event.getTask())) {
ParameterPanel panel = (ParameterPanel) paneltable.remove(event.getTask());
panel.disposePanel();
}
}
/**
* Called when a new connection is made between two tasks.
*/
public void cableConnected(TaskGraphCableEvent event) {
}
/**
* Called before a connection between two tasks is removed.
*/
public void cableDisconnected(TaskGraphCableEvent event) {
}
/**
* Called when a connection is reconnected to a different task.
*/
public void cableReconnected(TaskGraphCableEvent event) {
}
/**
* Called when the control task is connected/disconnected or unstable
*/
public void controlTaskStateChanged(ControlTaskStateEvent event) {
}
/**
* Called when a data input node is added.
*/
public void nodeAdded(TaskNodeEvent event) {
}
/**
* Called before a data input node is removed.
*/
public void nodeRemoved(TaskNodeEvent event) {
}
/**
* Called when the value of a parameter is changed, including when a parameter is removed.
*/
public void parameterUpdated(ParameterUpdateEvent event) {
}
/**
* Called when the core properties of a task change i.e. its name, whether it is running continuously etc.
*/
public void taskPropertyUpdate(TaskPropertyEvent event) {
}
public static ParameterWindow showParameterWindowFor(Task task, Object source) {
if (windowtable.containsKey(task)) {
ParameterWindow window = (ParameterWindow) windowtable.get(task);
if (window.isVisible()) {
window.requestFocus();
} else {
window.setVisible(true);
}
return window;
} else {
ParameterPanel panel = getParameterPanel(task);
if (panel != null) {
ParameterWindow paramWindow;
if (panel.isAlwaysOnTopPreferred()) {
paramWindow = new ParameterWindow(GUIEnv.getApplicationFrame(), panel.getPreferredButtons(), false);
} else {
paramWindow = new ParameterWindow(panel.getPreferredButtons());
}
windowtable.put(task, paramWindow);
tasktable.put(paramWindow, task);
paramWindow.addWindowListener(new ParamWindowListener());
paramWindow.setAutoDispose(false);
paramWindow.setTitle(task.getToolName());
paramWindow.setParameterPanel(panel);
Point loc = Display.getAnchorPoint(source, paramWindow);
loc.translate(140, 40);
paramWindow.setLocation(loc);
paramWindow.show();
return paramWindow;
}
}
return null;
}
public static void hideParameterWindowFor(Task task) {
if (windowtable.containsKey(task)) {
ParameterWindow window = (ParameterWindow) windowtable.get(task);
window.setVisible(false);
window.closeWindow();
}
}
private static class MessagePanel extends ParameterPanelImp {
public MessagePanel(String message) {
JPanel messpanel = new JPanel(new BorderLayout());
messpanel.setBorder(new EmptyBorder(3, 3, 3, 3));
messpanel.add(new JLabel(message), BorderLayout.CENTER);
add(messpanel);
}
}
private static class ParamWindowListener implements WindowListener {
/**
* Invoked when a window has been closed as the result of calling dispose on the window.
*/
public void windowClosed(WindowEvent event) {
Task task = (Task) tasktable.remove(event.getWindow());
if (task != null) {
windowtable.remove(task);
}
}
public void windowActivated(WindowEvent e) {
}
public void windowClosing(WindowEvent e) {
}
public void windowDeactivated(WindowEvent e) {
}
public void windowDeiconified(WindowEvent e) {
}
public void windowIconified(WindowEvent e) {
}
public void windowOpened(WindowEvent e) {
}
}
}