/*
* File ModelBuilder.java
*
* Copyright (C) 2010 Remco Bouckaert remco@cs.auckland.ac.nz
*
* This file is part of BEAST2.
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership and licensing.
*
* BEAST is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* BEAST is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with BEAST; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
package beast.app.draw;
//import com.itextpdf.awt.PdfGraphics2D;
//import com.itextpdf.text.pdf.PdfContentByte;
//import com.itextpdf.text.pdf.PdfWriter;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.awt.image.BufferedImage;
import java.awt.print.PageFormat;
import java.awt.print.Printable;
import java.awt.print.PrinterException;
import java.awt.print.PrinterJob;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.List;
import javax.imageio.ImageIO;
import javax.swing.Action;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JColorChooser;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JToolBar;
import javax.swing.KeyStroke;
import javax.swing.UIManager;
import javax.swing.filechooser.FileFilter;
import beast.app.util.Utils;
import beast.core.BEASTInterface;
import beast.evolution.alignment.Sequence;
import beast.util.AddOnManager;
import beast.util.Randomizer;
import beast.util.XMLProducer;
/**
* program for drawing BEAST 2.0 models *
*/
public class ModelBuilder extends JPanel implements ComponentListener {
/**
* for serialisation
*/
static final long serialVersionUID = 1L;
/**
* File extension for XML format containing all graphical details (colour,
* position, etc) NB This is not the extension for GenerationD model files.
*/
static public final String FILE_EXT = ".xml";
final public static String ICONPATH = "beast/app/draw/icons/";
/**
* contains the Panel
*/
JScrollPane m_jScrollPane;
public DrawPanel g_panel;
final static int MODE_SELECT = 0;
final static int MODE_MOVE = 1;
final static int MODE_ARROW = 7;
final static int MODE_FUNCTION = 9;
Shape m_drawShape = null;
Rectangle m_selectRect = null;
int m_nMode = MODE_SELECT;
boolean m_bViewOperators = true;
boolean m_bViewLoggers = true;
boolean m_bViewSequences = true;
boolean m_bViewState = true;
// boolean m_bViewOperators = false;
// boolean m_bViewLoggers = false;
// boolean m_bViewSequences = false;
// boolean m_bViewState = false;
boolean m_bRelax = false;
// flag to indicate the model can be edited.
// set to false for read only view of the model, e.g. from beauti
boolean m_bIsEditable = true;
public void setEditable(boolean isEditable) {
m_bIsEditable = isEditable;
}
/**
* number of seconds to 'relax' after loading a file *
*/
int m_nRelaxSeconds = 10;
/**
* menu item indicating whether to relax or not *
*/
JCheckBoxMenuItem m_viewRelax;
Action a_new = new ActionNew();
Action a_load = new ActionLoad();
Action a_save = new ActionSave();
Action a_saveas = new ActionSaveAs();
ActionExport a_export = new ActionExport();
ActionPrint a_print = new ActionPrint();
Action a_quit = new ActionQuit();
Action a_undo = new ActionUndo();
Action a_redo = new ActionRedo();
Action a_selectall = new ActionSelectAll();
Action a_delnode = new ActionDeleteNode();
Action a_cutnode = new ActionCutNode();
Action a_copynode = new ActionCopyNode();
Action a_pastenode = new ActionPasteNode();
Action a_group = new ActionCollapse();
// Action a_ungroup = new ActionUngroup();
Action a_select = new ActionSelect();
Action a_arrow = new ActionArrow();
Action a_function = new ActionFunction();
Action a_fillcolor = new ActionFillColor();
Action a_pencolor = new ActionPenColor();
Action a_tofront = new ActionToFront();
Action a_forward = new ActionForward();
Action a_toback = new ActionToBack();
Action a_backward = new ActionBackward();
Action a_alignleft = new ActionAlignLeft();
Action a_alignright = new ActionAlignRight();
Action a_aligntop = new ActionAlignTop();
Action a_alignbottom = new ActionAlignBottom();
Action a_centerhorizontal = new ActionCenterHorizontal();
Action a_centervertical = new ActionCenterVertical();
Action a_spacehorizontal = new ActionSpaceHorizontal();
Action a_spacevertical = new ActionSpaceVertical();
Action a_about = new ActionAbout();
Action a_relax = new ActionRelax();
Action a_viewOperators = new ActionViewOperators();
Action a_viewLoggers = new ActionViewLoggers();
Action a_viewSequences = new ActionViewSequences();
Action a_layout = new ActionLayout();
ClipBoard m_clipboard = new ClipBoard();
/**
* name of current file, used for saving (as opposed to saveAs) *
*/
String m_sFileName = "";
/**
* the document in the model/view pattern *
*/
public Document m_doc = new Document();
/**
* current directory for opening files *
*/
String m_sDir = System.getProperty("user.dir");
public ModelBuilder() {
} // GBDraw c'tor
class ClipBoard {
String m_sText = null;
public ClipBoard() {
if (a_pastenode != null) {
a_pastenode.setEnabled(false);
}
}
public boolean hasText() {
return m_sText != null;
}
public String getText() {
return m_sText;
}
public void setText(String text) {
m_sText = text;
a_pastenode.setEnabled(true);
}
} // class ClipBoard
Selection m_Selection = new Selection();
ExtensionFileFilter ef1 = new ExtensionFileFilter(".xml", "BEAST files");
ExtensionFileFilter ef2 = new ExtensionFileFilter(".gif", "GIF images");
ExtensionFileFilter ef3 = new ExtensionFileFilter(".jpg", "JPG images");
ExtensionFileFilter ef4 = new ExtensionFileFilter(".bmp", "BMP images");
ExtensionFileFilter ef5 = new ExtensionFileFilter(".png", "PNG images");
boolean validateModel() {
int status = m_doc.isValidModel();
if (status == Document.STATUS_OK) {
return true;
}
String msg = "<html>Document is not valid: ";
switch (status) {
case Document.STATUS_CYCLE:
msg += "there is a cycle in the model.";
break;
case Document.STATUS_EMPTY_MODEL:
msg += "The model is empty, there is nothing to save.";
break;
case Document.STATUS_NOT_RUNNABLE:
msg += "there is no top level runnable item in the model (e.g. an MCMC node).";
break;
case Document.STATUS_ORPHANS_IN_MODEL:
msg += "there are orphaned items in the model (i.e. beastObjects that have no parents).";
break;
}
msg += "<br>Do you still want to try to save the model?</html>";
if (JOptionPane.showConfirmDialog(this, msg, "Model not valid",
JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
return true;
}
return false;
}
class ActionSave extends MyAction {
/**
* for serialisation
*/
private static final long serialVersionUID = -20389110859355156L;
public ActionSave() {
super("Save", "Save Graph", "save", KeyEvent.VK_S);
} // c'tor
public ActionSave(String name, String toolTipText, String icon,
int acceleratorKey) {
super(name, toolTipText, icon, acceleratorKey);
} // c'tor
@Override
public void actionPerformed(ActionEvent ae) {
if (!m_sFileName.equals("")) {
if (!validateModel()) {
return;
}
saveFile(m_sFileName);
m_doc.isSaved();
} else {
if (saveAs()) {
m_doc.isSaved();
}
}
} // actionPerformed
boolean saveAs() {
if (!validateModel()) {
return false;
}
JFileChooser fc = new JFileChooser(m_sDir);
fc.addChoosableFileFilter(ef1);
fc.setDialogTitle("Save Model As");
if (!m_sFileName.equals("")) {
// can happen on actionQuit
fc.setSelectedFile(new File(m_sFileName));
}
int rval = fc.showSaveDialog(g_panel);
if (rval == JFileChooser.APPROVE_OPTION) {
// System.out.println("Saving to file \""+
// f.getAbsoluteFile().toString()+"\"");
String fileName = fc.getSelectedFile().toString();
if (fileName.lastIndexOf('/') > 0) {
m_sDir = fileName.substring(0, fileName.lastIndexOf('/'));
}
if (!fileName.endsWith(FILE_EXT))
fileName = fileName.concat(FILE_EXT);
saveFile(fileName);
return true;
}
return false;
} // saveAs
protected void saveFile(String fileName) {
try {
FileWriter outfile = new FileWriter(fileName);
outfile.write(m_doc.toXML());
outfile.close();
m_sFileName = fileName;
} catch (IOException e) {
e.printStackTrace();
}
} // saveFile
} // class ActionSave
class ActionPrint extends ActionSave {
/**
* for serialisation
*/
private static final long serialVersionUID = -20389001859354L;
boolean m_bIsPrinting = false;
public ActionPrint() {
super("Print", "Print Graph", "print", KeyEvent.VK_P);
} // c'tor
@Override
public void actionPerformed(ActionEvent ae) {
PrinterJob printJob = PrinterJob.getPrinterJob();
printJob.setPrintable(g_panel);
if (printJob.printDialog())
try {
m_bIsPrinting = true;
printJob.print();
m_bIsPrinting = false;
} catch (PrinterException pe) {
m_bIsPrinting = false;
}
} // actionPerformed
public boolean isPrinting() {
return m_bIsPrinting;
}
} // class ActionPrint
class ActionSaveAs extends ActionSave {
/**
* for serialisation
*/
private static final long serialVersionUID = -20389110859354L;
public ActionSaveAs() {
super("Save As", "Save Graph As", "saveas", -1);
} // c'tor
@Override
public void actionPerformed(ActionEvent ae) {
saveAs();
} // actionPerformed
} // class ActionSaveAs
abstract class MyFileFilter extends FileFilter {
@Override
public boolean accept(File f) {
return f.isDirectory()
|| f.getName().toLowerCase().endsWith(getExtention());
}
abstract public String getExtention();
}
class ActionExport extends MyAction {
boolean m_bIsExporting = false;
/**
* for serialisation
*/
private static final long serialVersionUID = -3027642085935519L;
public ActionExport() {
super("Export", "Export to graphics file", "export", -1);
} // c'tor
@Override
public void actionPerformed(ActionEvent ae) {
m_bIsExporting = true;
// JFileChooser fc = new JFileChooser(m_sDir);
// fc.addChoosableFileFilter(new MyFileFilter() {
// public String getExtention() {
// return ".bmp";
// }
//
// public String getDescription() {
// return "Bitmap files (*.bmp)";
// }
// });
// fc.addChoosableFileFilter(new MyFileFilter() {
// public String getExtention() {
// return ".jpg";
// }
//
// public String getDescription() {
// return "JPEG bitmap files (*.jpg)";
// }
// });
// fc.addChoosableFileFilter(new MyFileFilter() {
// public String getExtention() {
// return ".png";
// }
//
// public String getDescription() {
// return "PNG bitmap files (*.png)";
// }
// });
// fc.setDialogTitle("Export Image As");
// int rval = fc.showSaveDialog(g_panel);
// if (rval == JFileChooser.APPROVE_OPTION) {
// String fileName = fc.getSelectedFile().toString();
try {
File file = Utils.getSaveFile("Export image (type determined by extention)", new File(m_sDir), "Image files", "png", "bmp", "jpg", "svg", "pdf");
if (file != null) {
String fileName = file.getAbsolutePath();
if (fileName.lastIndexOf('/') > 0) {
m_sDir = fileName.substring(0, fileName.lastIndexOf('/'));
}
if (fileName != null && !fileName.equals("")) {
// if (!fileName.toLowerCase().endsWith(".png")
// && fileName.toLowerCase().endsWith(".jpg")
// && fileName.toLowerCase().endsWith(".bmp")
// && fileName.toLowerCase().endsWith(".svg")) {
// fileName += ((MyFileFilter) fc.getFileFilter())
// .getExtention();
// }
if (fileName.toLowerCase().endsWith(".pdf")) {
JOptionPane.showMessageDialog(null, "Not implemented yet");
// com.itextpdf.text.Document doc = new com.itextpdf.text.Document();
// PdfWriter writer = PdfWriter.getInstance(doc, new FileOutputStream(fileName));
// doc.setPageSize(new com.itextpdf.text.Rectangle(g_panel.getWidth(), g_panel.getHeight()));
// doc.open();
// PdfContentByte cb = writer.getDirectContent();
// Graphics2D g2d = new PdfGraphics2D(cb, g_panel.getWidth(), g_panel.getHeight());
//
// g_panel.paint(g2d);
//
// g2d.dispose();
// doc.close();
m_bIsExporting = false;
repaint();
return;
} else if (fileName.toLowerCase().endsWith(".png")
|| fileName.toLowerCase().endsWith(".jpg")
|| fileName.toLowerCase().endsWith(".bmp")) {
BufferedImage bi;
Graphics g;
bi = new BufferedImage(g_panel.getWidth(), g_panel
.getHeight(), BufferedImage.TYPE_INT_RGB);
g = bi.getGraphics();
g.setPaintMode();
g.setColor(getBackground());
g.fillRect(0, 0, g_panel.getWidth(), g_panel
.getHeight());
g_panel.printAll(g);
try {
if (fileName.toLowerCase().endsWith(".png")) {
ImageIO.write(bi, "png", new File(fileName));
} else if (fileName.toLowerCase().endsWith(".jpg")) {
ImageIO.write(bi, "jpg", new File(fileName));
} else if (fileName.toLowerCase().endsWith(".bmp")) {
ImageIO.write(bi, "bmp", new File(fileName));
}
} catch (Exception e) {
JOptionPane.showMessageDialog(null, fileName
+ " was not written properly: "
+ e.getMessage());
e.printStackTrace();
}
m_bIsExporting = false;
repaint();
return;
} else if (fileName.toLowerCase().endsWith(".svg")) {
writeSVG(fileName);
m_bIsExporting = false;
repaint();
return;
}
JOptionPane.showMessageDialog(null, "Extention of file "
+ fileName
+ " not recognized as png,bmp,jpg or svg file");
}
}
} catch (Exception e) {
JOptionPane.showMessageDialog(null, "Something went wrong while exporting image: " + e.getMessage());
}
m_bIsExporting = false;
repaint();
}
private void writeSVG(String fileName) throws FileNotFoundException {
PrintStream out = new PrintStream(fileName);
out.println("<?xml version='1.0'?>\n" + "<!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.1//EN'\n"
+ " 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd'>\n"
+ "<svg xmlns='http://www.w3.org/2000/svg' version='1.1'\n" + " width='" + getWidth()
+ "' height='" + getHeight() + "' viewBox='0 0 " + getWidth() + " " + getHeight() + "'>\n"
+ "<rect fill='#fff' width='" + getWidth() + "' height='" + getHeight() + "'/>");
for (Shape shape : m_doc.m_objects) {
shape.toSVG(out);
}
out.println("</svg>");
}
public boolean isExporting() {
return m_bIsExporting;
}
} // class ActionExport
class ActionQuit extends ActionSave {
/**
* for serialisation
*/
private static final long serialVersionUID = -2038911085935515L;
public ActionQuit() {
super("Exit", "Exit Program", "exit", KeyEvent.VK_F4);
} // c'tor
@Override
public void actionPerformed(ActionEvent ae) {
if (!m_doc.m_bIsSaved) {
int result = JOptionPane.showConfirmDialog(null,
"Drawing changed. Do you want to save it?",
"Save before closing?",
JOptionPane.YES_NO_CANCEL_OPTION);
if (result == JOptionPane.CANCEL_OPTION) {
return;
}
if (result == JOptionPane.YES_OPTION) {
if (!saveAs()) {
return;
}
}
}
System.exit(0);
}
} // class ActionQuit
class ActionNew extends MyAction {
/**
* for serialisation
*/
private static final long serialVersionUID = -2038911085935515L;
public ActionNew() {
super("New", "New Network", "new", -1);
} // c'tor
@Override
public void actionPerformed(ActionEvent ae) {
m_sFileName = "";
m_doc = new Document();
m_Selection.setDocument(m_doc);
updateStatus();
m_doc.clearUndoStack();
m_Selection.clear();
m_drawShape = null;
}
} // class ActionNew
class ActionLoad extends MyAction {
/**
* for serialisation
*/
private static final long serialVersionUID = -2038911085935515L;
public ActionLoad() {
super("Load", "Load Graph", "open", KeyEvent.VK_O);
} // c'tor
@Override
public void actionPerformed(ActionEvent ae) {
JFileChooser fc = new JFileChooser(m_sDir);
fc.addChoosableFileFilter(ef1);
fc.setDialogTitle("Load Graph");
int rval = fc.showOpenDialog(g_panel);
if (rval == JFileChooser.APPROVE_OPTION) {
String fileName = fc.getSelectedFile().toString();
if (fileName.lastIndexOf('/') > 0) {
m_sDir = fileName.substring(0, fileName.lastIndexOf('/'));
}
g_panel.setCursor(new Cursor(Cursor.WAIT_CURSOR));
m_doc.loadFile(fileName);
m_sFileName = fileName;
g_panel.repaint();
try {
Thread.sleep(1000);
} catch (Exception e) {
}
setDrawingFlag();
g_panel.repaint();
g_panel.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
}
}
} // class ActionLoad
class ActionUndo extends MyAction {
/**
* for serialisation
*/
private static final long serialVersionUID = -3038910085935519L;
public ActionUndo() {
super("Undo", "Undo", "undo", KeyEvent.VK_Z);
setEnabled(false);
} // c'tor
@Override
public boolean isEnabled() {
return m_doc.canUndo();
}
@Override
public void actionPerformed(ActionEvent ae) {
m_doc.undo();
m_Selection.clear();
setDrawingFlag();
updateStatus();
}
} // ActionUndo
class ActionRedo extends MyAction {
/**
* for serialisation
*/
private static final long serialVersionUID = -4038910085935519L;
public ActionRedo() {
super("Redo", "Redo", "redo", KeyEvent.VK_Y);
setEnabled(false);
} // c'tor
@Override
public boolean isEnabled() {
return m_doc.canRedo();
}
@Override
public void actionPerformed(ActionEvent ae) {
m_doc.redo();
m_Selection.clear();
setDrawingFlag();
updateStatus();
}
} // ActionRedo
class ActionSelectAll extends MyAction {
/**
* for serialisation
*/
private static final long serialVersionUID = -2038912085935519L;
public ActionSelectAll() {
super("Select All", "Select All", "selectall", KeyEvent.VK_A);
} // c'tor
@Override
public void actionPerformed(ActionEvent ae) {
m_Selection.clear();
for (int i = 0; i < m_doc.m_objects.size(); i++) {
if (m_doc.m_objects.get(i).m_bNeedsDrawing) {
m_Selection.m_Selection.add(new Integer(i));
}
}
m_Selection.refreshTracker();
updateStatus();
}
} // class ActionSelectAll
class ActionDeleteNode extends MyAction {
/**
* for serialisation
*/
private static final long serialVersionUID = -2038912085935519L;
public ActionDeleteNode() {
super("Delete Node", "Delete Node", "delnode", KeyEvent.VK_DELETE);
setEnabled(false);
} // c'tor
@Override
public void actionPerformed(ActionEvent ae) {
m_doc.deleteShapes(m_Selection.m_Selection);
m_Selection.clear();
updateStatus();
}
} // class ActionDeleteNode
class ActionCopyNode extends MyAction {
/**
* for serialisation
*/
private static final long serialVersionUID = -2038732085935519L;
public ActionCopyNode() {
super("Copy", "Copy Nodes", "copy", KeyEvent.VK_C);
setEnabled(false);
} // c'tor
public ActionCopyNode(String name, String toolTipText, String icon,
int acceleratorKey) {
super(name, toolTipText, icon, acceleratorKey);
} // c'rot
@Override
public void actionPerformed(ActionEvent ae) {
copy();
}
public void copy() {
if (m_Selection.hasSelection()) {
String xml = "<doc>\n";
for (int i : m_Selection.m_Selection) {
xml += m_doc.m_objects.get(i).getXML() + "\n";
}
xml += "</doc>\n";
m_clipboard.setText(xml);
}
} // copy
} // class ActionCopyNode
class ActionCutNode extends ActionCopyNode {
/**
* for serialisation
*/
private static final long serialVersionUID = -2038822085935519L;
public ActionCutNode() {
super("Cut", "Cut Nodes", "cut", KeyEvent.VK_X);
setEnabled(false);
} // c'tor
@Override
public void actionPerformed(ActionEvent ae) {
copy();
m_doc.deleteShapes(m_Selection.m_Selection);
m_Selection.clear();
updateStatus();
}
} // class ActionCutNode
class ActionPasteNode extends MyAction {
/**
* for serialisation
*/
private static final long serialVersionUID = -2038732085935519L;
public ActionPasteNode() {
super("Paste", "Paste Nodes", "paste", KeyEvent.VK_V);
setEnabled(false);
} // c'tor
@Override
public void actionPerformed(ActionEvent ae) {
try {
m_doc.pasteShape(m_clipboard.getText());
updateStatus();
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public boolean isEnabled() {
return m_clipboard.hasText();
}
} // class ActionPasteNode
class ActionCollapse extends MyAction {
private static final long serialVersionUID = -1;
public ActionCollapse() {
super("Collapse shapes", "Collapse", "collapse", -1);
KeyStroke keyStroke = KeyStroke.getKeyStroke("G");
putValue(Action.ACCELERATOR_KEY, keyStroke);
setEnabled(false);
} // c'tor
@Override
public void actionPerformed(ActionEvent ae) {
m_doc.collapse(m_Selection);
m_Selection.refreshTracker();
updateStatus();
}
} // class ActionGroup
// class ActionUngroup extends MyAction {
// private static final long serialVersionUID = -1;
// public ActionUngroup() {
// super("Ungroup shapes", "Ungroup", "ungroup", "Ctrl G");
// setEnabled(false);
// } // c'tor
// public void actionPerformed(ActionEvent ae) {
// m_doc.ungroup(m_Selection);
// m_Selection.refreshTracker();
// updateStatus();
// }
// } // class ActionUngroup
class ActionSelect extends MyAction {
private static final long serialVersionUID = -1;
public ActionSelect() {
super("Select", "Select", "select", -1);
} // c'tor
@Override
public void actionPerformed(ActionEvent ae) {
m_nMode = MODE_SELECT;
}
} // class ActionSelect
class ActionArrow extends MyAction {
private static final long serialVersionUID = -1;
public ActionArrow() {
super("Arrow", "Arrow", "arrow", -1);
} // c'tor
@Override
public void actionPerformed(ActionEvent ae) {
m_nMode = MODE_ARROW;
}
} // class ActionArrow
class ActionFunction extends MyAction {
private static final long serialVersionUID = -1;
public ActionFunction() {
super("Function", "Function", "function", -1);
} // c'tor
@Override
public void actionPerformed(ActionEvent ae) {
m_nMode = MODE_FUNCTION;
}
} // class ActionFunction
class ActionFillColor extends MyAction {
private static final long serialVersionUID = -1;
public ActionFillColor() {
super("Fill color", "Fill color", "fillcolor", -1);
setEnabled(false);
} // c'tor
@Override
public void actionPerformed(ActionEvent ae) {
Shape shape = m_doc.m_objects.get(m_Selection
.getSingleSelection());
Color color = JColorChooser.showDialog(g_panel,
"Select Fill color", shape.getFillColor());
if (color != null) {
m_doc.setFillColor(color, m_Selection);
g_panel.repaint();
}
}
} // class ActionFillColor
class ActionPenColor extends MyAction {
private static final long serialVersionUID = -1;
public ActionPenColor() {
super("Pen color", "Pen color", "pencolor", -1);
setEnabled(false);
} // c'tor
@Override
public void actionPerformed(ActionEvent ae) {
Shape shape = m_doc.m_objects.get(m_Selection
.getSingleSelection());
Color color = JColorChooser.showDialog(g_panel,
"Select Fill color", shape.getFillColor());
if (color != null) {
m_doc.setPenColor(color, m_Selection);
g_panel.repaint();
}
}
} // class ActionPenColor
class ActionToFront extends MyAction {
/**
* for serialisation
*/
private static final long serialVersionUID = -1;
public ActionToFront() {
super("Bring to front", "To front", "tofront", KeyEvent.VK_PLUS);
} // c'tor
@Override
public void actionPerformed(ActionEvent ae) {
m_doc.toFront(m_Selection);
g_panel.repaint();
}
} // class ActionToFront
class ActionForward extends MyAction {
/**
* for serialisation
*/
private static final long serialVersionUID = -1;
public ActionForward() {
super("Bring forward", "Forward", "forward", -1);
KeyStroke keyStroke = KeyStroke.getKeyStroke("plus");
putValue(Action.ACCELERATOR_KEY, keyStroke);
} // c'tor
@Override
public void actionPerformed(ActionEvent ae) {
m_doc.forward(m_Selection);
g_panel.repaint();
}
} // class ActionForward
class ActionToBack extends MyAction {
/**
* for serialisation
*/
private static final long serialVersionUID = -1;
public ActionToBack() {
super("Bring to back", "To back", "toback", KeyEvent.VK_MINUS);
} // c'tor
@Override
public void actionPerformed(ActionEvent ae) {
m_doc.toBack(m_Selection);
g_panel.repaint();
}
} // class ActionToBack
class ActionBackward extends MyAction {
/**
* for serialisation
*/
private static final long serialVersionUID = -1;
public ActionBackward() {
super("Bring backward", "Backward", "backward", -1);
KeyStroke keyStroke = KeyStroke.getKeyStroke("minus");
putValue(Action.ACCELERATOR_KEY, keyStroke);
} // c'tor
@Override
public void actionPerformed(ActionEvent ae) {
m_doc.backward(m_Selection);
g_panel.repaint();
}
} // class ActionBackward
class ActionAlignLeft extends MyAction {
/**
* for serialisation
*/
private static final long serialVersionUID = -3138642085935519L;
public ActionAlignLeft() {
super("Align Left", "Align Left", "alignleft", -1);
} // c'tor
@Override
public void actionPerformed(ActionEvent ae) {
m_doc.alignLeft(m_Selection);
m_Selection.refreshTracker();
updateStatus();
}
} // class ActionAlignLeft
class ActionAlignRight extends MyAction {
/**
* for serialisation
*/
private static final long serialVersionUID = -4238642085935519L;
public ActionAlignRight() {
super("Align Right", "Align Right", "alignright", -1);
} // c'tor
@Override
public void actionPerformed(ActionEvent ae) {
m_doc.alignRight(m_Selection);
m_Selection.refreshTracker();
updateStatus();
}
} // class ActionAlignRight
class ActionAlignTop extends MyAction {
/**
* for serialisation
*/
private static final long serialVersionUID = -5338642085935519L;
public ActionAlignTop() {
super("Align Top", "Align Top", "aligntop", -1);
} // c'tor
@Override
public void actionPerformed(ActionEvent ae) {
m_doc.alignTop(m_Selection);
m_Selection.refreshTracker();
updateStatus();
}
} // class ActionAlignTop
class ActionAlignBottom extends MyAction {
/**
* for serialisation
*/
private static final long serialVersionUID = -6438642085935519L;
public ActionAlignBottom() {
super("Align Bottom", "Align Bottom", "alignbottom", -1);
} // c'tor
@Override
public void actionPerformed(ActionEvent ae) {
m_doc.alignBottom(m_Selection);
m_Selection.refreshTracker();
updateStatus();
}
} // class ActionAlignBottom
class ActionCenterHorizontal extends MyAction {
/**
* for serialisation
*/
private static final long serialVersionUID = -7538642085935519L;
public ActionCenterHorizontal() {
super("Center Horizontal", "Center Horizontal", "centerhorizontal",
-1);
} // c'tor
@Override
public void actionPerformed(ActionEvent ae) {
m_doc.centreHorizontal(m_Selection);
m_Selection.refreshTracker();
updateStatus();
}
} // class ActionCenterHorizontal
class ActionCenterVertical extends MyAction {
/**
* for serialisation
*/
private static final long serialVersionUID = -8638642085935519L;
public ActionCenterVertical() {
super("Center Vertical", "Center Vertical", "centervertical", -1);
} // c'tor
@Override
public void actionPerformed(ActionEvent ae) {
m_doc.centreVertical(m_Selection);
m_Selection.refreshTracker();
updateStatus();
}
} // class ActionCenterVertical
class ActionSpaceHorizontal extends MyAction {
/**
* for serialisation
*/
private static final long serialVersionUID = -9738642085935519L;
public ActionSpaceHorizontal() {
super("Space Horizontal", "Space Horizontal", "spacehorizontal", -1);
} // c'tor
@Override
public void actionPerformed(ActionEvent ae) {
m_doc.spaceHorizontal(m_Selection);
m_Selection.refreshTracker();
updateStatus();
}
} // class ActionSpaceHorizontal
class ActionSpaceVertical extends MyAction {
/**
* for serialisation
*/
private static final long serialVersionUID = -838642085935519L;
public ActionSpaceVertical() {
super("Space Vertical", "Space Vertical", "spacevertical", -1);
} // c'tor
@Override
public void actionPerformed(ActionEvent ae) {
m_doc.spaceVertical(m_Selection);
m_Selection.refreshTracker();
updateStatus();
}
} // class ActionSpaceVertical
class ActionAbout extends MyAction {
/**
* for serialisation
*/
private static final long serialVersionUID = -20389110859353L;
public ActionAbout() {
super("About", "Help about", "about", -1);
} // c'tor
@Override
public void actionPerformed(ActionEvent ae) {
JOptionPane
.showMessageDialog(
null,
"GenerationD Draw Tool\nRemco Bouckaert\nrrb@xm.co.nz\n2010",
"About Message", JOptionPane.PLAIN_MESSAGE);
}
} // class ActionAbout
class ActionRelax extends MyAction {
private static final long serialVersionUID = -1;
public ActionRelax() {
super("Relax", "Relax positions", "about", -1);
} // c'tor
@Override
public void actionPerformed(ActionEvent ae) {
m_bRelax = !m_bRelax;
m_viewRelax.setState(m_bRelax);
g_panel.repaint();
}
} // class ActionRelax
class ActionViewLoggers extends MyAction {
private static final long serialVersionUID = -1;
public ActionViewLoggers() {
super("View loggers", "View loggers", "about", -1);
} // c'tor
@Override
public void actionPerformed(ActionEvent ae) {
m_bViewLoggers = !m_bViewLoggers;
setDrawingFlag();
g_panel.repaint();
}
} // class ActionViewLoggers
class ActionViewOperators extends MyAction {
private static final long serialVersionUID = -1;
public ActionViewOperators() {
super("View Operators", "View Operators", "viewoperators", -1);
} // c'tor
@Override
public void actionPerformed(ActionEvent ae) {
m_bViewOperators = !m_bViewOperators;
setDrawingFlag();
g_panel.repaint();
}
} // class ActionViewOperators
class ActionViewSequences extends MyAction {
private static final long serialVersionUID = -1;
public ActionViewSequences() {
super("View Sequences", "View Sequences", "viewsequences", -1);
} // c'tor
@Override
public void actionPerformed(ActionEvent ae) {
m_bViewSequences = !m_bViewSequences;
setDrawingFlag();
g_panel.repaint();
}
} // class ActionViewSequences
class ActionLayout extends MyAction {
private static final long serialVersionUID = -1;
public ActionLayout() {
super("Layout", "Layout graph", "layout", -1);
} // c'tor
@Override
public void actionPerformed(ActionEvent e) {
g_panel.setCursor(new Cursor(Cursor.WAIT_CURSOR));
m_doc.layout();
m_doc.adjustArrows();
g_panel.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
repaint();
g_panel.repaint();
}
} // class ActionViewSequences
void updateStatus() {
a_undo.setEnabled(m_doc.canUndo());
a_redo.setEnabled(m_doc.canRedo());
int selectionSize = m_Selection.m_Selection.size();
boolean hasSelection = (selectionSize > 0);
boolean hasGroupSelection = (selectionSize > 1);
a_delnode.setEnabled(hasSelection);
a_copynode.setEnabled(hasSelection);
a_cutnode.setEnabled(hasSelection);
a_pastenode.setEnabled(m_clipboard.hasText());
a_fillcolor.setEnabled(hasSelection);
a_pencolor.setEnabled(hasSelection);
a_forward.setEnabled(hasSelection);
a_backward.setEnabled(hasSelection);
a_tofront.setEnabled(hasSelection);
a_toback.setEnabled(hasSelection);
a_group.setEnabled(hasSelection);
a_alignbottom.setEnabled(hasGroupSelection);
a_aligntop.setEnabled(hasGroupSelection);
a_alignleft.setEnabled(hasGroupSelection);
a_alignright.setEnabled(hasGroupSelection);
a_spacehorizontal.setEnabled(hasGroupSelection);
a_spacevertical.setEnabled(hasGroupSelection);
a_centerhorizontal.setEnabled(hasGroupSelection);
a_centervertical.setEnabled(hasGroupSelection);
g_panel.repaint();
}
public JToolBar m_jTbTools;
public JToolBar m_jTbTools2;
public void init() {
m_Selection.setDocument(m_doc);
int size = UIManager.getFont("Label.font").getSize();
setSize(2048 * size / 13, 2048 * size / 13);
g_panel = new DrawPanel();
m_jScrollPane = new JScrollPane(g_panel);
makeToolbar();
makeMenuBar();
addComponentListener(this);
this.setLayout(new BorderLayout());
this.add(m_jScrollPane, BorderLayout.CENTER);
g_panel.setPreferredSize(getSize());
}
void makeToolbar() {
m_jTbTools = new JToolBar();
m_jTbTools.setFloatable(false);
// m_jTbTools.setLayout(new GridBagLayout());
m_jTbTools.add(a_new);
m_jTbTools.add(a_save);
m_jTbTools.add(a_load);
m_jTbTools.addSeparator(new Dimension(2, 2));
m_jTbTools.add(a_cutnode);
m_jTbTools.add(a_copynode);
m_jTbTools.add(a_pastenode);
m_jTbTools.addSeparator(new Dimension(2, 2));
m_jTbTools.add(a_undo);
m_jTbTools.add(a_redo);
m_jTbTools.addSeparator(new Dimension(2, 2));
m_jTbTools.add(a_select);
m_jTbTools.add(a_function);
// m_jTbTools.add(a_rect);
// m_jTbTools.add(a_rrect);
// m_jTbTools.add(a_ellipse);
// m_jTbTools.add(a_line);
// m_jTbTools.add(a_poly);
m_jTbTools.add(a_arrow);
m_jTbTools.addSeparator(new Dimension(2, 2));
m_jTbTools.add(a_alignleft);
m_jTbTools.add(a_alignright);
m_jTbTools.add(a_aligntop);
m_jTbTools.add(a_alignbottom);
m_jTbTools.add(a_centerhorizontal);
m_jTbTools.add(a_centervertical);
m_jTbTools.add(a_spacehorizontal);
m_jTbTools.add(a_spacevertical);
setLayout(new BorderLayout());
// add("North", m_jTbTools);
// add("Center", g_panel);
m_jTbTools2 = new JToolBar();
m_jTbTools2.setFloatable(false);
m_jTbTools2.add(a_relax);
m_jTbTools2.add(a_viewLoggers);
m_jTbTools2.add(a_viewOperators);
m_jTbTools2.add(a_viewSequences);
m_jTbTools2.add(a_layout);
} // init
boolean needsDrawing(BEASTInterface beastObject) {
if (beastObject == null) {
return true;
}
if (!m_bViewOperators && beastObject instanceof beast.core.Operator) {
return false;
}
if (!m_bViewLoggers && beastObject instanceof beast.core.Logger) {
return false;
}
if (!m_bViewSequences && beastObject instanceof Sequence) {
return false;
}
if (!m_bViewState && beastObject instanceof beast.core.State) {
return false;
}
return true;
}
public void setDrawingFlag() {
for (int i = 0; i < m_doc.m_objects.size(); i++) {
Shape shape = m_doc.m_objects.get(i);
shape.m_bNeedsDrawing = false;
if (shape.m_bNeedsDrawing) {
shape.m_bNeedsDrawing = true;
}
if (shape instanceof BEASTObjectShape) {
BEASTInterface beastObject = ((BEASTObjectShape) shape).m_beastObject;
if (needsDrawing(beastObject)) {
shape.m_bNeedsDrawing = true;
}
} else if (shape instanceof InputShape) {
BEASTObjectShape beastObjectShape = ((InputShape) shape).m_beastObjectShape;
if (beastObjectShape != null) {
if (needsDrawing(beastObjectShape.m_beastObject)) {
shape.m_bNeedsDrawing = true;
}
} else {
shape.m_bNeedsDrawing = true;
}
} else if (shape instanceof Arrow) {
Shape tail = ((Arrow) shape).m_tailShape;
boolean needsDrawing = true;
if (tail instanceof BEASTObjectShape) {
needsDrawing = needsDrawing(((BEASTObjectShape) tail).m_beastObject);
}
if (needsDrawing) {
Shape head = ((Arrow) shape).m_headShape;
if (head instanceof InputShape) {
BEASTObjectShape beastObjectShape = ((InputShape) head).m_beastObjectShape;
if (beastObjectShape != null) {
needsDrawing = needsDrawing(beastObjectShape.m_beastObject);
}
}
if (needsDrawing) {
shape.m_bNeedsDrawing = true;
}
}
} else {
shape.m_bNeedsDrawing = true;
}
}
}
class DrawPanel extends JPanel implements Printable {
/**
* for serialisation
*/
static final long serialVersionUID = 1L;
public DrawPanel() {
setBackground(Color.white);
addMouseMotionListener(new GBDrawMouseMotionListener());
addMouseListener(new GBDrawMouseEventListener());
}
@Override
public void paintComponent(Graphics gr) {
Graphics2D g = (Graphics2D) gr;
RenderingHints rh = new RenderingHints(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
rh.put(RenderingHints.KEY_RENDERING,
RenderingHints.VALUE_RENDER_SPEED);
g.setRenderingHints(rh);
g.setBackground(Color.WHITE);
Rectangle r = g.getClipBounds();
g.clearRect(r.x, r.y, r.width, r.height);
m_doc.adjustInputs();
for (int i = 0; i < m_doc.m_objects.size(); i++) {
Shape shape = m_doc.m_objects.get(i);
if (shape.m_bNeedsDrawing) {
shape.draw(g, this);
}
}
if (!a_export.isExporting() && !a_print.isPrinting()) {
if (m_drawShape != null) {
m_drawShape.draw(g, this);
}
if (m_Selection.m_tracker != null) {
g.setColor(Color.BLACK);
for (int i = 0; i < m_Selection.m_tracker.size(); i++) {
TrackPoint p = m_Selection.m_tracker
.get(i);
g.fillRect(p.m_nX - 4, p.m_nY - 4, 8, 8);
}
}
if (m_selectRect != null) {
g.setXORMode(Color.green);
g.draw(m_selectRect);
}
}
if (m_bRelax) {
m_doc.relax(true);
repaint();
}
m_jScrollPane.revalidate();
} // paintComponent
/**
* implementation of Printable, used for printing
*
* @see Printable
*/
@Override
public int print(Graphics g, PageFormat pageFormat, int pageIndex) {
if (pageIndex > 0) {
return (NO_SUCH_PAGE);
} else {
Graphics2D g2d = (Graphics2D) g;
g2d.translate(pageFormat.getImageableX(), pageFormat
.getImageableY());
// Turn off double buffering
paint(g2d);
// Turn double buffering back on
return (PAGE_EXISTS);
}
} // print
/**
* position clicked on
*/
int m_nPosX = 0, m_nPosY = 0, m_nPoint;
boolean m_bIsMoving = false;
class GBDrawMouseMotionListener extends MouseMotionAdapter {
@Override
public void mouseDragged(MouseEvent me) {
switch (m_nMode) {
case MODE_SELECT:
if (m_bIsMoving || m_Selection.isSingleSelection()
&& m_Selection.intersects(me.getX(), me.getY())) {
m_bIsMoving = true;
Shape shape = m_doc.m_objects.get(m_Selection
.getSingleSelection());
if (getCursor().getType() == Cursor.DEFAULT_CURSOR) {
// simple move operation
m_doc.moveShape(m_nPosX, m_nPosY, me.getX(), me
.getY(), m_Selection.getSingleSelection());
m_Selection.m_tracker = shape.getTracker();
} else {
// resize/move point operation
m_doc.movePoint(m_nPoint, m_nPosX, m_nPosY, me
.getX(), me.getY(), m_Selection
.getSingleSelection());
m_Selection.m_tracker = shape.getTracker();
}
updateStatus();
break;
} else {
if (m_selectRect == null) {
if (m_Selection.intersects(me.getX(), me.getY())) {
// move selection
m_nMode = MODE_MOVE;
// m_doc.addUndoGroupAction(m_Selection);
m_nPosX = me.getX();
m_nPosY = me.getY();
} else {
// start new Rectangle
m_selectRect = new Rectangle(me.getX(), me
.getY(), 1, 1);
}
} else {
m_selectRect.width = me.getX() - m_selectRect.x;
m_selectRect.height = me.getY() - m_selectRect.y;
}
g_panel.repaint();
}
break;
case MODE_MOVE:
int dX = me.getX() - m_nPosX;
int dY = me.getY() - m_nPosY;
m_doc.moveShapes(dX, dY, m_Selection.m_Selection);
m_Selection.offset(dX, dY);
m_doc.adjustArrows();
m_nPosX = me.getX();
m_nPosY = me.getY();
repaint();
break;
case MODE_FUNCTION:
beast.app.draw.BEASTObjectShape function = (beast.app.draw.BEASTObjectShape) m_drawShape;
if (m_drawShape == null) {
function = new beast.app.draw.BEASTObjectShape();
function.m_x = me.getX();
function.m_y = me.getY();
function.m_w = 1;
function.m_h = 1;
m_drawShape = function;
} else {
function.m_w = me.getX() - function.m_x;
function.m_h = me.getY() - function.m_y;
}
m_Selection.m_tracker = function.getTracker();
g_panel.repaint();
break;
case MODE_ARROW:
Arrow arrow = (Arrow) m_drawShape;
if (m_drawShape == null) {
int selectionIndex = -1;
for (int i = 0; selectionIndex < 0
&& i < m_doc.m_objects.size(); i++) {
Shape shape = m_doc.m_objects.get(i);
if (shape.m_bNeedsDrawing
&& shape.intersects(me.getX(), me.getY())) {
m_nPosX = shape.offsetX(me.getX());
m_nPosY = shape.offsetY(me.getY());
selectionIndex = i;
}
}
if (selectionIndex < 0) {
return;
}
Shape shape = m_doc.m_objects.get(selectionIndex);
if (shape instanceof Arrow) {
return;
}
if (shape instanceof InputShape) {
shape = ((InputShape) shape).m_beastObjectShape;
}
arrow = new Arrow((BEASTObjectShape) shape, me.getX(), me
.getY());
arrow.m_w = 1;
arrow.m_h = 1;
m_drawShape = arrow;
} else {
arrow.setHead(me.getX() - arrow.m_x, me.getY()
- arrow.m_y);
}
// m_Selection.m_tracker = arrow.getTracker();
g_panel.repaint();
break;
}
} // mouseDragged
@Override
public void mouseMoved(MouseEvent me) {
if (m_Selection.m_tracker != null
&& m_Selection.isSingleSelection()) {
if (getCursor().getType() != Cursor.DEFAULT_CURSOR) {
setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
}
for (int i = 0; i < m_Selection.m_tracker.size(); i++) {
TrackPoint p = m_Selection.m_tracker
.get(i);
if (me.getX() > p.m_nX - 4 && me.getX() < p.m_nX + 4
&& me.getY() > p.m_nY - 4
&& me.getY() < p.m_nY + 4) {
m_nPoint = i;
m_nPosX = me.getX() - p.m_nX;
m_nPosY = me.getY() - p.m_nY;
setCursor(new Cursor(p.m_nCursor));
return;
}
}
Shape shape = m_doc.m_objects.get(m_Selection
.getSingleSelection());
m_nPosX = me.getX() - shape.m_x;
m_nPosY = me.getY() - shape.m_y;
} else {
if (getCursor().getType() != Cursor.DEFAULT_CURSOR) {
setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
}
}
// set up tool tip text
for (int i = m_doc.m_objects.size() - 1; i >= 0; i--) {
Shape shape = m_doc.m_objects.get(i);
if (shape.m_bNeedsDrawing
&& shape.intersects(me.getX(), me.getY())) {
if (shape instanceof BEASTObjectShape) {
BEASTObjectShape beastObject = (BEASTObjectShape) shape;
try {
String toolTip = "<html>";
for (InputShape input : beastObject.m_inputs) {
toolTip += input.getLongLabel() + "<br>";
}
toolTip += "</html>";
setToolTipText(toolTip);
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return;
}
}
} // mouseMoved
} // class GBDrawMouseMotionListener
class GBDrawMouseEventListener extends MouseAdapter {
@Override
public void mouseClicked(MouseEvent me) {
if (me.getClickCount() == 2) {
handleDoubleClick(me);
return;
}
if (me.getButton() == MouseEvent.BUTTON3) {
handleRightClick(me);
return;
}
// otherwise, assume left click
switch (m_nMode) {
case MODE_SELECT:
int selectionIndex = -1;
for (int i = m_doc.m_objects.size() - 1; selectionIndex < 0 && i >= 0; i--) {
Shape shape = m_doc.m_objects.get(i);
if (shape.m_bNeedsDrawing && !(shape instanceof Arrow) && shape.intersects(me.getX(), me.getY())) {
m_nPosX = shape.offsetX(me.getX());
m_nPosY = shape.offsetY(me.getY());
selectionIndex = i;
}
}
if (selectionIndex < 0) {
for (int i = m_doc.m_objects.size() - 1; selectionIndex < 0 && i >= 0; i--) {
Shape shape = m_doc.m_objects.get(i);
if (shape.m_bNeedsDrawing && shape.intersects(me.getX(), me.getY())) {
m_nPosX = shape.offsetX(me.getX());
m_nPosY = shape.offsetY(me.getY());
selectionIndex = i;
}
}
if (selectionIndex < 0) {
return;
}
}
if ((me.getModifiersEx() & InputEvent.CTRL_DOWN_MASK) != 0) {
m_Selection.toggleSelection(selectionIndex);
} else if ((me.getModifiersEx() & InputEvent.SHIFT_DOWN_MASK) != 0) {
m_Selection.addToSelection(selectionIndex);
} else {
m_Selection.clear();
m_Selection.setSingleSelection(selectionIndex);
}
updateStatus();
break;
}
} // mouseClicked
void handleDoubleClick(MouseEvent me) {
// find the shape intersecting the mouse pointer
try {
for (int i = m_doc.m_objects.size() - 1; i >= 0; i--) {
Shape shape = m_doc.m_objects.get(i);
if (shape.m_bNeedsDrawing
&& shape.intersects(me.getX(), me.getY())) {
if (shape instanceof InputShape) {
// resolve the associated input
InputShape ellipse = (InputShape) shape;
String input = ellipse.getInputName();
BEASTInterface beastObject = ellipse.getBEASTObject();
if (beastObject.isPrimitive(input)) {
String valueString = "";
if (beastObject.getInputValue(input) != null) {
valueString = beastObject.getInputValue(input)
.toString();
}
valueString = JOptionPane.showInputDialog(input
+ ":", valueString);
if (valueString != null) {
m_doc.setInputValue(ellipse.getPluginShape(), input, valueString);
// ellipse.setLabel(input + "=" +
// beastObject.getInputValue(input).toString());
g_panel.repaint();
}
}
}
return;
}
}
} catch (Exception e) {
e.printStackTrace();
}
} // handleDoubleClick
void handleRightClick(MouseEvent me) {
if (!m_bIsEditable) {
return;
}
JPopupMenu popupMenu = new JPopupMenu("Choose a value");
if (!m_Selection.hasSelection()) {
int selectionIndex = -1;
for (int i = 0; selectionIndex < 0
&& i < m_doc.m_objects.size(); i++) {
Shape shape = m_doc.m_objects.get(i);
if (shape.m_bNeedsDrawing
&& shape.intersects(me.getX(), me.getY())) {
m_nPosX = shape.offsetX(me.getX());
m_nPosY = shape.offsetY(me.getY());
m_Selection.addToSelection(i);
break;
}
}
}
JMenuItem addNodeItem = new JMenuItem("Change label");
ActionListener label = new ActionListener() {
@Override
public void actionPerformed(ActionEvent ae) {
Shape shape = m_Selection.getSingleSelectionShape();
String name = (String) JOptionPane.showInputDialog(
null, shape.getID(), "New label",
JOptionPane.OK_CANCEL_OPTION, null, null, shape
.getID());
if (name == null || name.equals("")) {
return;
}
while (name.contains("\\n")) {
int i = name.indexOf("\\n");
name = name.substring(0, i - 1) + '\n'
+ name.substring(i + 2);
}
m_doc.setID(name, m_Selection.getSingleSelection());
repaint();
}
};
addNodeItem.addActionListener(label);
addNodeItem.setEnabled(m_Selection.isSingleSelection());
popupMenu.add(addNodeItem);
JMenuItem isFilledMenu = new JMenuItem("Fill object");
if (m_Selection.isSingleSelection()) {
Shape shape = m_Selection.getSingleSelectionShape();
if (shape.isFilled()) {
isFilledMenu = new JMenuItem("Don't fill object");
}
}
isFilledMenu.addActionListener(ae -> {
m_doc.toggleFilled(m_Selection.getSingleSelection());
g_panel.repaint();
});
isFilledMenu.setEnabled(m_Selection.isSingleSelection());
popupMenu.add(isFilledMenu);
JMenuItem propertiesItem = new JMenuItem("Properties");
propertiesItem.addActionListener(ae -> {
Shape shape = m_Selection.getSingleSelectionShape();
if (shape instanceof BEASTObjectShape) {
BEASTInterface beastObject = ((BEASTObjectShape) shape).m_beastObject;
List<BEASTInterface> beastObjects = new ArrayList<>();
for (Shape shape2 : m_doc.m_objects) {
if (shape2 instanceof BEASTObjectShape) {
beastObjects.add(((BEASTObjectShape) shape2).m_beastObject);
}
}
BEASTObjectDialog dlg = new BEASTObjectDialog(beastObject, beastObject.getClass(), beastObjects, null);
if (dlg.showDialog()) {
// add newly created Plug-ins
int newShapes = 0;
if (beastObjects.size() < BEASTObjectPanel.g_plugins.size()) {
for (BEASTInterface beastObject2 : BEASTObjectPanel.g_plugins.values()) {
if (!beastObjects.contains(beastObject2)) {
try {
newShapes++;
Shape shape2 = new BEASTObjectShape(beastObject2, m_doc);
shape2.m_x = 10;
shape2.m_y = newShapes * 50;
shape2.m_w = 80;
m_doc.addNewShape(shape2);
updateStatus();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
// re-attach all arrows
m_Selection.clear();
m_doc.recalcArrows();
m_doc.adjustArrows();
}
repaint();
}
});
propertiesItem.setEnabled(m_Selection.isSingleSelection());
popupMenu.add(propertiesItem);
JMenuItem saveAsItem = new JMenuItem("Save as");
saveAsItem.addActionListener(ae -> {
Shape shape = m_Selection.getSingleSelectionShape();
BEASTInterface beastObject = ((BEASTObjectShape) shape).m_beastObject;
JFileChooser fc = new JFileChooser(m_sDir);
fc.addChoosableFileFilter(ef1);
fc.setDialogTitle("Save BEASTObject As");
if (!m_sFileName.equals("")) {
// can happen on actionQuit
fc.setSelectedFile(new File(m_sFileName));
}
int rval = fc.showSaveDialog(g_panel);
if (rval == JFileChooser.APPROVE_OPTION) {
// System.out.println("Saving to file \""+
// f.getAbsoluteFile().toString()+"\"");
String fileName = fc.getSelectedFile().toString();
if (fileName.lastIndexOf('/') > 0) {
m_sDir = fileName.substring(0, fileName
.lastIndexOf('/'));
}
if (!fileName.endsWith(FILE_EXT))
fileName = fileName.concat(FILE_EXT);
try {
FileWriter outfile = new FileWriter(fileName);
outfile.write(new XMLProducer().modelToXML(beastObject));
outfile.close();
} catch (Exception e) {
JOptionPane.showMessageDialog(null,
"Something went wrong when writing the file: "
+ e.getClass().getName() + " "
+ e.getMessage());
}
m_sFileName = fileName;
}
repaint();
});
saveAsItem.setEnabled(m_Selection.isSingleSelection());
popupMenu.add(saveAsItem);
popupMenu.setLocation(me.getX(), me.getY());
popupMenu.show(g_panel, me.getX(), me.getY());
} // handleRightClick
@Override
public void mouseReleased(MouseEvent me) {
if (m_drawShape != null) {
m_drawShape.normalize();
}
m_bIsMoving = false;
boolean added = true;
switch (m_nMode) {
case MODE_SELECT:
if (m_selectRect != null) {
if ((me.getModifiersEx() & InputEvent.CTRL_DOWN_MASK) == 0
&& (me.getModifiersEx() & InputEvent.SHIFT_DOWN_MASK) == 0) {
// fresh selection
m_Selection.clear();
}
for (int i = 0; i < m_doc.m_objects.size(); i++) {
if (m_doc.m_objects.get(i)
.intersects(m_selectRect)
&& m_doc.m_objects.get(i).m_bNeedsDrawing) {
if ((me.getModifiersEx() & InputEvent.CTRL_DOWN_MASK) != 0) {
m_Selection.toggleSelection(i);
} else {
m_Selection.addToSelection(i);
}
}
}
m_selectRect = null;
updateStatus();
}
return;
case MODE_MOVE:
m_nMode = MODE_SELECT;
updateStatus();
return;
case MODE_FUNCTION:
BEASTObjectShape function = (BEASTObjectShape) m_drawShape;
if (function == null) {
return;
}
if (function.m_w > 0 && function.m_h > 0) {
String functionClassName = (String) JOptionPane
.showInputDialog(g_panel, "Select a constant",
"select", JOptionPane.PLAIN_MESSAGE,
null, m_doc.m_sPlugInNames, null);
if (functionClassName != null) {
try {
function.init(functionClassName, m_doc);
m_doc.addNewShape(function);
updateStatus();
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
} else {
added = false;
}
} else {
added = false;
}
break;
case MODE_ARROW:
Arrow arrow = (Arrow) m_drawShape;
if (m_drawShape != null) {
int selectionIndex = -1;
for (int i = 0; selectionIndex < 0
&& i < m_doc.m_objects.size(); i++) {
Shape shape = m_doc.m_objects.get(i);
if (shape.m_bNeedsDrawing
&& shape.intersects(me.getX(), me.getY())) {
m_nPosX = shape.offsetX(me.getX());
m_nPosY = shape.offsetY(me.getY());
selectionIndex = i;
}
}
if (selectionIndex < 0) {
m_drawShape = null;
repaint();
return;
}
Shape target = m_doc.m_objects.get(selectionIndex);
if (!(target instanceof InputShape)) {
// only connect to inputs of functions
m_drawShape = null;
repaint();
return;
}
// check no cycle is introduced
InputShape target2 = (InputShape) target;
if (m_doc.isAscendant(arrow.m_tailShape.m_beastObject,
target2.getBEASTObject())) {
JOptionPane
.showMessageDialog(null,
"Cannot make this connection since this creates a cycle in the model");
return;
}
try {
// try to add connection
// this links the input of the target beastObject
// to the source beastObject. If types mismatch,
// an exception is thrown and no arrow added.
arrow.setHead(target2, m_doc.m_objects, m_doc);
m_doc.addNewShape(arrow);
} catch (Exception e) {
JOptionPane.showMessageDialog(null, e.getMessage());
repaint();
}
}
break;
}
m_drawShape = null;
m_nMode = MODE_SELECT;
if (added) {
m_Selection.setSingleSelection(m_doc.m_objects.size() - 1);
g_panel.repaint();
} else {
m_Selection.clear();
g_panel.repaint();
}
} // mouseReleased
} // GBDrawMouseEventListener
} // class DrawPanel
public JMenuBar makeMenuBar() {
JMenuBar menuBar = new JMenuBar();
JMenu fileMenu = new JMenu("File");
fileMenu.setMnemonic('F');
menuBar.add(fileMenu);
fileMenu.add(a_new);
fileMenu.add(a_load);
fileMenu.add(a_save);
fileMenu.add(a_saveas);
fileMenu.addSeparator();
fileMenu.add(a_export);
fileMenu.add(a_print);
fileMenu.addSeparator();
fileMenu.add(a_quit);
JMenu editMenu = new JMenu("Edit");
editMenu.setMnemonic('E');
menuBar.add(editMenu);
editMenu.add(a_undo);
editMenu.add(a_redo);
editMenu.addSeparator();
editMenu.add(a_selectall);
editMenu.add(a_delnode);
editMenu.add(a_cutnode);
editMenu.add(a_copynode);
editMenu.add(a_pastenode);
editMenu.addSeparator();
editMenu.add(a_alignleft);
editMenu.add(a_alignright);
editMenu.add(a_aligntop);
editMenu.add(a_alignbottom);
editMenu.add(a_centerhorizontal);
editMenu.add(a_centervertical);
editMenu.add(a_spacehorizontal);
editMenu.add(a_spacevertical);
editMenu.addSeparator();
editMenu.add(a_group);
// editMenu.add(a_ungroup);
editMenu.addSeparator();
JMenu drawMenu = new JMenu("Draw");
drawMenu.setMnemonic('D');
menuBar.add(drawMenu);
drawMenu.add(a_select);
drawMenu.add(a_function);
drawMenu.add(a_arrow);
JMenu objectMenu = new JMenu("Object");
objectMenu.setMnemonic('O');
menuBar.add(objectMenu);
objectMenu.add(a_fillcolor);
objectMenu.add(a_pencolor);
objectMenu.addSeparator();
objectMenu.add(a_tofront);
objectMenu.add(a_forward);
objectMenu.add(a_toback);
objectMenu.add(a_backward);
JMenu viewMenu = new JMenu("View");
viewMenu.setMnemonic('V');
menuBar.add(viewMenu);
final JCheckBoxMenuItem viewOperators = new JCheckBoxMenuItem(
"Show Operators", m_bViewOperators);
viewOperators.addActionListener(ae -> {
m_bViewOperators = viewOperators.getState();
setDrawingFlag();
g_panel.repaint();
});
viewMenu.add(viewOperators);
final JCheckBoxMenuItem viewLoggers = new JCheckBoxMenuItem(
"Show Loggers", m_bViewLoggers);
viewLoggers.addActionListener(ae -> {
m_bViewLoggers = viewLoggers.getState();
setDrawingFlag();
g_panel.repaint();
});
viewMenu.add(viewLoggers);
final JCheckBoxMenuItem viewSequences = new JCheckBoxMenuItem(
"Show Sequences", m_bViewSequences);
viewSequences.addActionListener(ae -> {
m_bViewSequences = viewSequences.getState();
setDrawingFlag();
g_panel.repaint();
});
viewMenu.add(viewSequences);
final JCheckBoxMenuItem viewState = new JCheckBoxMenuItem("Show State",
m_bViewState);
viewState.addActionListener(ae -> {
m_bViewState = viewState.getState();
setDrawingFlag();
g_panel.repaint();
});
viewMenu.add(viewState);
m_viewRelax = new JCheckBoxMenuItem("Relax", m_bRelax);
m_viewRelax.addActionListener(ae -> {
m_bRelax = m_viewRelax.getState();
g_panel.repaint();
});
viewMenu.add(m_viewRelax);
JMenuItem layoutMenu = new JMenuItem("Layout Visible Items");
layoutMenu.setMnemonic('L');
layoutMenu.addActionListener(e -> {
g_panel.setCursor(new Cursor(Cursor.WAIT_CURSOR));
m_doc.layout();
m_doc.adjustArrows();
repaint();
g_panel.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
});
viewMenu.add(layoutMenu);
viewMenu.addSeparator();
final JCheckBoxMenuItem viewAllInputs = new JCheckBoxMenuItem("Show All Inputs",
m_doc.m_bShowALlInputs);
viewAllInputs.addActionListener(ae -> {
m_doc.m_bShowALlInputs = viewAllInputs.getState();
m_doc.reinit();
setDrawingFlag();
g_panel.repaint();
});
viewMenu.add(viewAllInputs);
final JCheckBoxMenuItem sanitseIDs = new JCheckBoxMenuItem("Sanitise IDs",
m_doc.m_bSanitiseIDs);
sanitseIDs.addActionListener(ae -> {
m_doc.m_bSanitiseIDs = sanitseIDs.getState();
setDrawingFlag();
g_panel.repaint();
});
viewMenu.add(sanitseIDs);
JMenu helpMenu = new JMenu("Help");
helpMenu.setMnemonic('H');
menuBar.add(helpMenu);
helpMenu.add(a_about);
return menuBar;
} // makeMenuBar
public static void main(String args[]) {
Randomizer.setSeed(127);
try {
AddOnManager.loadExternalJars();
} catch (Exception e) {
e.printStackTrace();
}
JFrame f = new JFrame("Model Builder");
ModelBuilder drawTest = new ModelBuilder();
drawTest.init();
JMenuBar menuBar = drawTest.makeMenuBar();
f.setJMenuBar(menuBar);
f.add(drawTest.m_jTbTools, BorderLayout.NORTH);
f.add(drawTest, BorderLayout.CENTER);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
java.net.URL tempURL = ClassLoader
.getSystemResource(ModelBuilder.ICONPATH + "/GenerationD.png");
try {
f.setIconImage(ImageIO.read(tempURL));
} catch (Exception e) {
e.printStackTrace();
// ignore
}
if (args.length > 0) {
drawTest.m_doc.loadFile(args[0]);
drawTest.setDrawingFlag();
}
int size = UIManager.getFont("Label.font").getSize();
f.setSize(800 * size / 13, 600 * size / 13);
f.setVisible(true);
} // main
// implements ComponentListener
@Override
public void componentHidden(ComponentEvent e) {
m_jScrollPane.revalidate();
}
// implements ComponentListener
@Override
public void componentMoved(ComponentEvent e) {
m_jScrollPane.revalidate();
}
// implements ComponentListener
@Override
public void componentResized(ComponentEvent e) {
m_jScrollPane.revalidate();
}
// implements ComponentListener
@Override
public void componentShown(ComponentEvent e) {
m_jScrollPane.revalidate();
}
} // class ModelBuilder