package jas2.swingstudio;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.tree.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.util.*;
import jas2.util.*;
import jas2.util.tree.*;
import jas2.job.*;
import jas2.plugin.*;
import java.rmi.*;
/**
* JASJob is that part of the "Job" which is always in the client, regardless of whether the job
* is local or remote. The getJob() method will return the real job, which may be an instance of
* LocalJob or JasJobAdaptor (for remote jobs).
*/
public final class JASJob implements Serializable, TreeSelectionListener, StoppableExecution, TreeObjectSource, ActionListener
{
static final long serialVersionUID = 8830773281026894908L;
public JASJob(String name)
{
m_name = name;
m_root = new TreeNode(name,"Job");
m_command = new JASJobCommandProcessor();
m_treeModel = new SimpleTreeModel(m_root);
m_treeRenderer = new JASTreeCellRenderer();
m_listRenderer = new JASListCellRenderer();
}
private void writeObject(ObjectOutputStream stream) throws IOException
{
stream.defaultWriteObject();
// Store the state of the remote job
stream.writeInt(m_job.eventsAnalyzed());
stream.writeBoolean(m_job.isAtEndOfData());
m_changes = 0;
m_command.forceSetChanged();
// m_treeModel.saveState(stream);
}
private void readObject(ObjectInputStream stream)
throws OpenJobException
{
try
{
m_treeRenderer = new JASTreeCellRenderer();
m_eventSourceModel = new ComboModel();
m_listRenderer = new JASListCellRenderer();
m_plugins = new Vector();
m_pluginMenus = new Vector();
m_pluginContext = new JobPluginContext(m_app);
stream.defaultReadObject();
m_root = new TreeNode(m_name,"Job");
m_treeModel = new SimpleTreeModel(m_root);
m_job.reopen(stream, this);
m_app = JavaAnalysisStudio.getApp();
m_changes = 0;
( m_command = new JASJobCommandProcessor() ).setChanged();
m_app.getCommandManager().add(m_command);
m_stopMonitor = m_app.registerStoppable(this);
// m_treeModel.restoreState(stream);
}
catch (Exception e)
{
throw new OpenJobException(e);
}
m_changes = 0;
}
/**
* Adds a plugin to the list of active plugins
* (so that they can be destroyed cleanly when the job is closed).
*/
private void addPlugin(IPlugin p)
{
m_plugins.addElement(p);
p.setPluginContext(m_pluginContext);
}
void loadPlugin(String className) throws InstantiationException,IllegalAccessException,ClassNotFoundException
{
Class pc = loadClientClass(className);
IPlugin plugin = (IPlugin) pc.newInstance();
addPlugin(plugin);
}
Class loadClientClass(String className) throws ClassNotFoundException
{
return m_job.loadClientClass(className);
}
void close()
{
if (m_job != null) m_job.close();
if (m_command != null) m_app.getCommandManager().remove(m_command);
m_job = null;
m_command = null;
if (m_stopMonitor != null) m_stopMonitor.end();
clearTreeModel();
clearEventSourceModel();
m_app.setCurrentSelection(null);
// unload any plugins
Enumeration e = m_plugins.elements();
while (e.hasMoreElements())
{
IPlugin p = (IPlugin) e.nextElement();
p.destroy();
}
JMenuBar menuBar = m_app.getMenuBar();
e = m_pluginMenus.elements();
while (e.hasMoreElements())
{
JMenu menu = (JMenu) e.nextElement();
menuBar.remove(menu);
}
menuBar.revalidate();
// Now would be a great time for a garbage collection!
Runtime rt = Runtime.getRuntime();
rt.gc();
rt.runFinalization();
}
/**
* Causes all classes loaded as a result of the LoadClass command to be
* reloaded
*/
void reload() throws RemoteException, LoaderException
{
if (m_job != null) m_job.reload();
m_changes++;
m_command.forceSetChanged();
}
/**
* Get the job name
*/
String getName()
{
return m_name;
}
/**
* The path to the file where this job is stored (use for Save/Restore)
*/
void setFilePath(String path)
{
m_filePath = path;
}
String getFilePath()
{
return m_filePath;
}
public void setJob(Job job)
{
m_job = job;
m_app.getCommandManager().add(m_command);
m_stopMonitor = m_app.registerStoppable(this);
}
public boolean isChanged()
{
return m_changes>0 || ( m_job != null && m_job.isChanged());
}
void setTreeModel(JTree tree)
{
if (m_tree != null)
{
// This is important to avoid memory leaks
m_tree.getSelectionModel().removeTreeSelectionListener(this);
m_tree.removeTreeSelectionListener((TreeSelectionListener) m_tree.getCellEditor());
}
m_tree = tree;
if (tree != null)
{
tree.setModel(m_treeModel);
tree.setCellRenderer(m_treeRenderer);
tree.setCellEditor(new JASTreeCellEditor(tree,m_treeRenderer));
tree.getSelectionModel().addTreeSelectionListener(this);
}
}
private void clearTreeModel()
{
setTreeModel(null);
}
/**
* Used to attach the "Current Event Source" combo box to the event source model.
* Also installs a listener to listen for changes to the combo box
*/
void setEventSourceModel(JComboBox combo)
{
if (m_combo != null)
{
m_combo.removeActionListener(this);
}
m_combo = combo;
if (combo != null)
{
combo.setModel(m_eventSourceModel);
combo.setRenderer(m_listRenderer);
combo.addActionListener(this);
}
}
private void clearEventSourceModel()
{
setEventSourceModel(null);
}
/**
* The event source combo box has been changed
*/
public void actionPerformed(ActionEvent e)
{
TreeNode node = (TreeNode) m_combo.getSelectedItem();
if (node != null) m_job.setEventSource(node.getTreeItem());
}
void updateTree()
{
//if (m_treeModel != null) m_treeModel.update();
m_changes++;
if (m_command != null) m_command.forceSetChanged();
}
void setCommandChanged()
{
if (m_command != null) m_command.setChanged();
}
Job getJob()
{
return m_job;
}
ComboBoxModel getComboModel()
{
return m_eventSourceModel;
}
ListCellRenderer getListRenderer()
{
return m_listRenderer;
}
public void stop()
{
m_job.stop();
m_stopMonitor.doStopEnabling();
}
public boolean isRunning()
{
return m_job.isRunning();
}
void addNode(TreeItem item)
{
TreeNode node = (TreeNode) m_root.add(item);
if ((item.flags & Job.EVENTSOURCE) != 0)
{
m_eventSourceModel.addElement(node);
}
node.update();
}
void deleteNode(TreeItem item)
{
TreeNode node = (TreeNode) m_root.find(item);
deleteEventSource(node);
node.destroy();
}
private void deleteEventSource(TreeNode node)
{
m_eventSourceModel.removeElement(node);
Enumeration e = node.children();
if (e != null) while (e.hasMoreElements()) deleteEventSource((TreeNode) e.nextElement());
}
private Object getAssociatedObject(TreeNode node)
{
return m_job.getItem(getTreeItem(node));
}
private TreeItem getTreeItem(TreeNode node)
{
return node.getTreeItem(m_root);
}
public Object getItem(TreeItem item)
{
return m_job.getItem(item);
}
public void valueChanged(TreeSelectionEvent e)
{
TreeNode sel = (TreeNode) e.getPath().getLastPathComponent();
TreeAdaptor a = sel.getTreeAdaptor();
m_app.setCurrentSelection(a);
}
/**
* Loads a class into the Job (either local or remote)
*/
public void loadClass(String name)
{
try
{
m_job.loadObject(name);
// if successful...
m_changes++;
setCommandChanged();
}
catch (jas2.job.LoaderException e)
{
// before throwing an exception, we expect loadObject() to do all cleanup for us
m_app.error("Could not load class", e);
}
}
boolean isLoaded(String className)
{
return m_job.isLoaded(className);
}
private String m_name;
private Job m_job;
private transient TreeModel m_treeModel = null;
private transient DefaultTreeCellRenderer m_treeRenderer;
private transient ListCellRenderer m_listRenderer;
private transient String m_filePath = null;
private transient int m_changes = 0;
private transient boolean m_connected = false;
private transient TreeNode m_root;
private transient JASJobCommandProcessor m_command;
private transient StoppableExecutionMonitor m_stopMonitor;
private transient JavaAnalysisStudio m_app = JavaAnalysisStudio.getApp();
private transient ComboModel m_eventSourceModel = new ComboModel();
private transient Vector m_plugins = new Vector();
private transient Vector m_pluginMenus = new Vector();
private transient PluginContext m_pluginContext = new JobPluginContext(m_app);
private transient JTree m_tree;
private transient JComboBox m_combo;
private class JobPluginContext extends JASPluginContext implements PluginContext
{
JobPluginContext(JavaAnalysisStudio app)
{
super(app);
}
public void addMenu(JMenu menu)
{
super.addMenu(menu);
m_pluginMenus.addElement(menu);
}
public void removeMenu(JMenu menu)
{
super.removeMenu(menu);
m_pluginMenus.removeElement(menu);
}
public void addRunListener(RunListener listener)
{
m_job.addRunListener(listener);
}
public void removeRunListener(RunListener listener)
{
m_job.removeRunListener(listener);
}
public hepjas.analysis.EventData getCurrentEvent() throws NoEventAvailable
{
return m_job.getEvent();
}
public void sendJob(Object message)
{
m_job.receiveMessage(message);
}
private Vector m_runListeners = new Vector();
}
private class ComboModel extends DefaultComboBoxModel
{
public void addElement(TreeNode node)
{
int index = getIndexOf(node);
if (index < 0) super.addElement(node);
if ((node.getFlags() & Job.CURRENTEVENTSOURCE) != 0 &&
getSelectedItem() != node)
{
setSelectedItem(node);
}
}
}
/**
* The JASJob contains a collection of TreeNodes that are mirrors of the
* nodes in the Job. JASJob.TreeNodes however implement TreeAdaptorSite which
* makes it possible to add popup menus and other GUI functionality to them.
*
* Currently the TreeNodes contain a lot of information which duplicates
* the information in the Job tree. It might be possible to merge these two trees,
* (when running locally), by having a tree factory which would create different
* types of nodes in the Job structure depending whether running locally or remotely.
* In this case we could make an extended version of SimpleNode which also implements
* TreeAdaptorSite. This is currently left as a future improvement. One complication
* would be that all updates to the tree in JASJob are done from the event dispatch thread,
* while the tree in AbstractJob can be updated from other threads.
*
*/
class TreeNode extends OrderedNode implements TreeAdaptorSite, Serializable
{
TreeNode(String name, String type)
{
super(name,type,0,JASJob.this);
}
TreeNode(TreeNode parent, String name, String type, int flags)
{
this(parent,name,type,flags,null);
}
private TreeNode(TreeNode parent, String name, String type, int flags, Object object)
{
super(parent,name,type,flags,object);
}
protected SimpleNode createNode(SimpleNode parent, String name, String type, int flags, Object object)
{
return new TreeNode((TreeNode) parent,name,type,flags,object);
}
/*
* This routine attempts to load and return a command processor
* suitable for this type of object
*/
public TreeAdaptor getTreeAdaptor()
{
if (adaptor == null && getType() != null)
{
try
{
String s = getType();
if (s.indexOf(".") < 0) s = "jas2.swingstudio.adaptor."+s.substring(0,1).toUpperCase()+s.substring(1)+"TreeAdaptor";
else s += "TreeAdaptor";
// S.Chekanov System.out.println(s);
Class c = Class.forName(s);
adaptor = (TreeAdaptor) c.newInstance();
adaptor.setAdaptorSite(this);
}
catch (ClassNotFoundException x)
{
adaptor = null;
}
catch (InstantiationException x)
{
adaptor = null;
}
catch (IllegalAccessException x)
{
adaptor = null;
}
}
return adaptor;
}
void update()
{
int flags = getFlags();
if ((flags & Job.SHOWNOW) != 0 && adaptor == null) getTreeAdaptor();
if (adaptor != null) adaptor.updateNode(flags);
}
public Object getAssociatedObject()
{
return getObject();
}
public PluginContext getPluginContext()
{
return m_pluginContext;
}
public TreeItem getTreeItem()
{
return JASJob.this.getTreeItem(this);
}
// Who uses this??
public Job getJob()
{
return m_job;
}
/**
* @return the icon for this node, or null if no custom icon exists
*/
Icon getIcon()
{
try
{
return new JASIcon(this,"images/"+this.getType()+".gif");
}
catch (ImageException x)
{
return null;
}
}
// Who uses this??
public TreeAdaptorSite getParentAdaptor()
{
return (TreeNode) getParent();
}
/**
* Support for editing (renaming)
*/
boolean isEditable()
{
TreeAdaptor ta = getTreeAdaptor();
return ta == null ? false : ta.isEditable();
}
JPopupMenu getPopupMenu()
{
TreeAdaptor ta = getTreeAdaptor();
return ta == null ? null : ta.getPopupMenu();
}
public void startEditing()
{
int n;
SimpleNode node = this;
for (n=0; node != null; n++) node=node.getParent();
SimpleNode[] nodes = new SimpleNode[n];
node = this;
for (int i=1; node != null; i++) { nodes[n-i] = node; node=node.getParent(); }
m_tree.startEditingAtPath(new TreePath(nodes));
}
private TreeAdaptor adaptor;
}
private static class JASTreeCellRenderer extends DefaultTreeCellRenderer
{
public Component getTreeCellRendererComponent(
JTree tree,
Object value,
boolean selected,
boolean expanded,
boolean leaf,
int row,
boolean hasFocus)
{
super.getTreeCellRendererComponent(tree,value,selected,expanded,leaf,row,hasFocus);
Icon icon = ((TreeNode) value).getIcon();
if (icon != null) setIcon(icon);
return this;
}
}
private class JASTreeCellEditor extends DefaultTreeCellEditor
{
JASTreeCellEditor(JTree tree, DefaultTreeCellRenderer renderer)
{
super(tree,renderer);
}
protected void determineOffset(JTree tree, Object value,
boolean isSelected, boolean expanded,
boolean leaf, int row)
{
editingIcon = ((TreeNode) value).getIcon();
if (editingIcon == null)
{
super.determineOffset(tree,value,isSelected,expanded,leaf,row);
}
else
{
offset = renderer.getIconTextGap() +
editingIcon.getIconWidth();
}
}
/**
* This is invoked if a TreeCellEditor is not supplied in the constructor.
* It returns a TextField editor.
*/
protected TreeCellEditor createTreeCellEditor()
{
javax.swing.border.Border aBorder = UIManager.getBorder("Tree.editorBorder");
DefaultCellEditor editor = new DefaultCellEditor(new DefaultTextField(aBorder))
{
public boolean shouldSelectCell(EventObject event)
{
boolean retValue = super.shouldSelectCell(event);
getComponent().requestFocus();
return retValue;
}
public boolean stopCellEditing()
{
TreeNode node = (TreeNode) m_tree.getEditingPath().getLastPathComponent();
if (node.getTreeAdaptor().stopEditing(getCellEditorValue().toString()))
{
return super.stopCellEditing();
}
return false;
}
};
editor.setClickCountToStart(1);
return editor;
}
}
private static class JASListCellRenderer extends DefaultListCellRenderer
{
public Component getListCellRendererComponent(
JList list,
Object value,
int index,
boolean isSelected,
boolean cellHasFocus)
{
super.getListCellRendererComponent(list,value,index,isSelected,cellHasFocus);
if (value != null) setIcon(((TreeNode) value).getIcon());
return this;
}
}
class JASJobCommandProcessor extends JASCommandProcessor
{
public void onOpenDataset()
{
if (m_job instanceof JASJobAdaptor) // remote JOb
{
new JASWizard(m_app.getFrame(), "New Dataset",new OpenDataSetPage((JASJobAdaptor) m_job,m_app));
}
else
{
new JASWizard(m_app.getFrame(), "New Dataset",new LocalJobPage(new JASLocalJobBuilder((LocalJob) m_job)));
}
}
public void onLoadProgram()
{
LoadDialog dlg = new LoadDialog(m_app.getFrame());
if (dlg.doModal())
loadClass(dlg.getClassName());
// loadClass() should handle all exceptions
}
public void onLoadPlugin()
{
LoadDialog dlg = new LoadPluginDialog(m_app.getFrame());
if (dlg.doModal())
{
try
{
loadPlugin(dlg.getClassName());
}
catch (Exception e)
{
m_app.error("Could not load plugin",e);
}
}
}
public void onUnloadAllPrograms() throws RemoteException
{
m_job.unloadAll();
m_changes++;
setChanged();
}
public void onSaveJob() throws IOException, JASException
{
if (m_app.jobSavingDisabled) throw new NotImplemented("Saving and restoring jobs");
m_app.saveJob();
}
// public void enableSaveJob(JASState state)
// {
// state.setEnabled(m_changes > 0);
// }
// Right now too difficult to include all the ways the job could have changed
// e.g. adding a function to a plot
public void onSaveJobAs() throws IOException, JASException
{
if (m_app.jobSavingDisabled) throw new NotImplemented("Saving and restoring jobs");
m_app.saveJobAs();
}
public void onCloseCurrentJob()
{
m_app.closeCurrentJob();
m_app.setToEmptyJob();
}
public void enableDisconnect(JASState state)
{
state.setEnabled(m_job instanceof JASJobAdaptor);
}
public void onDisconnect() throws RemoteException
{
((JASJobAdaptor) m_job).disconnect();
m_job = null;
m_app.closeCurrentJob();
m_app.setToEmptyJob();
}
public void onKill() throws RemoteException
{
m_job.kill();
}
public void onRewind() throws RemoteException
{
m_job.rewind();
}
public void onStep() throws RemoteException
{
m_job.go(1);
}
public void onGo() throws RemoteException
{
m_job.go(0);
}
//public void enableRun(JASState state)
//{
// state.setEnabled(m_job.isRunnable());
//}
public void enableGo(JASState state)
{
state.setEnabled(m_job.isRunnable() && !m_job.isAtEndOfData());
}
public void enableStep(JASState state)
{
state.setEnabled(m_job.isRunnable() && !m_job.isAtEndOfData());
}
public void enableRewind(JASState state)
{
state.setEnabled(!m_job.isAtStartOfData());
}
public void enableKill(JASState state)
{
state.setEnabled(m_job.isRunning());
}
public void enablePersistent(JASCheckboxState state)
{
state.setCheckbox(m_job.isPersistent());
state.setEnabled(true);
}
public void onPersistent(boolean persist) throws RemoteException
{
m_job.setPersistent(persist);
m_changes++;
setChanged();
}
protected void setChanged()
{
super.setChanged();
if (m_stopMonitor != null)
m_stopMonitor.doStopEnabling();
// have the stop button enable with the rest
}
void forceSetChanged()
{
super.setChanged();
}
}
}
Ads help maintain this website.