\n");
//moml.append("\n");
moml.append((String) transferable
.getTransferData(DataFlavor.stringFlavor));
// Needed by Kepler's Comad.
BasicGraphFrameExtension.alternatePasteMomlModification(container,
moml);
moml.append(" \n");
MoMLChangeRequest change = new OffsetMoMLChangeRequest(this,
container, moml.toString());
change.setUndoable(true);
container.requestChange(change);
// Added by Lei Dou to update the signature for Kepler/Comad
BasicGraphFrameExtension.alternatePaste(container, moml);
} catch (Exception ex) {
MessageHandler.error("Paste failed", ex);
}
}
/** Print the visible portion of the graph to a printer,
* which is represented by the specified graphics object.
* @param graphics The context into which the page is drawn.
* @param format The size and orientation of the page being drawn.
* @param index The zero based index of the page to be drawn.
* @return PAGE_EXISTS if the page is rendered successfully, or
* NO_SUCH_PAGE if pageIndex specifies a non-existent page.
* @exception PrinterException If the print job is terminated.
*/
@Override
public int print(Graphics graphics, PageFormat format, int index)
throws PrinterException {
if (getJGraph() != null) {
Rectangle2D view = getVisibleRectangle();
return getJGraph().print(graphics, format, index, view);
} else {
return NO_SUCH_PAGE;
}
}
/** Redo the last undone change on the model.
* @see #undo()
*/
public void redo() {
GraphModel model = _getGraphModel();
try {
NamedObj toplevel = (NamedObj) model.getRoot();
RedoChangeRequest change = new RedoChangeRequest(this, toplevel);
toplevel.requestChange(change);
} catch (Exception ex) {
MessageHandler.error("Redo failed", ex);
}
}
// /** Open a file browser and save the given entity in the file specified
// * by the user.
// * @param entity The entity to save.
// * @exception Exception If there is a problem saving the component.
// * @since Ptolemy 4.0
// */
// public void saveComponentInFile(Entity entity) throws Exception {
// // FIXME: This method is probably no
// // NOTE: This mirrors similar code in Top and TableauFrame, but
// // I can't find any way to re-use that code, since the details
// // are slightly different at each step here.
// JFileChooserBugFix jFileChooserBugFix = new JFileChooserBugFix();
// Color background = null;
// PtFileChooser ptFileChooser = null;
// try {
// background = jFileChooserBugFix.saveBackground();
// ptFileChooser = new PtFileChooser(this,
// "Save Component as...",
// JFileChooser.SAVE_DIALOG);
// ptFileChooser.setCurrentDirectory(_directory);
// // Hmm, is getCurrentDirectory necessary here?
// ptFileChooser.setSelectedFile(new File(ptFileChooser.getCurrentDirectory(),
// entity.getName() + ".xml"));
// int returnVal = ptFileChooser.showDialog(this,
// "Save");
// if (returnVal == JFileChooser.APPROVE_OPTION) {
// // We set _directory below.
// File file = ptFileChooser.getSelectedFile();
// if (!_confirmFile(entity, file)) {
// return;
// }
// // Record the selected directory.
// _directory = ptFileChooser.getCurrentDirectory();
// java.io.FileWriter fileWriter = null;
// try {
// fileWriter = new java.io.FileWriter(file);
// // Make sure the entity name saved matches the file name.
// String name = entity.getName();
// String filename = file.getName();
// int period = filename.indexOf(".");
// if (period > 0) {
// name = filename.substring(0, period);
// } else {
// name = filename;
// }
// fileWriter.write("\n"
// + "\n");
// entity.exportMoML(fileWriter, 0, name);
// } finally {
// if (fileWriter != null) {
// fileWriter.close();
// }
// }
// }
// } finally {
// jFileChooserBugFix.restoreBackground(background);
// }
// }
/** Report a message to either the status bar or message handler.
* @param owner The frame that, per the user, is generating the
* dialog.
* @param message The message.
*/
public static void report(Frame owner, String message) {
if (owner instanceof Top) {
((Top) owner).report(message);
} else {
MessageHandler.message(message);
}
}
/** Save the given entity in the user library in the given
* configuration.
* @param configuration The configuration.
* @param entity The entity to save.
* @since Ptolemy 2.1
* @deprecated Use {@link ptolemy.actor.gui.UserActorLibrary#saveComponentInLibrary(Configuration, Entity)}
*/
@Deprecated
public static void saveComponentInLibrary(Configuration configuration,
Entity entity) {
try {
ptolemy.actor.gui.UserActorLibrary.saveComponentInLibrary(
configuration, entity);
} catch (Exception ex) {
// We catch exceptions here because this method used to
// not throw Exceptions, and we don't want to break compatibility.
MessageHandler
.error("Failed to save \"" + entity.getName() + "\".");
}
}
/** Set the center location of the visible part of the pane.
* This will cause the panner to center on the specified location
* with the current zoom factor.
* @param center The center of the visible part.
* @see #getCenter()
*/
public void setCenter(Point2D center) {
Rectangle2D visibleRect = getVisibleCanvasRectangle();
AffineTransform newTransform = getJGraph().getCanvasPane()
.getTransformContext().getTransform();
newTransform.translate(visibleRect.getCenterX() - center.getX(),
visibleRect.getCenterY() - center.getY());
getJGraph().getCanvasPane().setTransform(newTransform);
}
/** Set the JGraph instance that this view uses to represent the
* ptolemy model.
* @param jgraph The JGraph.
* @see #getJGraph()
*/
public void setJGraph(JGraph jgraph) {
_jgraph = jgraph;
}
/** Undo the last undoable change on the model.
* @see #redo()
*/
public void undo() {
GraphModel model = _getGraphModel();
try {
NamedObj toplevel = (NamedObj) model.getRoot();
UndoChangeRequest change = new UndoChangeRequest(this, toplevel);
toplevel.requestChange(change);
} catch (Exception ex) {
MessageHandler.error("Undo failed", ex);
}
}
/** Update the size, zoom and position of the window.
* This method is typically called when closing the window
* or writing the moml file out.
* @exception IllegalActionException If there is a problem
* getting a parameter.
* @exception NameDuplicationException If there is a problem
* creating a parameter.
*/
public void updateWindowAttributes() throws IllegalActionException,
NameDuplicationException {
// First, record size and position.
// See "composite window size & position not always saved"
// http://bugzilla.ecoinformatics.org/show_bug.cgi?id=5637
// Record the position of the top-level frame, assuming
// there is one.
Component component = _getRightComponent().getParent();
Component parent = component.getParent();
while (parent != null && !(parent instanceof Frame)) {
component = parent;
parent = component.getParent();
}
// Oddly, sometimes getModel returns null? $PTII/bin/ptinvoke
// ptolemy.vergil.basic.export.ExportModel -force htm -run
// -openComposites -whiteBackground
// ptolemy/actor/gt/demo/MapReduce/MapReduce.xml
// $PTII/ptolemy/actor/gt/demo/MapReduce/MapReduce
NamedObj model = getModel();
if (model != null) {
// If there is no parent that is a Frame, do nothing.
// We know that: (parent == null) || (parent instanceof Frame)
if (parent != null) {
WindowPropertiesAttribute properties = (WindowPropertiesAttribute) model
.getAttribute("_windowProperties",
WindowPropertiesAttribute.class);
if (properties == null) {
properties = new WindowPropertiesAttribute(model,
"_windowProperties");
}
// This method uses MoMLChangeRequest
properties.recordProperties((Frame) parent);
}
_createSizeAttribute();
// Also record zoom and pan state.
JCanvas canvas = getJGraph().getGraphPane().getCanvas();
AffineTransform current = canvas.getCanvasPane()
.getTransformContext().getTransform();
// We assume the scaling in the X and Y directions are the same.
double scale = current.getScaleX();
Parameter zoom = (Parameter) model.getAttribute(
"_vergilZoomFactor", Parameter.class);
boolean updateValue = false;
if (zoom == null || zoom.getToken() == null) {
// NOTE: This will not propagate.
zoom = new ExpertParameter(model, "_vergilZoomFactor");
zoom.setToken("1.0");
updateValue = true;
} else {
double oldZoom = ((DoubleToken) zoom.getToken()).doubleValue();
if (oldZoom != scale) {
updateValue = true;
}
}
if (updateValue) {
// Don't call setToken(), instead use a MoMLChangeRequest so that
// the model is marked modified so that any changes are preserved.
//zoom.setToken(new DoubleToken(scale));
String moml = " ";
MoMLChangeRequest request = new MoMLChangeRequest(this, model,
moml);
request.setUndoable(true);
model.requestChange(request);
// Make sure the visibility is only expert.
zoom.setVisibility(Settable.EXPERT);
}
// Save the center, to record the pan state.
Point2D center = getCenter();
Parameter pan = (Parameter) model.getAttribute("_vergilCenter",
Parameter.class);
updateValue = false;
if (pan == null || pan.getToken() == null) {
// NOTE: This will not propagate.
pan = new ExpertParameter(model, "_vergilCenter");
pan.setToken("{" + center.getX() + ", " + center.getY() + "}");
updateValue = true;
} else {
Token[] oldCenter = ((ArrayToken) pan.getToken()).arrayValue();
double oldCenterX = ((DoubleToken) oldCenter[0]).doubleValue();
double oldCenterY = ((DoubleToken) oldCenter[1]).doubleValue();
if (center.getX() != oldCenterX || center.getY() != oldCenterY) {
updateValue = true;
}
}
if (updateValue) {
//Token[] centerArray = new Token[2];
//centerArray[0] = new DoubleToken(center.getX());
//centerArray[1] = new DoubleToken(center.getY());
//pan.setToken(new ArrayToken(centerArray));
String moml = " ";
MoMLChangeRequest request = new MoMLChangeRequest(this, model,
moml);
request.setUndoable(true);
getModel().requestChange(request);
// Make sure the visibility is only expert.
pan.setVisibility(Settable.EXPERT);
}
} // model == null
}
/** Write an HTML page based on the current view of the model
* to the specified destination directory. The file will be
* named "index.html," and supporting files, including at
* least a gif image showing the contents currently visible in
* the graph frame, will be created. If there are any plot windows
* open or any composite actors open, then gif and/or HTML will
* be generated for those as well and linked to the gif image
* created for this frame.
*
* The generated page has a header with the name of the model,
* a reference to a GIF image file with name equal to the name
* of the model with a ".gif" extension appended, and a script
* that reacts when the mouse is moved over an actor by
* displaying a table with the parameter values of the actor.
* The gif image is assumed to have been generated with the
* current view using the {@link #writeImage(OutputStream, String)}
* method.
* @param parameters The parameters that control the export.
* @param writer The writer to use the write the HTML. If this is null,
* then create an index.html file in the
* directory given by the directoryToExportTo field of the parameters.
* @exception IOException If unable to write associated files, or if the
* current configuration does not support it.
* @exception PrinterException If unable to write associated files.
* @exception IllegalActionException If something goes wrong accessing the model.
*/
@Override
public void writeHTML(ExportParameters parameters, Writer writer)
throws PrinterException, IOException, IllegalActionException {
if (_exportHTMLAction != null) {
((HTMLExportable) _exportHTMLAction).writeHTML(parameters, writer);
} else {
throw new IOException("Export to Web not supported.");
}
}
/** Write an image to the specified output stream in the specified format.
* Supported formats include at least "gif" and "png", standard image file formats.
* The image is a rendition of the current view of the model.
*
{@link ptolemy.vergil.basic.export.ExportModel} is a standalone class
* that exports an image of a model.
* @param stream The output stream to write to.
* @param format The image format to generate.
* @see #writeHTML(ExportParameters, Writer)
* @exception IOException If writing to the stream fails.
* @exception PrinterException If the specified format is not supported.
*/
@Override
public void writeImage(OutputStream stream, String format)
throws PrinterException, IOException {
writeImage(stream, format, null);
}
/** Write an image to the specified output stream in the specified format with
* the specified background color.
* Supported formats include at least "gif" and "png", standard image file formats.
* The image is a rendition of the current view of the model.
*
{@link ptolemy.vergil.basic.export.ExportModel} is a standalone class
* that exports an image of a model.
* @param stream The output stream to write to.
* @param format The image format to generate.
* @param background The background color, or null to use the current color.
* @see #writeHTML(ExportParameters, Writer)
* @exception IOException If writing to the stream fails.
* @exception PrinterException If the specified format is not supported.
*/
public void writeImage(OutputStream stream, String format, Color background)
throws PrinterException, IOException {
JCanvas canvas = getJGraph().getGraphPane().getCanvas();
Color previousBackground = canvas.getBackground();
try {
if (background != null) {
canvas.setBackground(background);
}
getJGraph().exportImage(stream, format);
} finally {
if (background != null) {
canvas.setBackground(previousBackground);
}
}
}
/** Zoom in or out to magnify by the specified factor, from the current
* magnification.
* @param factor The magnification factor (relative to 1.0).
*/
public void zoom(double factor) {
try {
_zoomFlag = true;
JCanvas canvas = getJGraph().getGraphPane().getCanvas();
AffineTransform current = canvas.getCanvasPane()
.getTransformContext().getTransform();
// Save the center, so we remember what we were looking at.
Point2D center = getCenter();
current.scale(factor, factor);
canvas.getCanvasPane().setTransform(current);
// Reset the center.
setCenter(center);
if (_graphPanner != null) {
_graphPanner.repaint();
}
} finally {
_zoomFlag = false;
}
}
/** Zoom to fit the current figures.
*/
public void zoomFit() {
GraphPane pane = getJGraph().getGraphPane();
Rectangle2D bounds = pane.getForegroundLayer().getLayerBounds();
zoomFit(pane, bounds);
}
/** Zoom to fit the bounds.
* @param pane The pane.
* @param bounds The bound to zoom to.
*/
public void zoomFit(GraphPane pane, Rectangle2D bounds) {
if (bounds.isEmpty()) {
// Empty diagram.
return;
}
Rectangle2D viewSize = getVisibleRectangle();
Rectangle2D paddedViewSize = new Rectangle2D.Double(viewSize.getX()
+ _ZOOM_FIT_PADDING, viewSize.getY() + _ZOOM_FIT_PADDING,
viewSize.getWidth() - 2 * _ZOOM_FIT_PADDING,
viewSize.getHeight() - 2 * _ZOOM_FIT_PADDING);
AffineTransform newTransform = CanvasUtilities.computeFitTransform(
bounds, paddedViewSize);
JCanvas canvas = pane.getCanvas();
canvas.getCanvasPane().setTransform(newTransform);
if (_graphPanner != null) {
_graphPanner.repaint();
}
}
/** Set zoom to the nominal.
*/
public void zoomReset() {
JCanvas canvas = getJGraph().getGraphPane().getCanvas();
AffineTransform current = canvas.getCanvasPane().getTransformContext()
.getTransform();
current.setToIdentity();
canvas.getCanvasPane().setTransform(current);
if (_graphPanner != null) {
_graphPanner.repaint();
}
}
/**
* Called when the mouse is clicked.
* This base class does nothing when the mouse is clicked.
* However, events _are_ handled by the components within this component.
* @param event The mouse event.
*/
@Override
public void mouseClicked(MouseEvent event) {
// Implementation of the MouseMotionListener interface.
}
/** Transform the graph by the amount the mouse is dragged
* while the middle mouse button is held down.
* @param event The drag event.
*/
@Override
public void mouseDragged(MouseEvent event) {
// Implementation of the MouseMotionListener interface.
// See https://chess.eecs.berkeley.edu/bugzilla/show_bug.cgi?id=73
if (event.isAltDown()) {
// Only interested in middle button. (defined as the alt modifier)
int deltaX = event.getX() - _previousMouseX;
int deltaY = event.getY() - _previousMouseY;
AffineTransform newTransform = getJGraph().getCanvasPane()
.getTransformContext().getTransform();
newTransform.translate(deltaX, deltaY);
getJGraph().getCanvasPane().setTransform(newTransform);
_previousMouseX = event.getX();
_previousMouseY = event.getY();
event.consume();
}
}
/**
* Called when the mouse enters this component.
* This base class does nothing when the enters this component.
* However, events _are_ handled by the components within this component.
* @param event The mouse event.
*/
@Override
public void mouseEntered(MouseEvent event) {
// Implementation of the MouseMotionListener interface.
}
/**
* Called when the mouse leaves this component.
* This base class does nothing when the exits this component.
* However, events _are_ handled by the components within this component.
* @param event The mouse event.
*/
@Override
public void mouseExited(MouseEvent event) {
// Implementation of the MouseMotionListener interface.
}
/** Called when the mouse is moved.
* This base class does nothing when the mouse is moved.
* @param event Contains details of the movement event.
* However, events _are_ handled by the components within this component.
*/
@Override
public void mouseMoved(MouseEvent event) {
// Implementation of the MouseMotionListener interface.
}
/** Store the location of the middle mouse event.
* @param event The mouse event.
*/
@Override
public void mousePressed(MouseEvent event) {
if (event.isAltDown()) {
// Only interested in middle button. (defined as the alt modifier)
_previousMouseX = event.getX();
_previousMouseY = event.getY();
event.consume();
}
}
/**
* Called when the mouse is released.
* This base class does nothing when the mouse is moved.
* However, events _are_ handled by the components within this component.
* @param event The mouse event.
*/
@Override
public void mouseReleased(MouseEvent event) {
// Implementation of the MouseMotionListener interface.
}
/** Scroll in when the mouse wheel is moved.
* @param event The mouse wheel event.
*/
@Override
public void mouseWheelMoved(MouseWheelEvent event) {
// Scrolling the wheel away from you zooms in. This is arbitrary and
// should be configurable by the user.
//
// TODO: It would be nice to centre the zoom on where the
// mouse is. That would mirror what apps like google earth do.
int notches = event.getWheelRotation();
double zoomFactor = 1.25;
if (notches > 0) {
zoomFactor = 1.0 / zoomFactor;
}
zoom(zoomFactor);
}
///////////////////////////////////////////////////////////////////
//// public variables ////
/** Default background color is a light grey. */
public static final Color BACKGROUND_COLOR = new Color(0xe5e5e5);
/** The name of the user library. The default value is
* "UserLibrary". The value of this variable is what appears
* in the Vergil left hand tree menu.
* @deprecated Use {@link ptolemy.actor.gui.UserActorLibrary#USER_LIBRARY_NAME}
*/
@Deprecated
public static String VERGIL_USER_LIBRARY_NAME = UserActorLibrary.USER_LIBRARY_NAME;
///////////////////////////////////////////////////////////////////
//// protected methods ////
/** Add a layout menu.
* @param graphMenu The menu to which to add the layout menu.
*/
protected void _addLayoutMenu(JMenu graphMenu) {
// The layout action is created by BasicGraphFrame.
if (_layoutAction != null) {
// If we are running with -ptinyViewer, then the layout facility
// might not be present.
GUIUtilities.addHotKey(_getRightComponent(), _layoutAction);
GUIUtilities.addMenuItem(graphMenu, _layoutAction);
if (_layoutConfigDialogAction != null) {
GUIUtilities.addMenuItem(graphMenu, _layoutConfigDialogAction);
}
graphMenu.addSeparator();
}
}
/** Create the menus that are used by this frame.
*/
@Override
protected void _addMenus() {
super._addMenus();
_editMenu = new JMenu("Edit");
_editMenu.setMnemonic(KeyEvent.VK_E);
_menubar.add(_editMenu);
// Add the undo action, followed by a separator then the editing actions
diva.gui.GUIUtilities.addHotKey(_getRightComponent(), _undoAction);
diva.gui.GUIUtilities.addMenuItem(_editMenu, _undoAction);
diva.gui.GUIUtilities.addHotKey(_getRightComponent(), _redoAction);
diva.gui.GUIUtilities.addMenuItem(_editMenu, _redoAction);
_editMenu.addSeparator();
GUIUtilities.addHotKey(_getRightComponent(), _cutAction);
GUIUtilities.addMenuItem(_editMenu, _cutAction);
GUIUtilities.addHotKey(_getRightComponent(), _copyAction);
GUIUtilities.addMenuItem(_editMenu, _copyAction);
GUIUtilities.addHotKey(_getRightComponent(), _pasteAction);
GUIUtilities.addMenuItem(_editMenu, _pasteAction);
_editMenu.addSeparator();
GUIUtilities.addHotKey(_getRightComponent(), _moveToBackAction);
GUIUtilities.addMenuItem(_editMenu, _moveToBackAction);
GUIUtilities.addHotKey(_getRightComponent(), _moveToFrontAction);
GUIUtilities.addMenuItem(_editMenu, _moveToFrontAction);
_editMenu.addSeparator();
GUIUtilities.addMenuItem(_editMenu, _editPreferencesAction);
// Hot key for configure (edit parameters).
GUIUtilities.addHotKey(_getRightComponent(),
BasicGraphController._configureAction);
// May be null if there are not multiple views in the configuration.
if (_viewMenu == null) {
_viewMenu = new JMenu("View");
_viewMenu.setMnemonic(KeyEvent.VK_V);
_menubar.add(_viewMenu);
} else {
_viewMenu.addSeparator();
}
GUIUtilities.addHotKey(_getRightComponent(), _zoomInAction);
GUIUtilities.addMenuItem(_viewMenu, _zoomInAction);
GUIUtilities.addHotKey(_getRightComponent(), _zoomResetAction);
GUIUtilities.addMenuItem(_viewMenu, _zoomResetAction);
GUIUtilities.addHotKey(_getRightComponent(), _zoomFitAction);
GUIUtilities.addMenuItem(_viewMenu, _zoomFitAction);
GUIUtilities.addHotKey(_getRightComponent(), _zoomOutAction);
GUIUtilities.addMenuItem(_viewMenu, _zoomOutAction);
_graphMenu = new JMenu("Graph");
_graphMenu.setMnemonic(KeyEvent.VK_G);
_menubar.add(_graphMenu);
GUIUtilities.addHotKey(_getRightComponent(), _findAction);
GUIUtilities.addMenuItem(_graphMenu, _findAction);
}
/** Return true if any element of the specified list is implied.
* An element is implied if its getDerivedLevel() method returns
* anything smaller than Integer.MAX_VALUE.
* @param elements A list of instances of NamedObj.
* @return True if any element in the list is implied.
* @see NamedObj#getDerivedLevel()
*/
protected boolean _checkForImplied(List elements) {
Iterator elementIterator = elements.iterator();
while (elementIterator.hasNext()) {
NamedObj element = elementIterator.next();
if (element.getDerivedLevel() < Integer.MAX_VALUE) {
MessageHandler.error("Cannot change the position of "
+ element.getFullName()
+ " because the position is set by the class.");
return true;
}
}
return false;
}
/** Override the base class to remove the listeners we have
* created when the frame closes. Specifically,
* remove our panner-updating listener from the entity.
* Also remove the listeners our graph model has created.
* @return True if the close completes, and false otherwise.
*/
@Override
protected boolean _close() {
if (_debugClosing) {
System.out.println("BasicGraphFrame._close() : " + this.getName());
}
// See "composite window size & position not always saved"
// http://bugzilla.ecoinformatics.org/show_bug.cgi?id=5637
// Don't update the _windowProperties attribute during _close()
// For example, if the model is a large model and there is an
// error and the user clicks on "Go To Actor", then the model
// may be zoomed. When the user closes the model, they will
// be prompted to save. Even worse, it appears that the size
// and location of windows can be slightly different between
// different platforms.
// try {
// _updateWindowAttributes();
// } catch (KernelException ex) {
// // Ignore problems here. Errors simply result in a default
// // size and location.
// System.out.println("While closing, failed to update size, position or zoom factor: " + ex);
// }
boolean result = super._close();
if (result) {
AbstractBasicGraphModel graphModel = _getGraphModel();
graphModel.removeListeners();
}
return result;
}
/** Create the default library to use if an entity has no
* LibraryAttribute. Note that this is called in the
* constructor and therefore overrides in subclasses
* should not refer to any members that may not have been
* initialized. If no library is found in the configuration,
* then an empty one is created in the specified workspace.
* @param workspace The workspace in which to create
* the library, if one needs to be created.
* @return The new library, or null if there is no
* configuration.
*/
protected CompositeEntity _createDefaultLibrary(Workspace workspace) {
Configuration configuration = getConfiguration();
if (configuration != null) {
CompositeEntity result = (CompositeEntity) configuration
.getEntity("actor library");
if (result == null) {
// Create an empty library by default.
result = new CompositeEntity(workspace);
try {
result.setName("topLibrary");
// Put a marker in so that this is
// recognized as a library.
new Attribute(result, "_libraryMarker");
} catch (Exception ex) {
throw new InternalErrorException(
"Library configuration failed: " + ex);
}
}
return result;
} else {
return null;
}
}
/** Create the items in the File menu's Export section
* This method adds a menu items to export images of the plot
* in GIF, PNG, and possibly PDF.
* @return The items in the File menu.
*/
@Override
protected JMenuItem[] _createFileMenuItems() {
JMenuItem[] fileMenuItems = super._createFileMenuItems();
JMenu importMenu = (JMenu) fileMenuItems[_IMPORT_MENU_INDEX];
importMenu.setEnabled(true);
JMenu exportMenu = (JMenu) fileMenuItems[_EXPORT_MENU_INDEX];
exportMenu.setEnabled(true);
// Get the "export PDF" action classname from the configuration.
// This may or many not be included because it depends on GPL'd code,
// and hence cannot be included included in any pure BSD distribution.
// NOTE: Cannot use getConfiguration() because the configuration is
// not set when this method is called. Hence, we assume that there
// is only one configuration, or that if there are multiple configurations
// in this execution, that the first one will determine whether PDF
// export is provided.
Configuration configuration = (Configuration) Configuration
.configurations().get(0);
// NOTE: Configuration should not be null, but just in case:
if (configuration != null) {
// Here, we get the _importActionClassNames from the configuration.
// _importActionClassNames is an array of Strings where each element
// names a class to that is an import action.
// See also _classesToRemove in Configuration.java
try {
Parameter importActionClassNames = (Parameter) configuration
.getAttribute("_importActionClassNames",
Parameter.class);
if (importActionClassNames != null) {
ArrayToken importActionClassNamesToken = (ArrayToken) importActionClassNames
.getToken();
for (int i = 0; i < importActionClassNamesToken.length(); i++) {
String importActionClassName = ((StringToken) importActionClassNamesToken
.getElement(i)).stringValue();
try {
// Get the class, instantiate it and add it to the menu.
Class importActionClass = Class
.forName(importActionClassName);
Constructor constructor = importActionClass
.getDeclaredConstructor(new Class[] { Top.class });
AbstractAction importAction = (AbstractAction) constructor
.newInstance(new Object[] { this });
JMenuItem importItem = new JMenuItem(importAction);
importMenu.add(importItem);
} catch (Throwable throwable) {
// We do not want to abort at this point because the worst
// case is that we will have no Import FMU in the menu.
// That is better than preventing the user from opening a model.
System.err
.println("Warning: Tried to create the an import menu item, but failed: "
+ throwable);
}
}
}
} catch (Throwable throwable) {
if (!_printedImportActionClassNamesMessage) {
_printedImportActionClassNamesMessage = true;
System.err
.println("Problem reading the _importActionClassNames parameter from "
+ "the configuration: " + throwable);
}
}
// PDF Action.
try {
_exportPDFAction = (AbstractAction) configuration
.getStringParameterAsClass("_exportPDFActionClassName",
new Class[] { Top.class },
new Object[] { this });
} catch (Throwable throwable) {
// We do not want to abort at this point because the worst
// case is that we will have no Export PDF in the menu.
// That is better than preventing the user from opening a model.
//System.err
// .printlns("Warning: Tried to create the Export PDF menu item, but failed: "
// + throwable);
}
// Deal with the HTML Action next.
try {
_exportHTMLAction = (AbstractAction) configuration
.getStringParameterAsClass(
"_exportHTMLActionClassName",
new Class[] { BasicGraphFrame.class },
new Object[] { this });
} catch (Throwable throwable) {
// We do not want to abort at this point because the worst
// case is that we will have no Export to Web in the menu.
// That is better than preventing the user from opening a model.
// We don't include the GPL'd iText PDF in the
// release, so don't print a message if it is missing.
//System.err
// .println("Warning: Tried to create the Export to Web menu item, but failed: "
// + throwable);
}
}
// Uncomment the next block to have Export PDF *ALWAYS* enabled.
// We don't want it always enabled because ptiny, the applets and
// Web Start should not included this AGPL'd piece of software
// NOTE: Comment out the entire block with lines that begin with //
// so that the test in adm notices that the block is commented out.
// if (_exportPDFAction == null) {
// //String exportPDFActionClassName = exportPDFActionClassNameParameter.stringValue();
// String exportPDFActionClassName = "ptolemy.vergil.basic.export.itextpdf.ExportPDFAction";
// try {
// Class exportPDFActionClass = Class
// .forName(exportPDFActionClassName);
// Constructor exportPDFActionConstructor = exportPDFActionClass
// .getDeclaredConstructor(Top.class);
// _exportPDFAction = (AbstractAction) exportPDFActionConstructor
// .newInstance(this);
// } catch (Throwable throwable) {
// new InternalErrorException(null, throwable,
// "Failed to construct export PDF class \""
// + exportPDFActionClassName
// + "\", which was read from the configuration.");
// }
// }
// End of block to uncomment.
if (_exportPDFAction != null) {
// Insert the Export PDF item.
JMenuItem exportItem = new JMenuItem(_exportPDFAction);
exportMenu.add(exportItem);
}
// Next do the export GIF action.
if (_exportGIFAction == null) {
_exportGIFAction = new ExportImageAction("GIF");
}
JMenuItem exportItem = new JMenuItem(_exportGIFAction);
exportMenu.add(exportItem);
// Next do the export PNG action.
if (_exportPNGAction == null) {
_exportPNGAction = new ExportImageAction("PNG");
}
exportItem = new JMenuItem(_exportPNGAction);
exportMenu.add(exportItem);
// Next do the export HTML action.
if (_exportHTMLAction != null) {
// Insert the Export to Web item.
exportItem = new JMenuItem(_exportHTMLAction);
exportMenu.add(exportItem);
}
return fileMenuItems;
}
/** Create a new graph pane. Subclasses will override this to change
* the pane that is created. Note that this method is called in
* constructor, so derived classes must be careful to not reference
* local variables that may not have yet been created.
* @param entity The object to be displayed in the pane.
* @return The pane that is created.
*/
protected abstract GraphPane _createGraphPane(NamedObj entity);
/** Create the component that goes to the right of the library.
* @param entity The entity to display in the component.
* @return The component that goes to the right of the library.
*/
protected JComponent _createRightComponent(NamedObj entity) {
GraphPane pane = _createGraphPane(entity);
FigureLayer fl = pane.getForegroundLayer();
fl.setPickHalo(2);
EventLayer fel = pane.getForegroundEventLayer();
fel.setConsuming(false);
fel.setEnabled(true);
_mousePressedLayerAdapter = new MousePressedLayerAdapter();
fel.addLayerListener(_mousePressedLayerAdapter);
JGraph graph = new JGraph(pane);
setJGraph(graph);
_dropTarget = new EditorDropTarget(_jgraph);
return _jgraph;
}
/** Create a SizeAttribute for the current model when it is being saved to
* a file. The size recorded in the SizeAttribute is the size of the
* current canvas.
* @return The SizeAttribute.
* @exception IllegalActionException If "_vergilSize" is found but is not
* an instance of SizeAttribute, or if a SizeAttribute is not accepted by
* the current model.
* @exception NameDuplicationException If the name "_vergilSize" is already
* used when trying to create the SizeAttribute.
*/
protected SizeAttribute _createSizeAttribute()
throws IllegalActionException, NameDuplicationException {
// Have to also record the size of the JGraph because
// setting the size of the frame is ignored if we don't
// also set the size of the JGraph. Why? Who knows. Swing.
NamedObj model = getModel();
if (model != null) {
SizeAttribute size = (SizeAttribute) model.getAttribute(
"_vergilSize", SizeAttribute.class);
if (size == null) {
size = new SizeAttribute(getModel(), "_vergilSize");
}
size.recordSize(_getRightComponent());
return size;
}
return null;
}
/** Export the model into the writer with the given name. If
* the _query has a selected entry and it is true,
* then only the selected named objects are exported;
* otherwise, the whole model is exported with its exportMoML()
* method.
*
* @param writer The writer.
* @param model The model to export.
* @param name The name of the exported model.
* @exception IOException If an I/O error occurs.
*/
protected void _exportDesignPattern(Writer writer, NamedObj model,
String name) throws IOException {
if (_query != null && _query.hasEntry("selected")
&& _query.getBooleanValue("selected")) {
try {
model.workspace().getReadAccess();
String elementName = model.getElementName();
writer.write("\n"
+ "\n");
writer.write("<" + elementName + " name=\"" + name
+ "\" class=\"" + model.getClassName() + "\"");
if (model.getSource() != null) {
writer.write(" source=\"" + model.getSource() + "\">\n");
} else {
writer.write(">\n");
}
String[] attributeNames = { "_alternateGetMomlAction",
"_designPatternIcon", "_transformationBefore",
"_transformationAfter" };
for (String attributeName : attributeNames) {
Attribute attribute = model.getAttribute(attributeName);
if (attribute != null) {
attribute.exportMoML(writer, 1);
}
}
HashSet namedObjSet = _getSelectionSet();
NamedObj container = (NamedObj) _getGraphModel().getRoot();
Iterator elements = container.sortContainedObjects(
namedObjSet).iterator();
while (elements.hasNext()) {
elements.next().exportMoML(writer, 1);
}
if (model instanceof CompositeEntity) {
writer.write(((CompositeEntity) model).exportLinks(1,
namedObjSet));
}
writer.write("" + elementName + ">\n");
} finally {
model.workspace().doneReading();
}
} else {
if (model.getContainer() != null) {
writer.write("\n"
+ "\n");
}
model.exportMoML(writer, 0, name);
}
}
/** Finish exporting a design pattern.
*/
protected void _finishExportDesignPattern() {
}
/** Get the directory that was last accessed by this window.
* @see #_setDirectory
* @return The directory last accessed.
* @deprecated Use {@link #getLastDirectory()} instead
*/
@Deprecated
protected File _getDirectory() {
return _getCurrentDirectory();
}
/** Return the graph controller associated with this frame.
* @return The graph controller associated with this frame.
*/
protected GraphController _getGraphController() {
GraphPane graphPane = getJGraph().getGraphPane();
return graphPane.getGraphController();
}
/** Return the graph model associated with this frame.
* @return The graph model associated with this frame.
*/
protected AbstractBasicGraphModel _getGraphModel() {
GraphController controller = _getGraphController();
return (AbstractBasicGraphModel) controller.getGraphModel();
}
/** Return the right component on which graph editing occurs.
* @return The JGraph on which graph editing occurs.
*/
protected JComponent _getRightComponent() {
return _rightComponent;
}
/** Return a set of instances of NamedObj representing the objects
* that are currently selected. This set has no particular order
* to it. If you need the selection objects in proper order, as
* defined by the container, then call sortContainedObjects()
* on the container to sort the result.
* @return The set of selected objects.
*/
protected HashSet _getSelectionSet() {
GraphController controller = _getGraphController();
GraphModel graphModel = controller.getGraphModel();
SelectionModel model = controller.getSelectionModel();
Object[] selection = model.getSelectionAsArray();
// A set, because some objects may represent the same
// ptolemy object.
HashSet namedObjSet = new HashSet();
HashSet nodeSet = new HashSet();
// First get all the nodes.
for (Object element : selection) {
if (element instanceof Figure) {
Object userObject = ((Figure) element).getUserObject();
if (graphModel.isNode(userObject)) {
NamedObj actual = (NamedObj) graphModel
.getSemanticObject(userObject);
//System.out.println("BasicGraphFrame._getSelectionSet() actual: " + actual.getClass().getName());
//if ( !(actual instanceof PortParameter)) {
nodeSet.add(userObject);
namedObjSet.add(actual);
//}
}
}
}
for (Object element : selection) {
if (element instanceof Figure) {
Object userObject = ((Figure) element).getUserObject();
if (graphModel.isEdge(userObject)) {
// Check to see if the head and tail are both being
// copied. Only if so, do we actually take the edge.
Object head = graphModel.getHead(userObject);
Object tail = graphModel.getTail(userObject);
boolean headOK = nodeSet.contains(head);
boolean tailOK = nodeSet.contains(tail);
Iterator objects = nodeSet.iterator();
while (!(headOK && tailOK) && objects.hasNext()) {
Object object = objects.next();
if (!headOK
&& GraphUtilities.isContainedNode(head, object,
graphModel)) {
headOK = true;
}
if (!tailOK
&& GraphUtilities.isContainedNode(tail, object,
graphModel)) {
tailOK = true;
}
}
if (headOK && tailOK) {
// Add the relation.
NamedObj actual = (NamedObj) graphModel
.getSemanticObject(userObject);
namedObjSet.add(actual);
}
}
}
}
return namedObjSet;
}
/**
* Initialize this BasicGraphFrame.
* Derived classes may call this method in their constructors.
* Derived classes should call the various _initBasicGraphFrame*() methods
* so as to avoid code duplication
*/
protected void _initBasicGraphFrame() {
// WARNING: If you change this method, then Kepler will probably break.
// kepler/gui/src/org/kepler/gui/KeplerGraphFrame.java extends BasicGraphFrame
// and has an _initBasicGraphFrame() method.
// To build Kepler under Eclipse, see
// https://kepler-project.org/developers/reference/kepler-and-eclipse
// This method calls a series of other protected methods whose
// names start with _initBasicGraphFrame. These methods contain common
// functionality between this class and KeplerGraphFrame so
// that there is a chance that we avoid a ton of code
// duplication.
// Code that is different between this class and KeplerGraphFrame
// appears below.
// Eventually, perhaps the common functionality can be put into one
// method.
_initBasicGraphFrameInitialization();
ActionListener deletionListener = new DeletionListener();
_rightComponent.registerKeyboardAction(deletionListener, "Delete",
KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0),
JComponent.WHEN_IN_FOCUSED_WINDOW);
_rightComponent.registerKeyboardAction(deletionListener, "BackSpace",
KeyStroke.getKeyStroke(KeyEvent.VK_BACK_SPACE, 0),
JComponent.WHEN_IN_FOCUSED_WINDOW);
_initBasicGraphFrameRightComponent();
// Background color is parameterizable by preferences.
Configuration configuration = getConfiguration();
_rightComponent.setBackground(BACKGROUND_COLOR);
if (configuration != null) {
try {
PtolemyPreferences preferences = PtolemyPreferences
.getPtolemyPreferencesWithinConfiguration(configuration);
if (preferences != null) {
_rightComponent.setBackground(preferences.backgroundColor
.asColor());
}
} catch (IllegalActionException e1) {
// Ignore the exception and use the default color.
}
}
_initBasicGraphFrameRightComponentMouseListeners();
try {
// The SizeAttribute property is used to specify the size
// of the JGraph component. Unfortunately, with Swing's
// mysterious and undocumented handling of component sizes,
// there appears to be no way to control the size of the
// JGraph from the size of the Frame, which is specified
// by the WindowPropertiesAttribute.
SizeAttribute size = (SizeAttribute) getModel().getAttribute(
"_vergilSize", SizeAttribute.class);
if (size != null) {
size.setSize(_rightComponent);
} else {
// Set the default size.
// Note that the location is of the frame, while the size
// is of the scrollpane.
_rightComponent.setMinimumSize(new Dimension(200, 200));
_rightComponent.setPreferredSize(new Dimension(700, 500));
_rightComponent.setSize(600, 450);
}
_initBasicGraphFrameSetZoomAndPan();
} catch (Throwable throwable) {
// Ignore problems here. Errors simply result in a default
// size and location.
}
// If we don't have a library, we might be trying to only show
// models
// FIXME: should we be checking for _library instead?
if (configuration != null
&& (CompositeEntity) configuration.getEntity("actor library") != null) {
// Create the panner.
_graphPanner = new JCanvasPanner(getJGraph());
_graphPanner.setPreferredSize(new Dimension(200, 150));
// _graphPanner.setMaximumSize(new Dimension(200, 450));
_graphPanner.setSize(200, 150);
// NOTE: Border causes all kinds of problems!
_graphPanner.setBorder(BorderFactory.createEtchedBorder());
}
// Create the library of actors, or use the one in the entity,
// if there is one.
// FIXME: How do we make changes to the library persistent?
boolean gotLibrary = false;
try {
LibraryAttribute libraryAttribute = (LibraryAttribute) getModel()
.getAttribute("_library", LibraryAttribute.class);
if (libraryAttribute != null) {
// The model contains a library.
try {
_topLibrary = libraryAttribute.getLibrary();
if (_topLibrary != null) {
gotLibrary = true;
}
} catch (SecurityException ex) {
System.out.println("Warning: failed to parse "
+ "_library attribute (running in an applet "
+ "or sandbox always causes this)");
}
}
} catch (Exception ex) {
try {
MessageHandler.warning("Invalid library in the model.", ex);
} catch (CancelException e) {
}
}
if (!gotLibrary) {
try {
if (_defaultLibrary != null) {
// A default library has been specified.
_topLibrary = _defaultLibrary.getLibrary();
gotLibrary = true;
}
} catch (SecurityException ex) {
// Ignore, we are in an applet or sandbox.
// We already printed a message, why print it again?
} catch (Exception ex) {
try {
// FIXME: It seems wrong to call MessageHandler here,
// instead, we should throw an IllegalActionException?
MessageHandler.warning(
"Invalid default library for the frame.", ex);
} catch (CancelException e) {
}
}
}
if (!gotLibrary) {
// Neither the model nor the argument have specified a library.
// See if there is a default library in the configuration.
_topLibrary = _createDefaultLibrary(getModel().workspace());
}
// Only include the palettePane and panner if there is an actor library.
// The ptinyViewer configuration uses this.
if (configuration != null
&& (CompositeEntity) configuration.getEntity("actor library") != null) {
_libraryModel = new VisibleTreeModel(_topLibrary);
// Second arguments prevents parameter values from showing in the library.
_library = new PTree(_libraryModel, false);
_library.setRootVisible(false);
_library.setBackground(BACKGROUND_COLOR);
// If you want to expand the top-level libraries, uncomment this.
// Object[] path = new Object[2];
// path[0] = _topLibrary;
// Iterator libraries = _topLibrary.entityList().iterator();
// while (libraries.hasNext()) {
// path[1] = libraries.next();
// _library.expandPath(new javax.swing.tree.TreePath(path));
// }
_libraryContextMenuCreator = new PTreeMenuCreator();
_libraryContextMenuCreator
.addMenuItemFactory(new OpenLibraryMenuItemFactory());
_libraryContextMenuCreator
.addMenuItemFactory(new DocumentationMenuItemFactory());
_library.addMouseListener(_libraryContextMenuCreator);
_libraryScrollPane = new JScrollPane(_library);
// See _treeViewScrollPane below.
_libraryScrollPane.setMinimumSize(new Dimension(200, 200));
_libraryScrollPane.setPreferredSize(new Dimension(200, 300));
// create the palette on the left.
_palettePane = new JPanel();
_palettePane.setBorder(null);
_palettePane.setLayout(new GridBagLayout());
// create a query for search.
JPanel findPanel = new JPanel(new GridBagLayout());
// Put in the label.
GridBagConstraints labelConstraints = new GridBagConstraints();
labelConstraints.gridx = 0;
labelConstraints.gridy = 0;
JLabel label = new JLabel("Find:");
findPanel.add(label, labelConstraints);
// Put in the entry box.
_findInLibraryEntryBox = new JTextField(12);
_findInLibraryEntryBox.addActionListener(new FindInLibraryAction());
GridBagConstraints entryBoxConstraints = new GridBagConstraints();
entryBoxConstraints.gridx = 1;
entryBoxConstraints.gridy = 0;
entryBoxConstraints.fill = GridBagConstraints.HORIZONTAL;
entryBoxConstraints.weightx = 1.0;
findPanel.add(_findInLibraryEntryBox, entryBoxConstraints);
// Put in the find panel.
GridBagConstraints findPanelConstraints = new GridBagConstraints();
findPanelConstraints.gridx = 0;
findPanelConstraints.gridy = 0;
findPanelConstraints.fill = GridBagConstraints.HORIZONTAL;
_palettePane.add(findPanel, findPanelConstraints);
// The Hierarchy Tree browser for CompositeEntities.
NamedObj model = getModel();
if (!(model instanceof CompositeEntity)) {
// EditIconFrame will have a EditorIcon as a model, not a CompositeEntity.
_treeViewScrollPane = null;
} else {
_treeViewModel = new ClassAndEntityTreeModel(
getModel().toplevel());
// Second arguments prevents parameter values from showing in the library,
// I'm not sure if that is relevant for the hierarchy tree browser.
_treeView = new PTree(_treeViewModel, false);
// Replaced by mouse listener.
// _treeView.addTreeSelectionListener(new HierarchyTreeSelectionListener());
_treeView.addMouseListener(new HierarchyTreeMouseAdapter());
_treeView.setBackground(BACKGROUND_COLOR);
_treeView.setCellRenderer(new HierarchyTreeCellRenderer());
_treeViewScrollPane = new JScrollPane(_treeView);
// See _libraryScrollPane above.
_treeViewScrollPane.setMinimumSize(new Dimension(200, 200));
_treeViewScrollPane.setPreferredSize(new Dimension(200, 300));
// Make the Ptolemy model visible in the tree.
TreePath modelTreePath = null;
{
// Traverse the Ptolemy model hierarchy, create a list, reverse it,
// create an array and then a TreePath.
List compositeList = new LinkedList();
NamedObj composite = getModel();
while (composite != null) {
compositeList.add(composite);
composite = composite.getContainer();
}
java.util.Collections.reverse(compositeList);
Object[] composites = compositeList.toArray();
modelTreePath = new TreePath(composites);
}
_treeView.expandPath(modelTreePath);
_treeView.makeVisible(modelTreePath);
_treeView.scrollPathToVisible(modelTreePath);
}
// Put in the tabbed pane that contains the hierarchy browser and the library
JTabbedPane libraryTreeTabbedPane = new JTabbedPane();
libraryTreeTabbedPane.add("Library", _libraryScrollPane);
if (_treeViewScrollPane != null) {
libraryTreeTabbedPane.add("Tree", _treeViewScrollPane);
}
GridBagConstraints tabbedPaneConstraints = new GridBagConstraints();
tabbedPaneConstraints.gridx = 0;
tabbedPaneConstraints.gridy = 1;
tabbedPaneConstraints.fill = GridBagConstraints.BOTH;
tabbedPaneConstraints.weightx = 1.0;
tabbedPaneConstraints.weighty = 0.7;
_palettePane.add(libraryTreeTabbedPane, tabbedPaneConstraints);
// Add the graph panner.
if (_graphPanner != null) {
GridBagConstraints pannerConstraints = new GridBagConstraints();
pannerConstraints.gridx = 0;
pannerConstraints.gridy = 2;
pannerConstraints.weighty = 0.3;
pannerConstraints.fill = GridBagConstraints.BOTH;
_palettePane.add(_graphPanner, pannerConstraints);
}
_splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true);
_splitPane.setLeftComponent(_palettePane);
_splitPane.setRightComponent(_rightComponent);
getContentPane().add(_splitPane, BorderLayout.CENTER);
} else {
getContentPane().add(_rightComponent, BorderLayout.CENTER);
}
_toolbar = new JToolBar();
_toolbar.setLayout(new FlowLayout(FlowLayout.LEADING, 0, 0));
try {
new ToolBar(getTableau(), "toolbar", _toolbar, BorderLayout.NORTH);
} catch (Exception e) {
throw new InternalErrorException(getTableau(), e,
"Unable to create tool bar.");
}
GUIUtilities.addToolBarButton(_toolbar, _saveAction);
// Note that in Top we disable Print unless the class implements
// the Printable or Pageable interfaces. By definition, this class
// implements the Printable interface
GUIUtilities.addToolBarButton(_toolbar, _printAction);
_initBasicGraphFrameToolBarZoomButtons();
GUIUtilities.addToolBarButton(_toolbar, _openContainerAction);
if (getModel() == getModel().toplevel()
|| getModel().getClass().getName()
.equals("ptolemy.domains.modal.modal.ModalController")) {
// If we are at the top level, disable. If we are in a
// ModalModel, disable. See "Up button does not work in
// modal models"
// https://chess.eecs.berkeley.edu/bugzilla/show_bug.cgi?id=323
_openContainerAction.setEnabled(false);
}
_initBasicGraphFrameActions();
// Add a weak reference to this to keep track of all
// the graph frames that have been created.
_openGraphFrames.add(this);
}
/** Add the cut, copy, paste, move to front, mode to back
* actions. Also add the EditPreferencesAction and initialize
* the layout gui.
* Derived classes usually call this at the end of
* _initBasicGraphFrame().
*/
protected void _initBasicGraphFrameActions() {
_cutAction = new CutAction();
_copyAction = new CopyAction();
_pasteAction = new PasteAction();
_findAction = new FindAction();
// FIXME: vergil.kernel.AttributeController also defines context
// menu choices that do the same thing.
_moveToFrontAction = new MoveToFrontAction();
_moveToBackAction = new MoveToBackAction();
_editPreferencesAction = new EditPreferencesAction();
_initLayoutGuiAction();
}
/** Set up the right component. */
protected void _initBasicGraphFrameRightComponent() {
_rightComponent.setRequestFocusEnabled(true);
_rightComponent.setAlignmentX(1);
_rightComponent.setAlignmentY(1);
}
/** Add listeners to the right component. */
protected void _initBasicGraphFrameRightComponentMouseListeners() {
_rightComponent.addMouseWheelListener(this);
_rightComponent.addMouseMotionListener(this);
_rightComponent.addMouseListener(this);
}
/** Common initialization for a BasicGraphFrame.
* Derived classes should call this method early in
* _initBasicGraphFrame().
*/
protected void _initBasicGraphFrameInitialization() {
getModel().addChangeListener(this);
getContentPane().setLayout(new BorderLayout());
_rightComponent = _createRightComponent(getModel());
}
/** Add tool bar buttons.
* Derived classes should set _toolbar before calling
* this method.
*/
protected void _initBasicGraphFrameToolBarZoomButtons() {
GUIUtilities.addToolBarButton(_toolbar, _zoomInAction);
GUIUtilities.addToolBarButton(_toolbar, _zoomResetAction);
GUIUtilities.addToolBarButton(_toolbar, _zoomFitAction);
GUIUtilities.addToolBarButton(_toolbar, _zoomOutAction);
}
/** Set the zoom factor and the pan.
* @exception IllegalActionException If the zoom or pan parameters
* cannot be read.
*/
protected void _initBasicGraphFrameSetZoomAndPan()
throws IllegalActionException {
// Set the zoom factor.
Parameter zoom = (Parameter) getModel().getAttribute(
"_vergilZoomFactor", Parameter.class);
if (zoom != null) {
zoom(((DoubleToken) zoom.getToken()).doubleValue());
// Make sure the visibility is only expert.
zoom.setVisibility(Settable.EXPERT);
}
// Set the pan position.
Parameter pan = (Parameter) getModel().getAttribute("_vergilCenter",
Parameter.class);
if (pan != null) {
ArrayToken panToken = (ArrayToken) pan.getToken();
Point2D center = new Point2D.Double(
((DoubleToken) panToken.getElement(0)).doubleValue(),
((DoubleToken) panToken.getElement(1)).doubleValue());
setCenter(center);
// Make sure the visibility is only expert.
pan.setVisibility(Settable.EXPERT);
}
// If we have neither zooming or panning info...
if (zoom == null && pan == null) {
// ...set the top left corner of the view to the top left corner of the model.
// Note: This code only works for a zoom factor of 1.0, which is no problem at
// this stage since that's the default and no zooming info was found in the model.
GraphPane pane = getJGraph().getGraphPane();
Rectangle2D bounds = pane.getForegroundLayer().getLayerBounds();
Rectangle2D visible = getVisibleRectangle();
double centerX = visible.getCenterX()
- (visible.getX() - bounds.getX());
double centerY = visible.getCenterY()
- (visible.getY() - bounds.getY());
// Set the new center point, but add a little free space between model and border
setCenter(new Point2D.Double(centerX - 10.0, centerY - 10.0));
}
}
/** Initialize the layout gui. */
protected void _initLayoutGuiAction() {
// Try to create an advanced layout action.
final IGuiAction layoutGuiAction = _createLayoutAction();
if (layoutGuiAction != null) {
_layoutAction = new AbstractAction("Automatic Layout") {
@Override
public void actionPerformed(ActionEvent e) {
layoutGuiAction.doAction(getModel());
}
};
// The advanced layout action is available, so create the configuration
// dialog for displaying layout parameters.
_layoutConfigDialogAction = new LayoutConfigDialogAction();
} else {
// The advanced layout action is not available, so use the simple
// Ptolemy layout algorithm.
_layoutAction = new AbstractAction("Automatic Layout") {
@Override
public void actionPerformed(ActionEvent e) {
new PtolemyLayoutAction().doAction(getModel());
}
};
}
_layoutAction.putValue("tooltip", "Layout the graph (Ctrl+T)");
_layoutAction.putValue(GUIUtilities.ACCELERATOR_KEY, KeyStroke
.getKeyStroke(KeyEvent.VK_T, Toolkit.getDefaultToolkit()
.getMenuShortcutKeyMask()));
_layoutAction.putValue(GUIUtilities.MNEMONIC_KEY,
Integer.valueOf(KeyEvent.VK_L));
}
/** Return true if this is a design pattern.
* @return true if the model corresponding to this object
* has a DesignPatternIcon attribute.
*/
protected boolean _isDesignPattern() {
NamedObj model = getModel();
return !model.attributeList(DesignPatternIcon.class).isEmpty();
}
/** Prepare to export a design pattern.
* In this base class, do nothing.
*/
protected void _prepareExportDesignPattern() {
}
/** Create and return a file dialog for the "Save As" command.
* This overrides the base class so that if this is a design pattern
* and items are selected, then the user is asked if they
* want to save only the selected objects.
* If {@link ptolemy.gui.PtGUIUtilities#useFileDialog()} returns true
* then {@link ptolemy.gui.Top#_saveAs()} uses this method. Otherwise,
* {@link #_saveAsJFileChooserComponent()} is used.
* @return A file dialog for save as.
*/
@Override
protected FileDialog _saveAsFileDialogComponent() {
FileDialog fileDialog = super._saveAsFileDialogComponent();
if (_isDesignPattern()) {
if (!_getSelectionSet().isEmpty()) {
// FIXME: It is not clear to me when this code would be called.
// File -> New -> Ptera Model, then opening DesignPatterns,
// dragging in a ListenToInput, selecting it and doing Save As
// does not do it.
_query = new Query();
_query.addCheckBox("selected", "Selected objects only", true);
// The problem here is that with FileDialog, we can't add the
// query as an accessory like we can with JFileChooser. So, we
// pop up a check box dialog before bringing up the FileDialog.
new ComponentDialog(this, "Save submodel only?", _query);
}
}
return fileDialog;
}
/** Create and return a file dialog for the "Save As" command.
* This overrides the base class so that if this is a design pattern
* and items are selected, then the user is asked if they
* want to save only the selected objects.
* If {@link ptolemy.gui.PtGUIUtilities#useFileDialog()} returns false
* then {@link ptolemy.gui.Top#_saveAs()} uses this method. Otherwise,
* {@link #_saveAsFileDialogComponent()} is used.
* @return A file dialog for save as.
*/
@Override
protected JFileChooser _saveAsJFileChooserComponent() {
JFileChooser fileChooser = super._saveAsJFileChooserComponent();
if (_isDesignPattern()) {
if (_getSelectionSet().isEmpty()) {
fileChooser.setAccessory(null);
} else {
_query = new Query();
_query.addCheckBox("selected", "Selected objects only", true);
fileChooser.setAccessory(_query);
}
}
return fileChooser;
}
/** Set the directory that was last accessed by this window.
* @see #getLastDirectory
* @param directory The directory last accessed.
* @deprecated Use {@link #setDirectory(File)} instead
*/
@Deprecated
protected void _setDirectory(File directory) {
setDirectory(directory);
}
/** Enable or disable drop into.
* @param enable False to disable.
*/
protected void _setDropIntoEnabled(boolean enable) {
_dropTarget.setDropIntoEnabled(enable);
}
/** Write the model to the specified file. This overrides the base
* class to record the current size and position of the window
* in the model.
* @param file The file to write to.
* @exception IOException If the write fails.
*/
@Override
protected void _writeFile(File file) throws IOException {
try {
updateWindowAttributes();
} catch (KernelException ex) {
// Ignore problems here. Errors simply result in a
// default size and location.
System.out
.println("While writing, failed to save size, position or zoom factor: "
+ ex);
}
if (_isDesignPattern()) {
FileWriter fileWriter = null;
try {
fileWriter = new FileWriter(file);
String name = getModel().getName();
String filename = file.getName();
int period = filename.indexOf(".");
if (period > 0) {
name = filename.substring(0, period);
} else {
name = filename;
}
_exportDesignPattern(fileWriter, getModel(), name);
} finally {
if (fileWriter != null) {
fileWriter.close();
}
}
} else {
super._writeFile(file);
}
}
/** Return the MoML to delete the specified selection objects.
* This has the side effect of unselecting the objects. It also
* deletes edges that are not fully connected (these deletions
* cannot be done through MoML, and cannot be undone).
* @param graphModel The graph model.
* @param selection The selection.
* @param model The selection model.
* @return The MoML to delete the selected objects.
*/
protected StringBuffer _deleteMoML(AbstractBasicGraphModel graphModel,
Object[] selection, SelectionModel model) {
// First collect selected objects into the userObjects array
// and deselect them.
Object[] userObjects = new Object[selection.length];
for (int i = 0; i < selection.length; i++) {
userObjects[i] = ((Figure) selection[i]).getUserObject();
model.removeSelection(selection[i]);
}
// Create a set to hold those elements whose deletion
// does not go through MoML. This is only links that
// are not connected to another port or a relation.
HashSet edgeSet = new HashSet();
StringBuffer moml = new StringBuffer("\n");
// Delete edges then nodes, since deleting relations may
// result in deleting links to that relation.
for (int i = 0; i < selection.length; i++) {
Object userObject = userObjects[i];
if (graphModel.isEdge(userObject)) {
NamedObj actual = (NamedObj) graphModel
.getSemanticObject(userObject);
// If there is no semantic object, then this edge is
// not fully connected, so we can't go through MoML.
if (actual == null) {
edgeSet.add(userObject);
} else {
moml.append(graphModel.getDeleteEdgeMoML(userObject));
}
}
}
// First, delete all the non-attributes.
// This helps avoid deleting properties such as top level parameters
// upon which the entities depend.
// FIXME: what if we have a parameter that is used by both the selection
// and the other parts of the model?
for (int i = 0; i < selection.length; i++) {
Object userObject = userObjects[i];
NamedObjNodeModel namedObjNodeModel = (NamedObjNodeModel) graphModel
.getNodeModel(userObject);
if (graphModel.isNode(userObject)
&& !(namedObjNodeModel instanceof AttributeNodeModel)) {
NamedObj actual = (NamedObj) graphModel
.getSemanticObject(userObject);
if (!(actual instanceof ParameterPort)) {
// We don't delete ParameterPorts here because if
// we drag a region around a ParmeterPort, then
// both the PortParameter and the ParameterPort
// are selected. Deleting both results in an
// error. If we just click (not drag) on a
// ParameterPort, then the PortParameter is only
// selected and deletion work ok. See
// https://chess.eecs.berkeley.edu/bugzilla/show_bug.cgi?id=311
moml.append(graphModel.getDeleteNodeMoML(userObject));
}
}
}
// Now delete attributes.
for (int i = 0; i < selection.length; i++) {
Object userObject = userObjects[i];
NamedObjNodeModel namedObjNodeModel = (NamedObjNodeModel) graphModel
.getNodeModel(userObject);
if (graphModel.isNode(userObject)
&& namedObjNodeModel instanceof AttributeNodeModel) {
moml.append(graphModel.getDeleteNodeMoML(userObject));
}
}
moml.append(" \n");
// Have both MoML to perform deletion and set of objects whose
// deletion does not go through MoML. This set of objects
// should be very small and so far consists of only links that are not
// connected to a relation
try {
// First manually delete any objects whose deletion does not go
// through MoML and so are not undoable
// Note that we turn off event dispatching so that each individual
// removal does not trigger graph redrawing.
graphModel.setDispatchEnabled(false);
Iterator edges = edgeSet.iterator();
while (edges.hasNext()) {
Object nextEdge = edges.next();
if (graphModel.isEdge(nextEdge)) {
graphModel.disconnectEdge(this, nextEdge);
}
}
} finally {
graphModel.setDispatchEnabled(true);
}
return moml;
}
///////////////////////////////////////////////////////////////////
//// protected variables ////
/** The copy action. */
protected Action _copyAction;
/** The cut action. */
protected Action _cutAction;
/** The default Library. **/
protected LibraryAttribute _defaultLibrary;
/** The instance of EditorDropTarget associated with the JGraph. */
protected EditorDropTarget _dropTarget;
/** The edit menu. */
protected JMenu _editMenu;
/** The action to edit preferences. */
protected EditPreferencesAction _editPreferencesAction;
/** The export to GIF action. */
protected Action _exportGIFAction;
/** The export HTML action. */
protected Action _exportHTMLAction;
/** The export to PDF action. */
protected Action _exportPDFAction;
/** The export to PNG action. */
protected Action _exportPNGAction;
/** The find action. */
protected Action _findAction;
/** The graph menu. */
protected JMenu _graphMenu;
/** The panner. Note that this variable
* can be null if the configuration does not have an entity named
* "actor library". For example, see $PTII/bin/vergil -ptinyViewer.
*/
protected JCanvasPanner _graphPanner;
/** The instance of JGraph for this editor. */
protected JGraph _jgraph;
/** The action for automatically laying out the graph.
* This can be either an advanced layout or the simple Ptolemy layout,
* depending on whether the better one is available.
*/
protected Action _layoutAction;
/** The action for opening the layout configuration dialog.
* This reference can be {@code null}, since the dialog is only supported
* if advanced layout is available. In this case the action should not
* be shown in menus.
*/
protected Action _layoutConfigDialogAction;
/** The library display widget. */
protected JTree _library;
/** The library context menu creator. */
protected PTreeMenuCreator _libraryContextMenuCreator;
/** The library model. */
protected EntityTreeModel _libraryModel;
/** The library scroll pane. */
protected JScrollPane _libraryScrollPane;
/** Action to move to the back. */
protected MoveToBackAction _moveToBackAction;
/** Action to move to the front. */
protected MoveToFrontAction _moveToFrontAction;
/** List of references to graph frames that are open. */
protected static LinkedList _openGraphFrames = new LinkedList();
/** The library display panel. */
protected JPanel _palettePane;
/** The paste action. */
protected Action _pasteAction;
/** The right component for this editor. */
protected JComponent _rightComponent;
/** The split pane for library and editor. Note that this variable
* can be null if the configuration does not have an entity named
* "actor library". For example, see $PTII/bin/vergil -ptinyViewer.
*/
protected JSplitPane _splitPane;
/** The toolbar. */
protected JToolBar _toolbar;
/** The library. */
protected CompositeEntity _topLibrary;
/** The tree view of the model, used for browsing large models. */
protected PTree _treeView;
/** The tree view scroll pane. */
protected JScrollPane _treeViewScrollPane;
/** The tree view model. */
protected ClassAndEntityTreeModel _treeViewModel;
/** Action for zoom fitting. */
protected Action _zoomFitAction = new ZoomFitAction("Zoom Fit");
/** Action for zooming in. */
protected Action _zoomInAction = new ZoomInAction("Zoom In");
/** Action for zooming out. */
protected Action _zoomOutAction = new ZoomOutAction("Zoom Out");
/** Action for zoom reset. */
protected Action _zoomResetAction = new ZoomResetAction("Zoom Reset");
/** True if we are inside zoom(). Used by derived classes with scrollbars.
*/
protected boolean _zoomFlag = false;
///////////////////////////////////////////////////////////////////
//// private methods ////
/**
* Create an action for advanced automatic layout, if possible.
*
* @return a layout action, or null if it cannot be created
*/
private IGuiAction _createLayoutAction() {
try {
StringParameter layoutGraphActionParameter = (StringParameter) getConfiguration()
.getAttribute("_layoutGraphAction", StringParameter.class);
if (layoutGraphActionParameter != null) {
// Try to find the class given in the configuration.
Class layoutGraphActionClass = Class
.forName(layoutGraphActionParameter.stringValue());
// Try to create an instance using the default constructor.
Object object = layoutGraphActionClass.getDeclaredConstructor()
.newInstance();
if (object instanceof IGuiAction) {
// If the action is a filter and the model is set, ask the action
// whether is supports the model.
if (object instanceof Filter && getModel() != null) {
if (!((Filter) object).accept(getModel())) {
return null;
}
}
return (IGuiAction) object;
}
}
} catch (Throwable throwable) {
// Fail silently!
}
return null;
}
///////////////////////////////////////////////////////////////////
//// private variables ////
/** The entry box for find in library. */
JTextField _findInLibraryEntryBox;
/** A layer adapter to handle the mousePressed event. */
private MousePressedLayerAdapter _mousePressedLayerAdapter;
/** Action for opening the container, moving uplevel. */
private Action _openContainerAction = new OpenContainerAction(
"Open the container");
/** X coordinate of where we last processed a press or drag of the
* middle mouse button.
*/
private int _previousMouseX = 0;
/** Y coordinate of where we last processed a press or drag of the
* middle mouse button.
*/
private int _previousMouseY = 0;
/** Action to print the model. */
private Action _printAction = new PrintAction("Print");
/** True if the message about problems reading
* _importActionClassNames has been printed.
*/
private static boolean _printedImportActionClassNamesMessage = false;
/** Action to redo the last undone MoML change. */
private Action _redoAction = new RedoAction();
/** Action to save the model. */
private Action _saveAction = new SaveAction("Save");
/** Action to undo the last MoML change. */
private Action _undoAction = new UndoAction();
private static double _ZOOM_FIT_PADDING = 5.0;
///////////////////////////////////////////////////////////////////
//// inner classes ////
/** A Layer Adapter to handle the mousePressed layer event. */
protected static class MousePressedLayerAdapter extends LayerAdapter {
// FindBugs indicates that this should be a static class.
/** Invoked when the mouse is pressed on a layer
* or figure.
*/
@Override
public void mousePressed(LayerEvent event) {
Component component = event.getComponent();
if (!component.hasFocus()) {
component.requestFocus();
}
}
}
///////////////////////////////////////////////////////////////////
//// CopyAction
/** Action to copy the current selection. */
protected class CopyAction extends AbstractAction {
/** Create a new action to copy the current selection. */
public CopyAction() {
super("Copy");
putValue("tooltip",
"Copy the current selection onto the clipboard.");
putValue(GUIUtilities.ACCELERATOR_KEY, KeyStroke.getKeyStroke(
KeyEvent.VK_C, Toolkit.getDefaultToolkit()
.getMenuShortcutKeyMask()));
putValue(GUIUtilities.MNEMONIC_KEY, Integer.valueOf(KeyEvent.VK_C));
}
/** Copy the current selection. */
@Override
public void actionPerformed(ActionEvent e) {
copy();
}
}
///////////////////////////////////////////////////////////////////
//// CutAction
/** Action to copy and delete the current selection. */
protected class CutAction extends AbstractAction {
/** Create a new action to copy and delete the current selection. */
public CutAction() {
super("Cut");
putValue("tooltip", "Cut the current selection onto the clipboard.");
putValue(GUIUtilities.ACCELERATOR_KEY, KeyStroke.getKeyStroke(
KeyEvent.VK_X, Toolkit.getDefaultToolkit()
.getMenuShortcutKeyMask()));
putValue(GUIUtilities.MNEMONIC_KEY, Integer.valueOf(KeyEvent.VK_T));
}
/** Copy and delete the current selection. */
@Override
public void actionPerformed(ActionEvent e) {
cut();
}
}
///////////////////////////////////////////////////////////////////
//// DeletionListener
/** An ActionListener for handling deletion events. */
private class DeletionListener implements ActionListener {
/** Delete any nodes or edges from the graph that are
* currently selected. In addition, delete any edges
* that are connected to any deleted nodes.
*/
@Override
public void actionPerformed(ActionEvent e) {
delete();
}
}
///////////////////////////////////////////////////////////////////
//// DocumentationMenuItemFactory
/**
* Create a menu item that will show documentation
*/
private class DocumentationMenuItemFactory implements MenuItemFactory {
/**
* Add an item to the given context menu that bring up the
* documentation for the given object
*/
@Override
public JMenuItem create(final JContextMenu menu, final NamedObj object) {
Action action = new GetDocumentationAction() {
@Override
public void actionPerformed(ActionEvent e) {
Configuration configuration = getConfiguration();
setConfiguration(configuration);
super.actionPerformed(e);
}
};
action.putValue("tooltip", "Get Documentation.");
action.putValue(diva.gui.GUIUtilities.MNEMONIC_KEY,
Integer.valueOf(KeyEvent.VK_D));
return menu.add(action, (String) action.getValue(Action.NAME));
}
}
///////////////////////////////////////////////////////////////////
//// EditPreferencesAction
/** Action to edit the preferences.
*/
protected class EditPreferencesAction extends AbstractAction {
public EditPreferencesAction() {
super("Edit Preferences");
putValue("tooltip", "Change the Vergil preferences");
putValue(GUIUtilities.MNEMONIC_KEY, Integer.valueOf(KeyEvent.VK_E));
}
@Override
public void actionPerformed(ActionEvent e) {
Configuration configuration = getConfiguration();
PtolemyPreferences preferences = null;
try {
preferences = (PtolemyPreferences) configuration.getAttribute(
PtolemyPreferences.PREFERENCES_WITHIN_CONFIGURATION,
PtolemyPreferences.class);
} catch (IllegalActionException ex) {
MessageHandler.error("Preferences attribute found, "
+ "but not of the right class.", ex);
}
if (preferences == null) {
MessageHandler
.message("No preferences given in the configuration.");
} else {
// Open a modal dialog to edit the parameters.
new EditParametersDialog(BasicGraphFrame.this, preferences,
"Edit Ptolemy Preferences");
// Make the current global variables conform with the
// new values.
try {
preferences.setAsDefault();
} catch (IllegalActionException ex) {
MessageHandler.error("Invalid expression.", ex);
actionPerformed(e);
}
// If any parameter has changed, all open vergil
// windows need to be notified.
Iterator frames = _openGraphFrames.iterator();
while (frames.hasNext()) {
BasicGraphFrame frame = frames.next();
GraphModel graphModel = frame._getGraphController()
.getGraphModel();
graphModel
.dispatchGraphEvent(new GraphEvent(this,
GraphEvent.STRUCTURE_CHANGED, graphModel
.getRoot()));
if (frame._graphPanner != null) {
frame._graphPanner.repaint();
}
}
// Make the changes persistent.
try {
preferences.save();
} catch (IOException ex) {
try {
MessageHandler.warning("Failed to save preferences.",
ex);
} catch (CancelException e1) {
// Ignore cancel.
}
}
}
}
}
///////////////////////////////////////////////////////////////////
//// ElementInLinkType
/**
* An enumerate to specifies what kind of element the element (head or tail) is in a link.
*/
private enum ElementInLinkType {
PORT_IN_ACTOR, STANDALONE_PORT, RELATION
}
///////////////////////////////////////////////////////////////////
//// ExecuteSystemAction
/** An action to open a run control window. */
// private class ExecuteSystemAction extends AbstractAction {
// /** Construct an action to execute the model. */
// public ExecuteSystemAction() {
// super("Go");
// putValue("tooltip", "Execute The Model");
// putValue(GUIUtilities.ACCELERATOR_KEY, KeyStroke.getKeyStroke(
// KeyEvent.VK_G, Toolkit.getDefaultToolkit()
// .getMenuShortcutKeyMask()));
// putValue(GUIUtilities.MNEMONIC_KEY, Integer.valueOf(KeyEvent.VK_G));
// }
//
// /** Open a run control window. */
// public void actionPerformed(ActionEvent e) {
// try {
// PtolemyEffigy effigy = (PtolemyEffigy) getTableau()
// .getContainer();
// new RunTableau(effigy, effigy.uniqueName("tableau"));
// } catch (Exception ex) {
// MessageHandler.error("Execution Failed", ex);
// }
// }
// }
///////////////////////////////////////////////////////////////////
//// ExportImageAction
/** Export an image of the model. */
public class ExportImageAction extends AbstractAction {
/** Create a new action to export an image.
* @param formatName The image format to be exported,
* currently, "GIF" and "PNG" are supported.
*/
public ExportImageAction(String formatName) {
super("Export " + formatName);
_formatName = formatName.toLowerCase(Locale.getDefault());
putValue("tooltip", "Export " + formatName + " image to a file.");
// putValue(GUIUtilities.MNEMONIC_KEY, Integer.valueOf(KeyEvent.VK_G));
}
///////////////////////////////////////////////////////////////////
//// public methods ////
/** Export an image.
*
* Under Mac OS X, use java.awt.FileDialog.
* Under other OS's, use javax.swing.JFileChooser. Under Mac OS
* X, see {@link ptolemy.gui.PtGUIUtilities#useFileDialog()} for
* how to select between the two.
*
* @param e The event that triggered this action.
*/
@Override
public void actionPerformed(ActionEvent e) {
JFileChooserBugFix jFileChooserBugFix = new JFileChooserBugFix();
Color background = null;
PtFileChooser ptFileChooser = null;
try {
background = jFileChooserBugFix.saveBackground();
ptFileChooser = new PtFileChooser(BasicGraphFrame.this,
"Specify a " + _formatName + " file to be written.",
JFileChooser.SAVE_DIALOG);
ptFileChooser.setSelectedFile(new File(getModel().getName()
+ "." + _formatName));
LinkedList extensions = new LinkedList();
extensions.add(_formatName);
ptFileChooser
.addChoosableFileFilter(new ExtensionFilenameFilter(
extensions));
ptFileChooser.setCurrentDirectory(_directory);
int returnVal = ptFileChooser.showDialog(
BasicGraphFrame.this,
"Export "
+ _formatName.toUpperCase(Locale.getDefault()));
if (returnVal == JFileChooser.APPROVE_OPTION) {
_directory = ptFileChooser.getCurrentDirectory();
File imageFile = ptFileChooser.getSelectedFile()
.getCanonicalFile();
if (imageFile.getName().indexOf(".") == -1) {
// If the user has not given the file an extension, add it
imageFile = new File(imageFile.getAbsolutePath() + "."
+ _formatName);
}
// The Mac OS X FileDialog will ask if we want to save before this point.
if (imageFile.exists() && !PtGUIUtilities.useFileDialog()) {
if (!MessageHandler.yesNoQuestion("Overwrite \""
+ imageFile.getName() + "\"?")) {
return;
}
}
OutputStream out = null;
try {
out = new FileOutputStream(imageFile);
getJGraph().exportImage(out, _formatName);
} finally {
if (out != null) {
out.close();
}
}
// Open the image file.
if (MessageHandler
.yesNoQuestion("Open \""
+ imageFile.getCanonicalPath()
+ "\" in a browser?")) {
Configuration configuration = getConfiguration();
try {
URL imageURL = new URL(imageFile.toURI().toURL()
.toString()
+ "#in_browser");
configuration.openModel(imageURL, imageURL,
imageURL.toExternalForm(),
BrowserEffigy.staticFactory);
} catch (Throwable throwable) {
MessageHandler.error("Failed to open \""
+ imageFile.getName() + "\".", throwable);
}
}
}
} catch (Exception ex) {
MessageHandler.error(
"Export to "
+ _formatName.toUpperCase(Locale.getDefault())
+ " failed", ex);
} finally {
jFileChooserBugFix.restoreBackground(background);
}
}
private String _formatName;
}
///////////////////////////////////////////////////////////////////
//// ExportMapAction
/** Accept only folders in a file browser. */
static public class FolderFileFilter extends FileFilter {
/** Accept only folders.
* @param fileOrDirectory The file or directory to be checked.
* @return true if the file is a directory.
*/
@Override
public boolean accept(File fileOrDirectory) {
if (fileOrDirectory.isDirectory()) {
return true;
}
return false;
}
/** The description of this filter. */
@Override
public String getDescription() {
return "Choose a Folder";
}
}
///////////////////////////////////////////////////////////////////
//// FindAction
/** Action to search for text in a model. */
protected class FindAction extends AbstractAction {
/** Create a new action to search for text. */
public FindAction() {
super("Find");
putValue("tooltip", "Find occurrences of specified text.");
putValue(GUIUtilities.ACCELERATOR_KEY, KeyStroke.getKeyStroke(
KeyEvent.VK_F, Toolkit.getDefaultToolkit()
.getMenuShortcutKeyMask()));
putValue(GUIUtilities.MNEMONIC_KEY, Integer.valueOf(KeyEvent.VK_F));
}
/** Open a dialog to find the specified text. */
@Override
public void actionPerformed(ActionEvent e) {
DialogTableau dialogTableau = DialogTableau.createDialog(
BasicGraphFrame.this, getConfiguration(), getEffigy(),
SearchResultsDialog.class, (Entity) getModel());
if (dialogTableau != null) {
dialogTableau.show();
}
}
}
///////////////////////////////////////////////////////////////////
//// FindInLibraryAction
/** An ActionListener for handling deletion events. */
private class FindInLibraryAction implements ActionListener {
/** Delete any nodes or edges from the graph that are
* currently selected. In addition, delete any edges
* that are connected to any deleted nodes.
*/
@Override
public void actionPerformed(ActionEvent e) {
_library.clearSelection();
String text = _findInLibraryEntryBox.getText().trim()
.toLowerCase(Locale.getDefault());
if (text.equals("")) {
// Nothing to search for. Ignore.
_previousText = null;
return;
}
NamedObj root = (NamedObj) _libraryModel.getRoot();
if (!text.equals(_previousText)) {
// Restart the search from the beginning.
if (_stack == null) {
_stack = new Stack();
_indexes = new Stack();
} else {
_stack.clear();
_indexes.clear();
}
_stack.push(root);
_indexes.push(Integer.valueOf(1));
}
_previousText = text;
try {
// Indicate that something is happening with the cursor.
// setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
_findInLibraryEntryBox.setCursor(Cursor
.getPredefinedCursor(Cursor.WAIT_CURSOR));
_library.setCursor(Cursor
.getPredefinedCursor(Cursor.WAIT_CURSOR));
// Put a message in the progress bar at the bottom of the window.
// FIXME: Sadly, this doesn't work.
report("Opening Libraries ...");
// Traverse the model until we get a match.
// _stack will be empty only when no further match is found.
boolean foundOne = false;
int index = 0;
while (!_stack.isEmpty()) {
NamedObj parent = _stack.peek();
if (_findInSublibrary(text, parent, index)) {
// Found one. Stop the search.
foundOne = true;
break;
} else {
// Pop up one level and continue the search.
_stack.pop();
index = _indexes.pop();
}
}
if (!foundOne) {
// Reached the end of the library.
try {
if (MessageHandler
.yesNoCancelQuestion("Reached the end of the library. Start search again from the top?")) {
// Restart the search.
_stack.clear();
_indexes.clear();
_stack.push(root);
_indexes.push(Integer.valueOf(0));
actionPerformed(e);
}
} catch (CancelException e1) {
// Canceled by user.
return;
}
}
} finally {
// Restore the cursor.
// setCursor(Cursor.getDefaultCursor());
_findInLibraryEntryBox.setCursor(Cursor.getDefaultCursor());
_library.setCursor(Cursor.getDefaultCursor());
// Clear the message in the progress bar at the bottom of the window.
report("");
}
}
/** Search the specified library for a name or class name that
* contains the specified text.
* @param text The text to search for.
* @param library The library to search.
* @param index The index at which to start the search.
* @return True if a match is found.
*/
private boolean _findInSublibrary(String text, NamedObj library,
int index) {
int count = _libraryModel.getChildCount(library);
for (int i = index; i < count; i++) {
NamedObj candidate = (NamedObj) _libraryModel.getChild(library,
i);
String name = candidate.getName();
if (name.toLowerCase(Locale.getDefault()).contains(text)) {
// Found a match to the name.
_stack.push(candidate);
Object[] path = _stack.toArray();
TreePath pathToHit = new TreePath(path);
_library.makeVisible(pathToHit);
_library.scrollPathToVisible(pathToHit);
_library.addSelectionPath(pathToHit);
// Start the next search at the next item.
_indexes.push(Integer.valueOf(i + 1));
return true;
}
// Not a match. See whether any of its children are a match.
int childCount = 0;
ErrorHandler momlErrorHandler = MoMLParser.getErrorHandler();
MoMLParser.setErrorHandler(new SimpleErrorHandler());
MessageHandler messageHandler = MessageHandler
.getMessageHandler();
MessageHandler.setMessageHandler(new SimpleMessageHandler());
try {
childCount = _libraryModel.getChildCount(candidate);
} catch (Throwable throwable) {
report("Skipping opening " + candidate.getName() + ": "
+ throwable);
} finally {
MoMLParser.setErrorHandler(momlErrorHandler);
MessageHandler.setMessageHandler(messageHandler);
}
if (!_libraryModel.isLeaf(candidate) && childCount > 0) {
_stack.push(candidate);
_indexes.push(Integer.valueOf(i + 1));
if (_findInSublibrary(text, candidate, 0)) {
return true;
} else {
_stack.pop();
_indexes.pop();
}
}
}
return false;
}
private String _previousText;
private Stack _stack;
private Stack _indexes;
}
///////////////////////////////////////////////////////////////////
//// LinkElementProperties
/**
* A class that keeps stores basic properties of element (head, tail) in a link
*/
static private class LinkElementProperties {
/**
* Create a LinkElementProperties from the element (head or tail), a port if one is available and the ElementInLinkType
*/
LinkElementProperties(Object element, IOPort port,
ElementInLinkType type) {
this.element = element;
this.port = port;
this.type = type;
}
/**
* Extract the properties from an element (head or tail) in a link a return these as an ElementInLinkType
*/
static LinkElementProperties extractLinkProperties(Object element) {
IOPort elementPort = null;
ElementInLinkType elementType = ElementInLinkType.PORT_IN_ACTOR;
if (element instanceof IOPort) {
//This is a port of an actor
elementPort = (IOPort) element;
elementType = ElementInLinkType.PORT_IN_ACTOR;
} else if (element instanceof Location) {
//Either a port (not one of an actor) or a relation
NamedObj elementContainer = ((Location) element).getContainer();
if (elementContainer instanceof IOPort) {
//This is a port
elementPort = (IOPort) elementContainer;
elementType = ElementInLinkType.STANDALONE_PORT;
} else {
//This is a relation
assert elementContainer instanceof IORelation;
elementType = ElementInLinkType.RELATION;
}
}
return new LinkElementProperties(element, elementPort, elementType);
}
public final Object element;
public final IOPort port;
public final ElementInLinkType type;
}
///////////////////////////////////////////////////////////////////
//// HierarchyTreeCellRenderer
/** Render a cell in the model hierarchy tree. The model being
* displayed is highlighted.
*/
class HierarchyTreeCellRenderer extends PtolemyTreeCellRenderer {
/** Create a new rendition for the given object.
* If the object is the same as the currently displayed Ptolemy
* model, then make it bold.
*/
@Override
public Component getTreeCellRendererComponent(JTree tree, Object value,
boolean sel, boolean expanded, boolean leaf, int row,
boolean hasFocus) {
DefaultTreeCellRenderer component = (DefaultTreeCellRenderer) super
.getTreeCellRendererComponent(tree, value, selected,
expanded, leaf, row, hasFocus);
NamedObj model = getModel();
if (model != null && component != null && model.equals(value)) {
component.setText("" + component.getText()
+ " ");
}
return this;
}
}
///////////////////////////////////////////////////////////////////
//// HierarchyTreeSelectionListener
/** The user selected a node in the Hierarchy tree browser */
// Replaced by mouse listener
/*
private class HierarchyTreeSelectionListener implements
TreeSelectionListener {
// The value of the selection in the model hierarchy tree
// browser changed.
@Override
public void valueChanged(TreeSelectionEvent event) {
// Returns the last path element of the selection.
// This method is useful only when the selection model allows a single selection.
Object lastSelectedPathComponent = _treeView
.getLastSelectedPathComponent();
if (lastSelectedPathComponent instanceof NamedObj) {
try {
getConfiguration().openInstance(
(NamedObj) lastSelectedPathComponent);
} catch (Throwable throwable) {
MessageHandler.error("Could not open "
+ lastSelectedPathComponent, throwable);
}
}
}
}
*/
///////////////////////////////////////////////////////////////////
//// HierarchyTreeMouseAdapter
/** Listen for clicks of the mouse on the tree.
*/
private class HierarchyTreeMouseAdapter extends MouseAdapter {
public void mousePressed(MouseEvent e) {
if (e.getClickCount() == 2) {
// Returns the last path element of the selection.
// This method is useful only when the selection model allows a single selection.
Object lastSelectedPathComponent = _treeView
.getLastSelectedPathComponent();
if (lastSelectedPathComponent instanceof NamedObj) {
try {
getConfiguration().openInstance(
(NamedObj) lastSelectedPathComponent);
} catch (Throwable throwable) {
MessageHandler.error("Could not open "
+ lastSelectedPathComponent, throwable);
}
}
}
}
}
///////////////////////////////////////////////////////////////////
//// MoveToBackAction
/** Action to move the current selection to the back (which corresponds
* to first in the ordered list).
*/
protected class MoveToBackAction extends AbstractAction {
public MoveToBackAction() {
// Note that we also have "Send to Back" in
// vergil/kernel/AttributeController.java
super("Send to Back");
putValue("tooltip", "Send to back of like objects");
putValue(GUIUtilities.ACCELERATOR_KEY, KeyStroke.getKeyStroke(
KeyEvent.VK_B, Toolkit.getDefaultToolkit()
.getMenuShortcutKeyMask()));
putValue(GUIUtilities.MNEMONIC_KEY, Integer.valueOf(KeyEvent.VK_B));
}
@Override
public void actionPerformed(ActionEvent e) {
final NamedObj container = (NamedObj) _getGraphModel().getRoot();
// Get the selection objects.
// NOTE: The order in the model must be respected.
HashSet namedObjSet = _getSelectionSet();
final List elements = container
.sortContainedObjects(namedObjSet);
// Return if any is a derived object.
if (_checkForImplied(elements)) {
return;
}
// Issue a change request, since this requires write access.
ChangeRequest request = new ChangeRequest(container, "Send to back") {
@Override
protected void _execute() throws IllegalActionException {
MoveAction.move(elements, MoveAction.TO_FIRST, container);
}
};
container.requestChange(request);
}
}
///////////////////////////////////////////////////////////////////
//// MoveToFrontAction
/** Action to move the current selection to the back (which corresponds
* to first in the ordered list).
*/
protected class MoveToFrontAction extends AbstractAction {
public MoveToFrontAction() {
// Note that we also have "Bring to Front" in
// vergil/kernel/AttributeController.java
super("Bring to Front");
putValue("tooltip", "Bring to front of like objects");
putValue(GUIUtilities.ACCELERATOR_KEY, KeyStroke.getKeyStroke(
KeyEvent.VK_F, Toolkit.getDefaultToolkit()
.getMenuShortcutKeyMask()));
putValue(GUIUtilities.MNEMONIC_KEY, Integer.valueOf(KeyEvent.VK_F));
}
@Override
public void actionPerformed(ActionEvent e) {
final NamedObj container = (NamedObj) _getGraphModel().getRoot();
// Get the selection objects.
// NOTE: The order in the model must be respected.
HashSet namedObjSet = _getSelectionSet();
final List elements = container
.sortContainedObjects(namedObjSet);
// Return if any is a derived object.
if (_checkForImplied(elements)) {
return;
}
// Issue a change request, since this requires write access.
ChangeRequest request = new ChangeRequest(container,
"Bring to front") {
@Override
protected void _execute() throws IllegalActionException {
MoveAction.move(elements, MoveAction.TO_LAST, container);
}
};
container.requestChange(request);
}
}
///////////////////////////////////////////////////////////////////
//// PasteAction
/** Paste the current contents of the clipboard into the current model. */
protected class PasteAction extends AbstractAction {
/** Create a new action to paste the current contents of the
* clipboard into the current model.
*/
public PasteAction() {
super("Paste");
putValue("tooltip", "Paste the contents of the clipboard.");
putValue(GUIUtilities.ACCELERATOR_KEY, KeyStroke.getKeyStroke(
KeyEvent.VK_V, Toolkit.getDefaultToolkit()
.getMenuShortcutKeyMask()));
putValue(GUIUtilities.MNEMONIC_KEY, Integer.valueOf(KeyEvent.VK_P));
}
/** Paste the current contents of the clipboard into
* the current model.
*/
@Override
public void actionPerformed(ActionEvent e) {
paste();
}
}
///////////////////////////////////////////////////////////////////
//// OpenContainerAction
/** An action to open the container of this entity. */
private class OpenContainerAction extends AbstractAction {
/** Construct an open container action. This action opens
* the container of this class. If this entity is the toplevel
* then the icon is disabled.
* @param description A string that describes the action. Spaces are
* permitted, each word is usually capitalized.
*/
public OpenContainerAction(String description) {
super(description);
// Load the image by using the absolute path to the gif.
// Using a relative location should work, but it does not.
// Use the resource locator of the class.
// For more information, see
// jdk1.3/docs/guide/resources/resources.html
GUIUtilities.addIcons(this, new String[][] {
{ "/ptolemy/vergil/basic/img/up.gif",
GUIUtilities.LARGE_ICON },
{ "/ptolemy/vergil/basic/img/up_o.gif",
GUIUtilities.ROLLOVER_ICON },
{ "/ptolemy/vergil/basic/img/up_ov.gif",
GUIUtilities.ROLLOVER_SELECTED_ICON },
{ "/ptolemy/vergil/basic/img/up_on.gif",
GUIUtilities.SELECTED_ICON } });
putValue("tooltip", description);
}
/** Open the parent container, if any.
* @param event The action event, ignored by this method.
*/
@Override
public void actionPerformed(ActionEvent event) {
openContainer();
}
}
///////////////////////////////////////////////////////////////////
//// OpenLibraryMenuItemFactory
/**
* Create a menu item that will open a library in editable form.
*/
private class OpenLibraryMenuItemFactory implements MenuItemFactory {
/**
* Add an item to the given context menu that will open the
* given object as an editable model.
*/
@Override
public JMenuItem create(final JContextMenu menu, final NamedObj object) {
Action action = new AbstractAction("Open for Editing") {
@Override
public void actionPerformed(ActionEvent e) {
try {
getConfiguration().openModel(object);
} catch (KernelException ex) {
MessageHandler.error("Open failed.", ex);
}
}
};
action.putValue("tooltip", "Open library for editing.");
action.putValue(diva.gui.GUIUtilities.MNEMONIC_KEY,
Integer.valueOf(KeyEvent.VK_O));
return menu.add(action, (String) action.getValue(Action.NAME));
}
}
///////////////////////////////////////////////////////////////////
//// PrintAction
/**
* Print the current model.
*/
private class PrintAction extends AbstractAction {
/** Construct a print action.
* @param description A string that describes the action. Spaces are
* permitted, each word is usually capitalized.
*/
public PrintAction(String description) {
super(description);
putValue("tooltip", description);
// Load the image by using the absolute path to the gif.
// Using a relative location should work, but it does not.
// Use the resource locator of the class.
// For more information, see
// jdk1.3/docs/guide/resources/resources.html
GUIUtilities.addIcons(this, new String[][] {
{ "/ptolemy/vergil/basic/img/print.gif",
GUIUtilities.LARGE_ICON },
{ "/ptolemy/vergil/basic/img/print_o.gif",
GUIUtilities.ROLLOVER_ICON },
{ "/ptolemy/vergil/basic/img/print_ov.gif",
GUIUtilities.ROLLOVER_SELECTED_ICON },
{ "/ptolemy/vergil/basic/img/print_on.gif",
GUIUtilities.SELECTED_ICON } });
}
/** Print the current layout.
* @param event The action event, ignored by this method.
*/
@Override
public void actionPerformed(ActionEvent event) {
_print();
}
}
///////////////////////////////////////////////////////////////////
//// RedoAction
/**
* Redo the last undone MoML change on the current current model.
*/
private class RedoAction extends AbstractAction {
/**
* Create a new action to paste the current contents of the clipboard
* into the current model.
*/
public RedoAction() {
super("Redo");
putValue("tooltip", "Redo the last change undone.");
putValue(diva.gui.GUIUtilities.ACCELERATOR_KEY,
KeyStroke.getKeyStroke(KeyEvent.VK_Y, Toolkit
.getDefaultToolkit().getMenuShortcutKeyMask()));
putValue(diva.gui.GUIUtilities.MNEMONIC_KEY,
Integer.valueOf(KeyEvent.VK_R));
}
/**
* Redo the last undone MoML change on the current current model.
*
* @param e The event for the action.
*/
@Override
public void actionPerformed(ActionEvent e) {
redo();
}
}
///////////////////////////////////////////////////////////////////
//// SaveAction
/**
* Save the current model.
*/
private class SaveAction extends AbstractAction {
/** Construct a save action.
* @param description A string that describes the action. Spaces are
* permitted, each word is usually capitalized.
*/
public SaveAction(String description) {
super(description);
putValue("tooltip", description);
// Load the image by using the absolute path to the gif.
// Using a relative location should work, but it does not.
// Use the resource locator of the class.
// For more information, see
// jdk1.3/docs/guide/resources/resources.html
GUIUtilities.addIcons(this, new String[][] {
{ "/ptolemy/vergil/basic/img/save.gif",
GUIUtilities.LARGE_ICON },
{ "/ptolemy/vergil/basic/img/save_o.gif",
GUIUtilities.ROLLOVER_ICON },
{ "/ptolemy/vergil/basic/img/save_ov.gif",
GUIUtilities.ROLLOVER_SELECTED_ICON },
{ "/ptolemy/vergil/basic/img/save_on.gif",
GUIUtilities.SELECTED_ICON } });
putValue(GUIUtilities.MNEMONIC_KEY, Integer.valueOf(KeyEvent.VK_Z));
}
/** Save the current layout.
* @param e The action event, ignored by this method.
*/
@Override
public void actionPerformed(ActionEvent e) {
_save();
}
}
///////////////////////////////////////////////////////////////////
//// UndoAction
/**
* Undo the last undoable MoML change on the current current model.
*/
private class UndoAction extends AbstractAction {
/**
* Create a new action to paste the current contents of the clipboard
* into the current model.
*/
public UndoAction() {
super("Undo");
putValue("tooltip", "Undo the last change.");
putValue(diva.gui.GUIUtilities.ACCELERATOR_KEY,
KeyStroke.getKeyStroke(KeyEvent.VK_Z, Toolkit
.getDefaultToolkit().getMenuShortcutKeyMask()));
putValue(diva.gui.GUIUtilities.MNEMONIC_KEY,
Integer.valueOf(KeyEvent.VK_U));
}
/**
* Undo the last undoable MoML change on the current current model.
*
* @param e The event for the action.
*/
@Override
public void actionPerformed(ActionEvent e) {
undo();
}
}
///////////////////////////////////////////////////////////////////
//// ZoomInAction
/** An action to zoom in. */
private class ZoomInAction extends AbstractAction {
/** Construct a zoom in action.
* @param description A string that describes the action. Spaces are
* permitted, each word is usually capitalized.
*/
public ZoomInAction(String description) {
super(description);
// Load the image by using the absolute path to the gif.
// Using a relative location should work, but it does not.
// Use the resource locator of the class.
// For more information, see
// jdk1.3/docs/guide/resources/resources.html
GUIUtilities.addIcons(this, new String[][] {
{ "/ptolemy/vergil/basic/img/zoomin.gif",
GUIUtilities.LARGE_ICON },
{ "/ptolemy/vergil/basic/img/zoomin_o.gif",
GUIUtilities.ROLLOVER_ICON },
{ "/ptolemy/vergil/basic/img/zoomin_ov.gif",
GUIUtilities.ROLLOVER_SELECTED_ICON },
{ "/ptolemy/vergil/basic/img/zoomin_on.gif",
GUIUtilities.SELECTED_ICON } });
putValue("tooltip", description + " (Ctrl+Shift+=)");
// NOTE: The following assumes that the + key is the same
// as the = key. Unfortunately, the VK_PLUS key event doesn't
// work, so we have to do it this way.
putValue(GUIUtilities.ACCELERATOR_KEY, KeyStroke.getKeyStroke(
KeyEvent.VK_EQUALS, Toolkit.getDefaultToolkit()
.getMenuShortcutKeyMask() | Event.SHIFT_MASK));
putValue(GUIUtilities.MNEMONIC_KEY, Integer.valueOf(KeyEvent.VK_Z));
}
/** Zoom in by a factor of 1.25.
* @param e The action event, ignored by this method.
*/
@Override
public void actionPerformed(ActionEvent e) {
zoom(1.25);
}
}
///////////////////////////////////////////////////////////////////
//// ZoomResetAction
/** An action to reset zoom. */
private class ZoomResetAction extends AbstractAction {
/** Construct a zoom reset action.
* @param description A string that describes the action. Spaces are
* permitted, each word is usually capitalized.
*/
public ZoomResetAction(String description) {
super(description);
// Load the image by using the absolute path to the gif.
// Using a relative location should work, but it does not.
// Use the resource locator of the class.
// For more information, see
// jdk1.3/docs/guide/resources/resources.html
GUIUtilities.addIcons(this, new String[][] {
{ "/ptolemy/vergil/basic/img/zoomreset.gif",
GUIUtilities.LARGE_ICON },
{ "/ptolemy/vergil/basic/img/zoomreset_o.gif",
GUIUtilities.ROLLOVER_ICON },
{ "/ptolemy/vergil/basic/img/zoomreset_ov.gif",
GUIUtilities.ROLLOVER_SELECTED_ICON },
{ "/ptolemy/vergil/basic/img/zoomreset_on.gif",
GUIUtilities.SELECTED_ICON } });
// Control-m is usually carriage return. In this case, we use
// it to mean "return the zoom to the original state".
putValue("tooltip", description + " (Ctrl+M)");
putValue(GUIUtilities.ACCELERATOR_KEY, KeyStroke.getKeyStroke(
KeyEvent.VK_M, Toolkit.getDefaultToolkit()
.getMenuShortcutKeyMask()));
putValue(GUIUtilities.MNEMONIC_KEY, Integer.valueOf(KeyEvent.VK_M));
}
/** Reset the zoom.
* @param e The action event, ignored by this method.
*/
@Override
public void actionPerformed(ActionEvent e) {
zoomReset();
}
}
///////////////////////////////////////////////////////////////////
//// ZoomFitAction
/** An action to zoom fit.*/
private class ZoomFitAction extends AbstractAction {
/** Construct a zoom fit action.
* @param description A string that describes the action. Spaces are
* permitted, each word is usually capitalized.
*/
public ZoomFitAction(String description) {
super(description);
// Load the image by using the absolute path to the gif.
// Using a relative location should work, but it does not.
// Use the resource locator of the class.
// For more information, see
// jdk1.3/docs/guide/resources/resources.html
GUIUtilities.addIcons(this, new String[][] {
{ "/ptolemy/vergil/basic/img/zoomfit.gif",
GUIUtilities.LARGE_ICON },
{ "/ptolemy/vergil/basic/img/zoomfit_o.gif",
GUIUtilities.ROLLOVER_ICON },
{ "/ptolemy/vergil/basic/img/zoomfit_ov.gif",
GUIUtilities.ROLLOVER_SELECTED_ICON },
{ "/ptolemy/vergil/basic/img/zoomfit_on.gif",
GUIUtilities.SELECTED_ICON } });
putValue("tooltip", description + " (Ctrl+Shift+-)");
putValue(GUIUtilities.ACCELERATOR_KEY, KeyStroke.getKeyStroke(
KeyEvent.VK_MINUS, Toolkit.getDefaultToolkit()
.getMenuShortcutKeyMask() | Event.SHIFT_MASK));
putValue(GUIUtilities.MNEMONIC_KEY, Integer.valueOf(KeyEvent.VK_F));
}
/** Zoom so that the entire graph is visible.
* @param e The action event, ignored by this method.
*/
@Override
public void actionPerformed(ActionEvent e) {
zoomFit();
}
}
///////////////////////////////////////////////////////////////////
//// ZoomOutAction
/** An action to zoom out. */
private class ZoomOutAction extends AbstractAction {
/** Construct a zoom fit action.
* @param description A string that describes the action. Spaces are
* permitted, each word is usually capitalized.
*/
public ZoomOutAction(String description) {
super(description);
// Load the image by using the absolute path to the gif.
// Using a relative location should work, but it does not.
// Use the resource locator of the class.
// For more information, see
// jdk1.3/docs/guide/resources/resources.html
GUIUtilities.addIcons(this, new String[][] {
{ "/ptolemy/vergil/basic/img/zoomout.gif",
GUIUtilities.LARGE_ICON },
{ "/ptolemy/vergil/basic/img/zoomout_o.gif",
GUIUtilities.ROLLOVER_ICON },
{ "/ptolemy/vergil/basic/img/zoomout_ov.gif",
GUIUtilities.ROLLOVER_SELECTED_ICON },
{ "/ptolemy/vergil/basic/img/zoomout_on.gif",
GUIUtilities.SELECTED_ICON } });
putValue("tooltip", description + " (Ctrl+-)");
putValue(GUIUtilities.ACCELERATOR_KEY, KeyStroke.getKeyStroke(
KeyEvent.VK_MINUS, Toolkit.getDefaultToolkit()
.getMenuShortcutKeyMask()));
putValue(GUIUtilities.MNEMONIC_KEY, Integer.valueOf(KeyEvent.VK_U));
}
/** Zoom out by a factor of 1/1.25.
* @param e The action event, ignored by this method.
*/
@Override
public void actionPerformed(ActionEvent e) {
zoom(1.0 / 1.25);
}
}
///////////////////////////////////////////////////////////////////
//// LayoutConfigDialogAction
/** Action to display a dialog for setting layout options. */
private class LayoutConfigDialogAction extends AbstractAction {
/** Create a new action to show the layout configuration dialog. */
public LayoutConfigDialogAction() {
super("Configure Layout...");
putValue("tooltip",
"Set parameters for controlling the layout algorithm");
}
/** Show the layout configuration dialog. */
@Override
public void actionPerformed(ActionEvent e) {
NamedObj model = getModel();
Attribute attribute = model.getAttribute("_layoutConfiguration");
if (attribute == null) {
String momlChange = "";
model.requestChange(new MoMLChangeRequest(this, model,
momlChange, false));
attribute = model.getAttribute("_layoutConfiguration");
if (attribute == null) {
MessageHandler
.error("Could not create the layout configuration attribute.");
return;
}
}
new EditParametersDialog(BasicGraphFrame.this, attribute,
"Configure Layout Parameters");
}
}
}