summaryrefslogtreecommitdiff
path: root/src/main/java/simulator
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2025-06-06 08:02:52 +0300
committerPaul Buetow <paul@buetow.org>2025-06-06 08:02:52 +0300
commit1d99762c7965d351510cfb5e08eac25e48d96038 (patch)
treef469493e911878ab9055ccf0494211bf9015922d /src/main/java/simulator
parent4d35597bd92607c4d194686e20b125044506c79a (diff)
Modernize project structure, update Maven config, move sources, add logging config, update README and .gitignore
Diffstat (limited to 'src/main/java/simulator')
-rw-r--r--src/main/java/simulator/VSCreateTask.java179
-rw-r--r--src/main/java/simulator/VSLogging.java201
-rw-r--r--src/main/java/simulator/VSMain.java70
-rw-r--r--src/main/java/simulator/VSMenuItemStates.java109
-rw-r--r--src/main/java/simulator/VSSimulator.java1536
-rw-r--r--src/main/java/simulator/VSSimulatorFrame.java628
-rw-r--r--src/main/java/simulator/VSSimulatorVisualization.java1814
7 files changed, 4537 insertions, 0 deletions
diff --git a/src/main/java/simulator/VSCreateTask.java b/src/main/java/simulator/VSCreateTask.java
new file mode 100644
index 0000000..9a6426b
--- /dev/null
+++ b/src/main/java/simulator/VSCreateTask.java
@@ -0,0 +1,179 @@
+package simulator;
+
+import core.VSInternalProcess;
+import core.VSTask;
+import events.VSAbstractEvent;
+import events.VSRegisteredEvents;
+import events.internal.VSProtocolEvent;
+
+/**
+ * The class VSCreateTask, an object of this class represents how new
+ * VSTask objects are to be created using JComboBox selections of the
+ * GUI editor..
+ *
+ * @author Paul C. Buetow
+ */
+public class VSCreateTask {
+ /** The event classname. */
+ private String eventClassname;
+
+ /** The create task menu string. */
+ private String menuText;
+
+ /** The protocol classname. */
+ private String protocolClassname;
+
+ /** The shortname. */
+ private String shortname;
+
+ /** The task is a protocol activation. */
+ private boolean isProtocolActivation;
+
+ /** The task is a protocol deactivation. */
+ private boolean isProtocolDeactivation;
+
+ /** The task is a client protocol. */
+ private boolean isClientProtocol;
+
+ /** True, if the task is a client request. false, if the task is a
+ * server request
+ */
+ private boolean isRequest;
+
+ /**
+ * Instantiates a new VSCreateTask object.
+ *
+ * @param menuText the menu text
+ * @param eventClassname the event classname
+ */
+ public VSCreateTask(String menuText, String eventClassname) {
+ this.menuText = menuText;
+ this.eventClassname = eventClassname;
+ }
+
+ /**
+ * Instantiates a new VSCreateTask dummy object.
+ *
+ * @param menuText the menu text
+ */
+ public VSCreateTask(String menuText) {
+ this.menuText = menuText;
+ this.eventClassname = null;
+ }
+
+ /**
+ * Sets if it is a protocol activation task.
+ *
+ * @param isProtocolActivation true, if it is a protocol activation
+ * task.
+ */
+ public void isProtocolActivation(boolean isProtocolActivation) {
+ this.isProtocolActivation = isProtocolActivation;
+
+ if (isProtocolActivation)
+ isProtocolDeactivation(false);
+ }
+
+ /**
+ * Sets if it is a protocol deactivation task.
+ *
+ * @param isProtocolDeactivation true, if it is a protocol deactivation
+ * task.
+ */
+ public void isProtocolDeactivation(boolean isProtocolDeactivation) {
+ this.isProtocolDeactivation = isProtocolDeactivation;
+
+ if (isProtocolDeactivation)
+ isProtocolActivation(false);
+ }
+
+ /**
+ * Sets if it is a client protocol.
+ *
+ * @param isClientProtocol the is client protocol
+ */
+ public void isClientProtocol(boolean isClientProtocol) {
+ this.isClientProtocol = isClientProtocol;
+ }
+
+ /**
+ * Sets if it is a client request.
+ *
+ * @param isRequest the is client request
+ */
+ public void isRequest(boolean isRequest) {
+ this.isRequest = isRequest;
+ }
+
+ /**
+ * Checks if it is a dummy object..
+ *
+ * @return true, if dummy
+ */
+ public boolean isDummy() {
+ return eventClassname == null;
+ }
+
+ /**
+ * Sets the protocol classname.
+ *
+ * @param protocolClassname the protocol classname
+ */
+ public void setProtocolClassname(String protocolClassname) {
+ this.protocolClassname = protocolClassname;
+ }
+
+ /**
+ * Sets the shortname.
+ *
+ * @param shortname the shortname
+ */
+ public void setShortname(String shortname) {
+ this.shortname = shortname;
+ }
+
+ /**
+ * Gets the create tasks menu text.
+ *
+ * @return The text
+ */
+ public String getMenuText() {
+ return menuText;
+ }
+
+ /**
+ * Creates the task.
+ *
+ * @param process the process
+ * @param time the time
+ * @param localTimedTask the local timed task
+ *
+ * @return the new task
+ */
+ public VSTask createTask(VSInternalProcess process, long time,
+ boolean localTimedTask) {
+ VSAbstractEvent event = null;
+
+ if (isRequest) {
+ event = process.getProtocolObject(eventClassname);
+
+ } else {
+ event = VSRegisteredEvents.createEventInstanceByClassname(
+ eventClassname, process);
+ }
+
+ event.init(process);
+ if (shortname != null)
+ event.setShortname(shortname);
+
+ if (isProtocolActivation || isProtocolDeactivation) {
+ VSProtocolEvent protocolEvent = (VSProtocolEvent) event;
+ protocolEvent.setProtocolClassname(protocolClassname);
+ protocolEvent.isProtocolActivation(isProtocolActivation);
+ protocolEvent.isClientProtocol(isClientProtocol);
+ }
+
+ return new VSTask(time, process, event, localTimedTask);
+ }
+}
+
diff --git a/src/main/java/simulator/VSLogging.java b/src/main/java/simulator/VSLogging.java
new file mode 100644
index 0000000..66cb563
--- /dev/null
+++ b/src/main/java/simulator/VSLogging.java
@@ -0,0 +1,201 @@
+package simulator;
+
+import java.util.ArrayList;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.swing.JTextArea;
+
+import utils.VSTools;
+
+/**
+ * The class VSLogging, an object of this class is responsible for the loging
+ * of text messages into the simulator's loging window.
+ *
+ * @author Paul C. Buetow
+ */
+public class VSLogging {
+ /** The loging area. */
+ private JTextArea logingArea;
+
+ /** The filter text. */
+ private String filterText;
+
+ /** The pause lines. Used for cacheing the loging if the loging is
+ * deactivated for a while
+ */
+ private ArrayList<StringBuffer> pauseLines;
+
+ /** The loging lines. */
+ private ArrayList<StringBuffer> logingLines;
+
+ /** The simulator canvas. */
+ private VSSimulatorVisualization simulatorVisualization;
+
+ /** The loging messages are filtered. */
+ private boolean isFiltered;
+
+ /** The loging is paused. */
+ private boolean isPaused;
+
+ /** The filter pattern. */
+ private Pattern filterPattern;
+
+ /**
+ * Instantiates a new VSLogging object.
+ */
+ public VSLogging() {
+ logingArea = new JTextArea(0, 0);
+ logingArea.setEditable(false);
+ logingArea.setLineWrap(true);
+ logingArea.setWrapStyleWord(true);
+ logingLines = new ArrayList<StringBuffer>();
+ pauseLines = new ArrayList<StringBuffer>();
+ filterText = "";
+ }
+
+ /**
+ * Sets the simulator canvas.
+ *
+ * @param sv the simulator canvas
+ */
+ public void setSimulatorCanvas(VSSimulatorVisualization sv) {
+ this.simulatorVisualization = sv;
+ }
+
+ /**
+ * Gets the loging area.
+ *
+ * @return the loging area
+ */
+ public JTextArea getLoggingArea() {
+ return logingArea;
+ }
+
+ /**
+ * Loggs a message using the global time.
+ *
+ * @param message the message
+ */
+ public void log(String message) {
+ if (simulatorVisualization == null)
+ log(message, 0);
+ else
+ log(message, simulatorVisualization.getTime());
+ }
+
+ /**
+ * Loggs a message using the specified time.
+ *
+ * @param message the message
+ * @param time the time
+ */
+ public synchronized void log(String message, long time) {
+ StringBuffer buffer = new StringBuffer();
+ buffer.append(VSTools.getTimeString(time));
+ buffer.append(": ");
+ buffer.append(message);
+
+ if (isPaused)
+ pauseLines.add(buffer);
+ else
+ logFiltered(buffer);
+ }
+
+ /**
+ * Sets if the loging is paused.
+ *
+ * @param isPaused true, if the loging is paused
+ */
+ public synchronized void isPaused(boolean isPaused) {
+ this.isPaused = isPaused;
+
+ if (!isPaused) {
+ for (StringBuffer buffer : pauseLines)
+ logFiltered(buffer);
+
+ pauseLines.clear();
+ }
+ }
+
+ /**
+ * If the loging is filtered, it's using the pattern matching.
+ *
+ * @param buffer the loging buffer to filter
+ */
+ private void logFiltered(StringBuffer buffer) {
+ logingLines.add(buffer);
+ if (!isFiltered) {
+ logingArea.append(buffer.toString()+"\n");
+ logingArea.setCaretPosition(
+ logingArea.getDocument().getLength());
+
+ } else if (filterPattern != null &&
+ filterPattern.matcher(buffer).find()) {
+ logingArea.append(buffer.toString()+"\n");
+ logingArea.setCaretPosition(
+ logingArea.getDocument().getLength());
+ }
+ }
+
+ /**
+ * Checks if the loging is filtered.
+ *
+ * @param isFiltered true, if the loging is filtered
+ */
+ public synchronized void isFiltered(boolean isFiltered) {
+ this.isFiltered = isFiltered;
+
+ if (!isFiltered)
+ setFilterText("");
+ else
+ filter();
+ }
+
+ /**
+ * Sets the filter text.
+ *
+ * @param filterText the new filter text
+ */
+ public synchronized void setFilterText(String filterText) {
+ this.filterText = filterText;
+ filter();
+ }
+
+ /**
+ * Clears the loging.
+ */
+ public synchronized void clear() {
+ logingLines.clear();
+ pauseLines.clear();
+ logingArea.setText("");
+ }
+
+ /**
+ * Filters the loging.
+ */
+ private void filter() {
+ try {
+ filterPattern = Pattern.compile(filterText);
+ StringBuffer buffer = new StringBuffer();
+
+ for (StringBuffer line : logingLines) {
+ if (isFiltered) {
+ Matcher matcher = filterPattern.matcher(line);
+ if (matcher.find()) {
+ buffer.append(line);
+ buffer.append("\n");
+ }
+ } else {
+ buffer.append(line);
+ buffer.append("\n");
+ }
+ }
+ logingArea.setText(buffer.toString());
+
+ } catch (Exception e) {
+ filterPattern = null;
+ logingArea.setText("");
+ }
+ }
+}
diff --git a/src/main/java/simulator/VSMain.java b/src/main/java/simulator/VSMain.java
new file mode 100644
index 0000000..34a21b7
--- /dev/null
+++ b/src/main/java/simulator/VSMain.java
@@ -0,0 +1,70 @@
+package simulator;
+
+import java.awt.Component;
+import java.util.Locale;
+
+import javax.swing.UIManager;
+
+import events.VSRegisteredEvents;
+import prefs.VSDefaultPrefs;
+import prefs.VSPrefs;
+
+/**
+ * The class VSMain. This class contains the static main method. The simulator
+ * starts here!
+ *
+ * @author Paul C. Buetow
+ */
+public class VSMain {
+ /** The global preferences */
+ public static VSPrefs prefs;
+
+ /**
+ * Instantiates a new VSMain object.
+ *
+ * @param prefs the prefs
+ */
+ public VSMain(VSPrefs prefs) {
+ init(prefs, null);
+ }
+
+ /**
+ * Instantiates a new VSMain object
+ *
+ * @param prefs the prefs
+ * @param relativeTo the component to open the window relative to
+ */
+ public VSMain(VSPrefs prefs, Component relativeTo) {
+ init(prefs, relativeTo);
+ }
+
+ /**
+ * Inits the VSMain object.
+ *
+ * @param prefs the prefs
+ * @param relativeTo the component to open the window relative to
+ */
+ private void init(VSPrefs prefs, Component relativeTo) {
+ //VSSimulatorFrame simulatorFrame =
+ VSMain.prefs = prefs;
+ new VSSimulatorFrame(prefs, relativeTo);
+ }
+
+ /**
+ * The main method.
+ *
+ * @param args the arguments
+ */
+ public static void main(String[] args) {
+ try {
+ UIManager.setLookAndFeel(
+ UIManager.getCrossPlatformLookAndFeelClassName());
+ } catch (Exception e) { }
+
+ Locale.setDefault(Locale.GERMAN);
+ javax.swing.JPopupMenu.setDefaultLightWeightPopupEnabled(false);
+ VSPrefs prefs = VSDefaultPrefs.init();
+ VSRegisteredEvents.init(prefs);
+ new VSMain(prefs);
+ }
+}
diff --git a/src/main/java/simulator/VSMenuItemStates.java b/src/main/java/simulator/VSMenuItemStates.java
new file mode 100644
index 0000000..941dbf5
--- /dev/null
+++ b/src/main/java/simulator/VSMenuItemStates.java
@@ -0,0 +1,109 @@
+package simulator;
+
+/**
+ * The class VSMenuItemStates. Used by the VSSimulator to update the
+ * "simulator" bar of the VSSimulatorFrame.
+ *
+ * @author Paul C. Buetow
+ */
+public class VSMenuItemStates {
+ /** The pause state. */
+ private volatile boolean pause;
+
+ /** The replay state. */
+ private volatile boolean replay;
+
+ /** The reset state. */
+ private volatile boolean reset;
+
+ /** The start state. */
+ private volatile boolean start;
+
+ /**
+ * Instantiates a new VSMenuItemStates object.
+ *
+ * @param pause the pause state
+ * @param replay the replay state
+ * @param reset the reset state
+ * @param start the start state
+ */
+ public VSMenuItemStates(boolean pause, boolean replay, boolean reset,
+ boolean start) {
+ this.pause = pause;
+ this.replay = replay;
+ this.reset = reset;
+ this.start = start;
+ }
+
+ /**
+ * Sets the pause state.
+ *
+ * @param pause the new pause state
+ */
+ public void setPause(boolean pause) {
+ this.pause = pause;
+ }
+
+ /**
+ * Sets the replay state.
+ *
+ * @param replay the new replay state
+ */
+ public void setReplay(boolean replay) {
+ this.replay = replay;
+ }
+
+ /**
+ * Sets the reset state.
+ *
+ * @param reset the new reset state
+ */
+ public void setReset(boolean reset) {
+ this.reset = reset;
+ }
+
+ /**
+ * Sets the start state.
+ *
+ * @param start the new start state
+ */
+ public void setStart(boolean start) {
+ this.start = start;
+ }
+
+ /**
+ * Gets the pause state.
+ *
+ * @return the pause state
+ */
+ public boolean getPause() {
+ return pause;
+ }
+
+ /**
+ * Gets the replay state.
+ *
+ * @return the replay state
+ */
+ public boolean getReplay() {
+ return replay;
+ }
+
+ /**
+ * Gets the reset state.
+ *
+ * @return the reset state
+ */
+ public boolean getReset() {
+ return reset;
+ }
+
+ /**
+ * Gets the start state.
+ *
+ * @return the start state
+ */
+ public boolean getStart() {
+ return start;
+ }
+}
diff --git a/src/main/java/simulator/VSSimulator.java b/src/main/java/simulator/VSSimulator.java
new file mode 100644
index 0000000..4965a71
--- /dev/null
+++ b/src/main/java/simulator/VSSimulator.java
@@ -0,0 +1,1536 @@
+package simulator;
+
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.GridBagLayout;
+import java.awt.GridLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Vector;
+
+import javax.swing.AbstractButton;
+import javax.swing.AbstractCellEditor;
+import javax.swing.BoxLayout;
+import javax.swing.ButtonModel;
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JComboBox;
+import javax.swing.JLabel;
+import javax.swing.JMenuItem;
+import javax.swing.JPanel;
+import javax.swing.JPopupMenu;
+import javax.swing.JScrollPane;
+import javax.swing.JSplitPane;
+import javax.swing.JTabbedPane;
+import javax.swing.JTable;
+import javax.swing.JTextArea;
+import javax.swing.JTextField;
+import javax.swing.ListSelectionModel;
+import javax.swing.SwingUtilities;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
+import javax.swing.table.AbstractTableModel;
+import javax.swing.table.TableCellEditor;
+import javax.swing.table.TableColumn;
+
+import core.VSInternalProcess;
+import core.VSTask;
+import core.VSTaskManager;
+import events.VSRegisteredEvents;
+import exceptions.VSNegativeNumberException;
+import prefs.VSPrefs;
+import prefs.editors.VSProcessEditor;
+import serialize.VSSerializable;
+import serialize.VSSerialize;
+
+/**
+ * The class VSSimulator, an object of this class represents a whole simulator.
+ * It may be, that several parallel simulators exist. They are independent
+ * fron each other.
+ *
+ * @author Paul C. Buetow
+ */
+public class VSSimulator extends JPanel implements VSSerializable {
+ /** The serial version uid */
+ private static final long serialVersionUID = 1L;
+
+ /** The global text fields. */
+ private ArrayList<String> globalTextFields;
+
+ /** The local text fields. */
+ private ArrayList<String> localTextFields;
+
+ /** The create tasks array list. */
+ private ArrayList<VSCreateTask> createTasks;
+
+ /** The filter active check box. */
+ private JCheckBox filterActiveCheckBox;
+
+ /** The lamport active check box. */
+ private JCheckBox lamportActiveCheckBox;
+
+ /** The vector time active check box. */
+ private JCheckBox vectorTimeActiveCheckBox;
+
+ /** The global pid combo box. */
+ private JComboBox<String> globalPIDComboBox;
+
+ /** The local pid combo box. */
+ private JComboBox<String> localPIDComboBox;
+
+ /** The processes combo box. */
+ private JComboBox<String> processesComboBox;
+
+ /** The local add panel. */
+ private JPanel localAddPanel;
+
+ /** The local panel. */
+ private JPanel localPanel;
+
+ /** The loging panel. */
+ private JPanel logingPanel;
+
+ /** The split pane1. */
+ private JSplitPane splitPane1;
+
+ /** The split pane h. */
+ private JSplitPane splitPaneH;
+
+ /** The split pane v. */
+ private JSplitPane splitPaneV;
+
+ /** The tabbed pane. */
+ private JTabbedPane tabbedPane;
+
+ /** The loging area. */
+ private JTextArea logingArea;
+
+ /** The filter text field. */
+ private JTextField filterTextField;
+
+ /** The global text field. */
+ private JTextField globalTextField;
+
+ /** The local text field. */
+ private JTextField localTextField;
+
+ /** The thread. */
+ private Thread thread;
+
+ /** The loging. */
+ private VSLogging loging;
+
+ /** The menu item states. */
+ private VSMenuItemStates menuItemStates;
+
+ /** The prefs. */
+ private VSPrefs prefs;
+
+ /** The simulator canvas. */
+ private VSSimulatorVisualization simulatorVisualization;
+
+ /** The simulator frame. */
+ private VSSimulatorFrame simulatorFrame;
+
+ /** The task manager. */
+ private VSTaskManager taskManager;
+
+ /** The task manager global model. */
+ private VSTaskManagerTableModel taskManagerGlobalModel;
+
+ /** The task manager local model. */
+ private VSTaskManagerTableModel taskManagerLocalModel;
+
+ /** The task manager global editor. */
+ private VSTaskManagerCellEditor taskManagerGlobalEditor;
+
+ /** The task manager local editor. */
+ private VSTaskManagerCellEditor taskManagerLocalEditor;
+
+ /** The last selected process num. */
+ private int lastSelectedProcessNum;
+
+ /** The last expert state. */
+ private boolean lastExpertState;
+
+ /** The simulator counter. */
+ private static int simulatorCounter;
+
+ /** The simulator num. */
+ private static volatile int simulatorNum;
+
+ /**
+ * The class VSTaskManagerTableModel, an object of this class handles
+ * the task manager's JTable.
+ */
+ private class VSTaskManagerTableModel extends AbstractTableModel
+ implements MouseListener {
+ /** the serial version uid */
+ private static final long serialVersionUID = 1l;
+
+ /** The Constant LOCAL. */
+ public static final boolean LOCAL = true;
+
+ /** The Constant GLOBAL. */
+ public static final boolean GLOBAL = false;
+
+ /** The Constant ALL_PROCESSES. */
+ // public static final boolean ALL_PROCESSES = true;
+
+ /** The Constant ONE_PROCESS. */
+ public static final boolean ONE_PROCESS = false;
+
+ /** The tasks. */
+ private ArrayList<VSTask> tasks;
+
+ /** The column names. */
+ private String columnNames[];
+
+ /** The num columns. */
+ private int numColumns;
+
+ /** The table. */
+ //private JTable table;
+
+ /** The editor. */
+ //private VSTaskManagerCellEditor editor;
+
+ /**
+ * Instantiates a new VSTaskManagerTableModel object
+ *
+ * @param process the process
+ * @param localTask true, if this table manages the local task. false,
+ * if this table manages the global tasks.
+ */
+ public VSTaskManagerTableModel(VSInternalProcess process,
+ boolean localTask) {
+ tasks = new ArrayList<VSTask>();
+ set(process, localTask, ONE_PROCESS);
+ columnNames = new String[3];
+ columnNames[0]= prefs.getString("lang.time") + " (ms)";
+ columnNames[1] = prefs.getString("lang.process.id");
+ columnNames[2] = prefs.getString("lang.event");
+ numColumns = 3;
+ }
+
+ /**
+ * Sets the table.
+ *
+ * @param table the table
+ */
+ public void setTable(JTable table) {
+ /* Maybe needed for future usage */
+ //this.table = table;
+ }
+
+ /**
+ * Sets the editor.
+ *
+ * @param editor the editor
+ */
+ public void setEditor(VSTaskManagerCellEditor editor) {
+ /* Maybe needed for future usage */
+ //this.editor = editor;
+ }
+
+ /**
+ * Sets new values.
+ *
+ * @param process the process
+ * @param localTasks true, if this table manages the local tasks. false
+ * if this table manages the global tasks.
+ * @param allProcesses true, if this table shows tasks of all processes.
+ * false, if this table only shows tasks of the specified process.
+ */
+ public void set(VSInternalProcess process, boolean localTasks,
+ boolean allProcesses) {
+
+ if (allProcesses) {
+ this.tasks = localTasks
+ ? taskManager.getLocalTasks()
+ : taskManager.getGlobalTasks();
+ } else {
+ this.tasks = localTasks
+ ? taskManager.getProcessLocalTasks(process)
+ : taskManager.getProcessGlobalTasks(process);
+ }
+
+ Collections.sort(tasks);
+ fireTableDataChanged();
+ }
+
+ /* (non-Javadoc)
+ * @see javax.swing.table.AbstractTableModel#getColumnName(int)
+ */
+ public String getColumnName(int col) {
+ return columnNames[col];
+ }
+
+ /* (non-Javadoc)
+ * @see javax.swing.table.TableModel#getRowCount()
+ */
+ public int getRowCount() {
+ return tasks == null ? 0 : tasks.size();
+ }
+
+ /* (non-Javadoc)
+ * @see javax.swing.table.TableModel#getColumnCount()
+ */
+ public int getColumnCount() {
+ return numColumns;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.swing.table.TableModel#getValueAt(int, int)
+ */
+ public Object getValueAt(int row, int col) {
+ VSTask task = tasks.get(row);
+
+ switch (col) {
+ case 0:
+ return task.getTaskTime();
+ case 1:
+ return task.getProcess().getProcessID();
+ }
+
+ return task.getEvent().getShortname();
+ }
+
+ /* (non-Javadoc)
+ * @see javax.swing.table.AbstractTableModel#isCellEditable(int, int)
+ */
+ public boolean isCellEditable(int row, int col) {
+ if (col == 2)
+ return false;
+
+ return true;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.swing.table.AbstractTableModel#setValueAt(
+ * java.lang.Object, int, int)
+ */
+ public void setValueAt(Object value, int row, int col) {
+ }
+
+ /**
+ * Adds the task.
+ *
+ * @param task the task
+ */
+ public void addTask(VSTask task) {
+ tasks.add(task);
+ Collections.sort(tasks);
+ fireTableDataChanged();
+ }
+
+ /**
+ * Removes the task at a specified row.
+ *
+ * @param row the row
+ * @return The removed task
+ */
+ public VSTask removeTaskAtRow(int row) {
+ VSTask task = tasks.get(row);
+ tasks.remove(task);
+ taskManager.removeTask(task);
+ fireTableDataChanged();
+ return task;
+ }
+
+ /**
+ * Checks if a specific row exists
+ *
+ * @param row the row
+ * @return True, if the row exists. False, if not
+ */
+ public boolean rowExists(int row) {
+ if (row < 0)
+ return false;
+
+ if (tasks.size() <= row)
+ return false;
+
+ return true;
+ }
+
+ /**
+ * Gets the index of a specific task
+ *
+ * @param task The task
+ * @return The index of the task
+ */
+ public int getIndexOf(VSTask task) {
+ return tasks.indexOf(task);
+ }
+
+ /**
+ * Copies the tasks at a specified rows.
+ *
+ * @param rows the rows
+ */
+ private void copyTasksAtRows(int rows[]) {
+ ArrayList<VSTask> copiedTasks = new ArrayList<VSTask>();
+
+ for (int row : rows)
+ /* Use the copy constructor */
+ copiedTasks.add(new VSTask(tasks.get(row)));
+
+ for (VSTask task : copiedTasks) {
+ taskManager.addTask(task, VSTaskManager.PROGRAMMED);
+ addTask(task);
+ }
+
+ fireTableDataChanged();
+ }
+
+ /* (non-Javadoc)
+ * @see java.awt.event.MouseListener#mouseClicked(
+ * java.awt.event.MouseEvent)
+ */
+ public void mouseClicked(MouseEvent me) {
+ final JTable source = (JTable) me.getSource();
+ //final int row = source.rowAtPoint(me.getPoint());
+ //final int col = source.columnAtPoint(me.getPoint());
+
+ if (SwingUtilities.isRightMouseButton(me)) {
+ ActionListener actionListener = new ActionListener() {
+ public void actionPerformed(ActionEvent ae) {
+ String command = ae.getActionCommand();
+ int rows[] = source.getSelectedRows();
+
+ if (command.equals(prefs.getString("lang.remove"))) {
+ for (int i = rows.length - 1; i >= 0; --i)
+ removeTaskAtRow(rows[i]);
+
+ } else if (command.equals(
+ prefs.getString("lang.copy"))) {
+ copyTasksAtRows(rows);
+ }
+ }
+ };
+
+ JPopupMenu popup = new JPopupMenu();
+ JMenuItem item = new JMenuItem(prefs.getString("lang.remove"));
+ item.addActionListener(actionListener);
+ popup.add(item);
+
+ item = new JMenuItem(prefs.getString("lang.copy"));
+ item.addActionListener(actionListener);
+ popup.add(item);
+
+ popup.show(me.getComponent(), me.getX(), me.getY());
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see java.awt.event.MouseListener#mouseEntered(
+ * java.awt.event.MouseEvent)
+ */
+ public void mouseEntered(MouseEvent me) { }
+
+ /* (non-Javadoc)
+ * @see java.awt.event.MouseListener#mouseExited(
+ * java.awt.event.MouseEvent)
+ */
+ public void mouseExited(MouseEvent me) { }
+
+ /* (non-Javadoc)
+ * @see java.awt.event.MouseListener#mousePressed(
+ * java.awt.event.MouseEvent)
+ */
+ public void mousePressed(MouseEvent me) { }
+
+ /* (non-Javadoc)
+ * @see java.awt.event.MouseListener#mouseReleased(
+ * java.awt.event.MouseEvent)
+ */
+ public void mouseReleased(MouseEvent me) { }
+ }
+
+ /**
+ * The class VSTaskManagerCellEditor, an object of this class handles
+ * the task manager's JTable editor
+ */
+ private class VSTaskManagerCellEditor extends AbstractCellEditor
+ implements TableCellEditor {
+ /** the serial version uid */
+ private static final long serialVersionUID = 1L;
+
+ /** The JTable model */
+ private VSTaskManagerTableModel model;
+
+ /**
+ * Instantiates a new VSTaskManagerCellEditor object.
+ *
+ * @param model the model
+ */
+ public VSTaskManagerCellEditor(VSTaskManagerTableModel model) {
+ this.model = model;
+ model.setEditor(this);
+ }
+
+ /**
+ * Stops editing
+ */
+ public void stopEditing() {
+ fireEditingStopped();
+ }
+
+ /**
+ /* (non-Javadoc)
+ * @see javax.swing.table.TableCellEditor#getTableCellEditorComponent(
+ * javax.swing.JTable, java.lang.Object, boolean, int, int)
+ */
+ public Component getTableCellEditorComponent(final JTable table,
+ Object object,
+ boolean isSelected,
+ final int row,
+ final int col) {
+ switch (col) {
+ case 0:
+ Long val = (Long) model.getValueAt(row, col);
+ final JTextField valField = new JTextField(val.toString());
+ valField.setBackground(Color.WHITE);
+ valField.setBorder(null);
+ valField.addActionListener(new ActionListener() {
+ private boolean isRed = false;
+ public void actionPerformed(ActionEvent ae) {
+ try {
+ Long val = Long.valueOf(valField.getText());
+ if (val.longValue() < 0)
+ throw new VSNegativeNumberException();
+ VSTask task = model.removeTaskAtRow(row);
+ task.setTaskTime(val.longValue());
+ taskManager.addTask(task, VSTaskManager.PROGRAMMED);
+ model.addTask(task);
+ if (isRed) {
+ valField.setBackground(Color.WHITE);
+ isRed = false;
+ }
+ int index = model.getIndexOf(task);
+ ListSelectionModel selectionModel =
+ table.getSelectionModel();
+ selectionModel.setSelectionInterval(index, index);
+ fireEditingStopped();
+
+ } catch (NumberFormatException exc) {
+ valField.setBackground(Color.RED);
+ isRed = true;
+
+ } catch (VSNegativeNumberException exc) {
+ valField.setBackground(Color.RED);
+ isRed = true;
+ }
+ }
+ });
+ return valField;
+ case 1:
+ Integer current[] = { (Integer) model.getValueAt(row, col) };
+ final JComboBox<Integer> comboBox = new JComboBox<>(current);
+
+ Integer pids[] = simulatorVisualization.getProcessIDs();
+ for (Integer pid : pids)
+ comboBox.addItem(pid);
+
+ comboBox.setSelectedIndex(0);
+ comboBox.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent ae) {
+ int index = comboBox.getSelectedIndex() - 1;
+ if (model.rowExists(row)) {
+ VSTask task = model.removeTaskAtRow(row);
+ VSInternalProcess process =
+ simulatorVisualization.getProcess(index);
+ task.setProcess(process);
+ taskManager.addTask(task, VSTaskManager.PROGRAMMED);
+ if (allProcessesAreSelected())
+ model.addTask(task);
+ }
+
+ fireEditingStopped();
+ }
+ });
+
+ return comboBox;
+ case 2:
+ break;
+ }
+
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.swing.CellEditor#getCellEditorValue()
+ */
+ public Object getCellEditorValue() {
+ return new String("");
+ }
+ }
+
+
+ /**
+ * Instantiates a new VSSimulator object.
+ *
+ * @param prefs the prefs
+ * @param simulatorFrame the simulator frame
+ */
+ public VSSimulator(VSPrefs prefs, VSSimulatorFrame simulatorFrame) {
+ init(prefs, simulatorFrame);
+ }
+
+ /**
+ * inits the VSSimulator object.
+ *
+ * @param prefs the prefs
+ * @param simulatorFrame the simulator frame
+ */
+ private void init(VSPrefs prefs, VSSimulatorFrame simulatorFrame) {
+ this.prefs = prefs;
+ this.simulatorFrame = simulatorFrame;
+ simulatorNum = ++simulatorCounter;
+ this.menuItemStates = new VSMenuItemStates(false, false, false, true);
+ this.localTextFields = new ArrayList<String>();
+ this.globalTextFields = new ArrayList<String>();
+
+ /* Not null if init has been called from the deserialization */
+ if (this.loging == null)
+ this.loging = new VSLogging();
+
+ loging.log(prefs.getString("lang.simulator.new"));
+
+ fillContentPane();
+ updateFromPrefs();
+
+ splitPaneH.setDividerLocation(
+ prefs.getInteger("div.window.splitsize"));
+
+ splitPaneV.setDividerLocation(
+ prefs.getInteger("div.window.ysize")
+ - prefs.getInteger("div.window.logsize"));
+
+ splitPane1.setDividerLocation((int) (getPaintSize()/2) - 20);
+
+ int numProcesses = simulatorVisualization.getNumProcesses();
+ for (int i = 0; i <= numProcesses; ++i) {
+ localTextFields.add("0000");
+ globalTextFields.add("0000");
+ }
+
+ processesComboBox.setSelectedIndex(0);
+ localPIDComboBox.setSelectedIndex(0);
+ globalPIDComboBox.setSelectedIndex(0);
+
+ thread = new Thread(simulatorVisualization);
+ thread.start();
+ }
+
+ /**
+ * Fills the content pane.
+ */
+ private void fillContentPane() {
+ logingArea = loging.getLoggingArea();
+
+ splitPaneH = new JSplitPane();
+ splitPaneV = new JSplitPane();
+
+ /* Not null if init has been called from the deserialization */
+ if (this.simulatorVisualization == null)
+ simulatorVisualization = new VSSimulatorVisualization(
+ prefs, this, loging);
+
+ taskManager = simulatorVisualization.getTaskManager();
+ loging.setSimulatorCanvas(simulatorVisualization);
+
+ JPanel canvasPanel = new JPanel();
+ canvasPanel.setLayout(new GridLayout(1, 1, 3, 3));
+ canvasPanel.add(simulatorVisualization);
+ canvasPanel.setMinimumSize(new Dimension(0, 0));
+ canvasPanel.setMaximumSize(new Dimension(0, 0));
+
+ logingPanel = new JPanel(new BorderLayout());
+ logingPanel.add(new JScrollPane(logingArea), BorderLayout.CENTER);
+ logingPanel.add(createToolsPanel(), BorderLayout.SOUTH);
+ logingPanel.setPreferredSize(new Dimension(200, 1));
+
+ splitPaneH.setOrientation(JSplitPane.HORIZONTAL_SPLIT);
+ splitPaneH.setLeftComponent(createProcessPanel());
+ splitPaneH.setRightComponent(canvasPanel);
+ splitPaneH.setContinuousLayout(true);
+ splitPaneH.setOneTouchExpandable(true);
+
+ splitPaneV.setOrientation(JSplitPane.VERTICAL_SPLIT);
+ splitPaneV.setTopComponent(splitPaneH);
+ splitPaneV.setBottomComponent(logingPanel);
+ splitPaneV.setContinuousLayout(true);
+
+ this.add(splitPaneV);
+ }
+
+ /**
+ * Creates the tools panel.
+ *
+ * @return the panel
+ */
+ private JPanel createToolsPanel() {
+ JPanel toolsPanel = new JPanel();
+ boolean expertMode = prefs.getBoolean("sim.mode.expert");
+
+ toolsPanel.setLayout(new BoxLayout(toolsPanel, BoxLayout.X_AXIS));
+ JCheckBox expertActiveCheckBox =
+ new JCheckBox(prefs.getString("lang.mode.expert"));
+
+ expertActiveCheckBox.setSelected(expertMode);
+ expertActiveCheckBox.addChangeListener(new ChangeListener() {
+ public void stateChanged(ChangeEvent ce) {
+ AbstractButton abstractButton =
+ (AbstractButton) ce.getSource();
+ ButtonModel buttonModel = abstractButton.getModel();
+ boolean newState = buttonModel.isSelected();
+ if (lastExpertState != newState) {
+ lastExpertState = newState;
+ prefs.setBoolean("sim.mode.expert", newState);
+ fireExpertModeChanged();
+ }
+ }
+ });
+ toolsPanel.add(expertActiveCheckBox);
+
+ if (expertMode) {
+ lamportActiveCheckBox = new JCheckBox(
+ prefs.getString("lang.time.lamport"));
+ lamportActiveCheckBox.setSelected(false);
+ lamportActiveCheckBox.addChangeListener(new ChangeListener() {
+ public void stateChanged(ChangeEvent ce) {
+ AbstractButton abstractButton =
+ (AbstractButton) ce.getSource();
+ ButtonModel buttonModel = abstractButton.getModel();
+ simulatorVisualization.showLamport(
+ buttonModel.isSelected());
+ if (buttonModel.isSelected())
+ vectorTimeActiveCheckBox.setSelected(false);
+ }
+ });
+ toolsPanel.add(lamportActiveCheckBox);
+
+ vectorTimeActiveCheckBox = new JCheckBox(
+ prefs.getString("lang.time.vector"));
+ vectorTimeActiveCheckBox.setSelected(false);
+ vectorTimeActiveCheckBox.addChangeListener(new ChangeListener() {
+ public void stateChanged(ChangeEvent ce) {
+ AbstractButton abstractButton =
+ (AbstractButton) ce.getSource();
+ ButtonModel buttonModel = abstractButton.getModel();
+ simulatorVisualization.showVectorTime(
+ buttonModel.isSelected());
+ if (buttonModel.isSelected())
+ lamportActiveCheckBox.setSelected(false);
+ }
+ });
+ toolsPanel.add(vectorTimeActiveCheckBox);
+
+ JCheckBox antiAliasing = new JCheckBox(
+ prefs.getString("lang.antialiasing"));
+ antiAliasing.setSelected(false);
+ antiAliasing.addChangeListener(new ChangeListener() {
+ public void stateChanged(ChangeEvent ce) {
+ AbstractButton abstractButton =
+ (AbstractButton) ce.getSource();
+ ButtonModel buttonModel = abstractButton.getModel();
+ simulatorVisualization.isAntiAliased(
+ buttonModel.isSelected());
+ }
+ });
+ toolsPanel.add(antiAliasing);
+ }
+
+ JCheckBox logingActiveCheckBox = new JCheckBox(
+ prefs.getString("lang.loging.active"));
+ logingActiveCheckBox.setSelected(true);
+ logingActiveCheckBox.addChangeListener(new ChangeListener() {
+ public void stateChanged(ChangeEvent ce) {
+ AbstractButton abstractButton =
+ (AbstractButton) ce.getSource();
+ ButtonModel buttonModel = abstractButton.getModel();
+ loging.isPaused(!buttonModel.isSelected());
+ }
+ });
+ toolsPanel.add(logingActiveCheckBox);
+
+ if (expertMode) {
+ filterActiveCheckBox = new JCheckBox(
+ prefs.getString("lang.filter"));
+ filterActiveCheckBox.setSelected(false);
+ filterActiveCheckBox.addChangeListener(new ChangeListener() {
+ public void stateChanged(ChangeEvent ce) {
+ AbstractButton abstractButton =
+ (AbstractButton) ce.getSource();
+ ButtonModel buttonModel = abstractButton.getModel();
+ loging.isFiltered(buttonModel.isSelected());
+ if (buttonModel.isSelected())
+ loging.setFilterText(filterTextField.getText());
+ }
+ });
+ toolsPanel.add(filterActiveCheckBox);
+
+ filterTextField = new JTextField();
+ filterTextField.getDocument().addDocumentListener(
+ new DocumentListener() {
+ public void insertUpdate(DocumentEvent de) {
+ loging.setFilterText(filterTextField.getText());
+ }
+ public void removeUpdate(DocumentEvent de) {
+ loging.setFilterText(filterTextField.getText());
+ }
+ public void changedUpdate(DocumentEvent de) {
+ loging.setFilterText(filterTextField.getText());
+ }
+ });
+ toolsPanel.add(filterTextField);
+
+ JButton clearButton = new JButton(
+ prefs.getString("lang.loging.clear"));
+ clearButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent ae) {
+ String command = ae.getActionCommand();
+ if (command.equals(
+ prefs.getString("lang.loging.clear"))) {
+ loging.clear();
+ }
+ }
+ });
+ toolsPanel.add(clearButton);
+ }
+
+ return toolsPanel;
+ }
+
+ /**
+ * Creates the process panel.
+ *
+ * @return the panel
+ */
+ private JPanel createProcessPanel() {
+ JPanel editPanel = new JPanel(new GridBagLayout());
+ boolean expertMode = prefs.getBoolean("sim.mode.expert");
+ editPanel.setLayout(new BoxLayout(editPanel, BoxLayout.Y_AXIS));
+
+ processesComboBox = new JComboBox<>();
+ localPIDComboBox = new JComboBox<>();
+ globalPIDComboBox = new JComboBox<>();
+
+ lastSelectedProcessNum = 0;
+ int numProcesses = simulatorVisualization.getNumProcesses();
+ String processString = prefs.getString("lang.process");
+
+ for (int i = 0; i < numProcesses; ++i) {
+ int pid = simulatorVisualization.getProcess(i).getProcessID();
+ processesComboBox.addItem(processString + " " + pid);
+ localPIDComboBox.addItem("PID: " + pid);
+ globalPIDComboBox.addItem("PID: " + pid);
+ }
+
+ processesComboBox.addItem(prefs.getString("lang.processes.all"));
+ localPIDComboBox.addItem(prefs.getString("lang.all"));
+ globalPIDComboBox.addItem(prefs.getString("lang.all"));
+
+ tabbedPane = new JTabbedPane(JTabbedPane.TOP,
+ JTabbedPane.WRAP_TAB_LAYOUT);
+ localPanel = createTaskLabel(VSTaskManagerTableModel.LOCAL);
+ JPanel globalPanel = createTaskLabel(VSTaskManagerTableModel.GLOBAL);
+
+ splitPane1 = new JSplitPane();
+ splitPane1.setOrientation(JSplitPane.VERTICAL_SPLIT);
+ splitPane1.setTopComponent(localPanel);
+ splitPane1.setBottomComponent(globalPanel);
+ splitPane1.setOneTouchExpandable(true);
+
+ if (expertMode)
+ tabbedPane.addTab(prefs.getString("lang.events"), splitPane1);
+
+ else
+ tabbedPane.addTab(prefs.getString("lang.events"), localPanel);
+
+ processesComboBox.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent ae) {
+ localTextFields.set(lastSelectedProcessNum,
+ localTextField.getText());
+ globalTextFields.set(lastSelectedProcessNum,
+ globalTextField.getText());
+ updateTaskManagerTable();
+
+ int processNum = getSelectedProcessNum();
+ localTextField.setText(localTextFields.get(processNum));
+ globalTextField.setText(globalTextFields.get(processNum));
+ localTextField.setBackground(Color.WHITE);
+ globalTextField.setBackground(Color.WHITE);
+ lastSelectedProcessNum = processNum;
+
+ localPIDComboBox.setSelectedIndex(processNum);
+ globalPIDComboBox.setSelectedIndex(processNum);
+
+ if (processNum == simulatorVisualization.getNumProcesses()) {
+ tabbedPane.setEnabledAt(1, false);
+ if (tabbedPane.getSelectedIndex() == 1)
+ tabbedPane.setSelectedIndex(0);
+
+ } else if (!tabbedPane.isEnabledAt(1)) {
+ tabbedPane.setEnabledAt(1, true);
+ }
+
+ if (processNum != simulatorVisualization.getNumProcesses()) {
+ VSInternalProcess process = getSelectedProcess();
+ VSProcessEditor processEditor =
+ new VSProcessEditor(prefs, process);
+ tabbedPane.setComponentAt(1,
+ processEditor.getContentPane());
+ }
+ }
+ });
+
+ tabbedPane.add(prefs.getString("lang.variables"), null);
+
+ editPanel.add(processesComboBox);
+ editPanel.add(tabbedPane);
+
+ return editPanel;
+ }
+
+ /**
+ * Creates the label panel.
+ *
+ * @param text the text
+ *
+ * @return the panel
+ */
+ private JPanel createLabelPanel(String text) {
+ JPanel panel = new JPanel();
+ JLabel label = new JLabel(text);
+ panel.add(label);
+
+ return panel;
+ }
+
+ /**
+ * Creates the task label.
+ *
+ * @param localTasks true, if the local task label has to get created.
+ * false, if the global task label has to get created.
+ *
+ * @return the panel
+ */
+ private JPanel createTaskLabel(boolean localTasks) {
+ JPanel panel = new JPanel(new GridBagLayout());
+ panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
+
+ if (localTasks)
+ panel.add(createLabelPanel(prefs.getString("lang.timed.local")));
+ else
+ panel.add(createLabelPanel(prefs.getString("lang.timed.global")));
+
+ JScrollPane scrollPane = new JScrollPane(createTaskTable(localTasks));
+ panel.add(scrollPane);
+
+ if (localTasks)
+ localAddPanel = initAddPanel(panel, localTasks);
+ else
+ /*globalAddPanel = */ initAddPanel(panel, localTasks);
+
+ return panel;
+ }
+
+ /**
+ * Creates the task table.
+ *
+ * @param localTasks true, if the local task label has to get created.
+ * false, if the global task label has to get created.
+ *
+ * @return the table
+ */
+ private JTable createTaskTable(boolean localTasks) {
+ VSInternalProcess process = getSelectedProcess();
+ VSTaskManagerTableModel model =
+ new VSTaskManagerTableModel(process, localTasks);
+ VSTaskManagerCellEditor cellEditor =
+ new VSTaskManagerCellEditor(model);
+
+ if (localTasks) {
+ taskManagerLocalModel = model;
+ taskManagerLocalEditor = cellEditor;
+ } else {
+ taskManagerGlobalModel = model;
+ taskManagerGlobalEditor = cellEditor;
+ }
+
+ JTable table = new JTable(model);
+ table.setDefaultEditor(Object.class, cellEditor);
+ model.setTable(table);
+
+ table.addMouseListener(model);
+
+ TableColumn col = table.getColumnModel().getColumn(0);
+ col.setMaxWidth(62);
+ col.setResizable(false);
+
+ col = table.getColumnModel().getColumn(1);
+ col.setMaxWidth(40);
+ col.setResizable(false);
+
+ col = table.getColumnModel().getColumn(2);
+ col.sizeWidthToFit();
+ table.setBackground(Color.WHITE);
+
+ return table;
+ }
+
+ /**
+ * Inits the add panel.
+ *
+ * @param panel the panel
+ * @param localTasks true, if the local task label has to get created.
+ * false, if the global task label has to get created.
+ *
+ * @return the panel
+ */
+ private JPanel initAddPanel(JPanel panel, final boolean localTasks) {
+ JPanel addPanel = new JPanel();
+ addPanel.setLayout(new BoxLayout(addPanel, BoxLayout.X_AXIS));
+ boolean expertMode = prefs.getBoolean("sim.mode.expert");
+
+ final JTextField textField = new JTextField();
+ if (localTasks)
+ localTextField = textField;
+ else
+ globalTextField = textField;
+
+ textField.setText("0000");
+ textField.setBackground(Color.WHITE);
+ addPanel.add(textField);
+
+ addPanel.add(new JLabel(" ms "));
+
+ if (localTasks) {
+ if (expertMode)
+ addPanel.add(localPIDComboBox);
+ } else {
+ addPanel.add(globalPIDComboBox);
+ }
+
+ final JComboBox<String> comboBox = new JComboBox<>();
+ JButton takeoverButton = new JButton(prefs.getString("lang.takeover"));
+ takeoverButton.setMnemonic(prefs.getInteger("keyevent.takeover"));
+ takeoverButton.addActionListener(new ActionListener() {
+ private boolean isRed;
+ public void actionPerformed(ActionEvent ae) {
+ String textValue = textField.getText();
+ Long longValue = null;
+
+ try {
+ longValue = Long.valueOf(textValue);
+
+ if (longValue.longValue() < 0) {
+ makeRed();
+ return;
+ }
+
+ if (isRed) {
+ makeWhite();
+ }
+
+ } catch (NumberFormatException e) {
+ makeRed();
+ }
+
+ if (longValue == null)
+ return;
+
+ if (takeover(longValue.longValue())) {
+ if (isRed)
+ makeWhite();
+
+ } else {
+ makeRed();
+ }
+ }
+
+ private void makeWhite() {
+ textField.setBackground(Color.WHITE);
+ isRed = false;
+ }
+
+ private void makeRed() {
+ textField.setBackground(Color.RED);
+ isRed = true;
+ }
+
+ private boolean takeover(long time) {
+ VSInternalProcess selectedProcess = getSelectedProcess();
+ int index = comboBox.getSelectedIndex();
+ VSCreateTask createTask = createTasks.get(index);
+
+ if (createTask.isDummy())
+ return false;
+
+ ArrayList<VSInternalProcess> processes =
+ getConcernedProcesses(localTasks);
+
+ for (VSInternalProcess process : processes) {
+ VSTask task = createTask.createTask(process, time,
+ localTasks);
+ taskManager.addTask(task, VSTaskManager.PROGRAMMED);
+
+ if (selectedProcess == null ||
+ process.equals(selectedProcess)) {
+ if (localTasks)
+ taskManagerLocalModel.addTask(task);
+ else
+ taskManagerGlobalModel.addTask(task);
+ }
+ }
+
+ return true;
+ }
+ });
+
+ addPanel.add(takeoverButton);
+
+ boolean createTaskFlag = createTasks == null;
+ if (createTaskFlag) createTasks = new ArrayList<VSCreateTask>();
+
+ Vector<String> eventClassnames =
+ VSRegisteredEvents.getNonProtocolClassnames();
+
+ comboBox.setMaximumRowCount(20);
+ String menuText = prefs.getString("lang.events.process");
+ comboBox.addItem("----- " + menuText + " -----");
+
+ if (createTaskFlag)
+ createTasks.add(new VSCreateTask(menuText));
+
+ for (String eventClassname : eventClassnames) {
+ String eventShortname =
+ VSRegisteredEvents.getShortnameByClassname(eventClassname);
+ menuText = eventShortname;
+ comboBox.addItem(menuText);
+ if (createTaskFlag)
+ createTasks.add(new VSCreateTask(menuText, eventClassname));
+ }
+
+ String activate = prefs.getString("lang.activate");
+ String client = prefs.getString("lang.client");
+ String clientRequest = prefs.getString("lang.clientrequest.start");
+ String deactivate = prefs.getString("langactivate");
+ String server = prefs.getString("lang.server");
+ String serverRequest = prefs.getString("lang.serverrequest.start");
+ String protocol = prefs.getString("lang.protocol");
+
+ String protocolEventClassname = "events.internal.VSProtocolEvent";
+ eventClassnames = VSRegisteredEvents.getProtocolClassnames();
+
+ for (String eventClassname : eventClassnames) {
+ String eventShortname_ =
+ VSRegisteredEvents.getShortnameByClassname(eventClassname);
+ String eventShortname = null;
+
+ menuText = eventShortname_ + " " + protocol;
+ comboBox.addItem("----- " + menuText + " -----");
+
+ if (createTaskFlag)
+ createTasks.add(new VSCreateTask(menuText));
+
+ if (VSRegisteredEvents.isOnServerStartProtocol(eventClassname))
+ eventShortname = eventShortname_ + " " + serverRequest;
+ else
+ eventShortname = eventShortname_ + " " + clientRequest;
+
+ menuText = eventShortname;
+ comboBox.addItem(menuText);
+ if (createTaskFlag) {
+ VSCreateTask createTask = new VSCreateTask(menuText,
+ eventClassname);
+ createTask.setShortname(eventShortname);
+ createTask.isRequest(true);
+ createTasks.add(createTask);
+ }
+
+ eventShortname = eventShortname_ + " " + client + " " + activate;
+ menuText = eventShortname;
+ comboBox.addItem(menuText);
+ if (createTaskFlag) {
+ VSCreateTask createTask =
+ new VSCreateTask(menuText, protocolEventClassname);
+ createTask.isProtocolActivation(true);
+ createTask.isClientProtocol(true);
+ createTask.setProtocolClassname(eventClassname);
+ createTask.setShortname(eventShortname);
+ createTasks.add(createTask);
+ }
+
+ eventShortname = eventShortname_ + " " + client + " " + deactivate;
+ menuText = eventShortname;
+ comboBox.addItem(menuText);
+ if (createTaskFlag) {
+ VSCreateTask createTask =
+ new VSCreateTask(menuText, protocolEventClassname);
+ createTask.isProtocolDeactivation(true);
+ createTask.isClientProtocol(true);
+ createTask.setProtocolClassname(eventClassname);
+ createTask.setShortname(eventShortname);
+ createTasks.add(createTask);
+ }
+
+ eventShortname = eventShortname_ + " " + server + " " + activate;
+ menuText = eventShortname;
+ comboBox.addItem(menuText);
+ if (createTaskFlag) {
+ VSCreateTask createTask =
+ new VSCreateTask(menuText, protocolEventClassname);
+ createTask.isProtocolActivation(true);
+ createTask.isClientProtocol(false);
+ createTask.setProtocolClassname(eventClassname);
+ createTask.setShortname(eventShortname);
+ createTasks.add(createTask);
+ }
+
+ eventShortname = eventShortname_ + " " + server + " " + deactivate;
+ menuText = eventShortname;
+ comboBox.addItem(menuText);
+ if (createTaskFlag) {
+ VSCreateTask createTask =
+ new VSCreateTask(menuText, protocolEventClassname);
+ createTask.isProtocolDeactivation(true);
+ createTask.isClientProtocol(false);
+ createTask.setProtocolClassname(eventClassname);
+ createTask.setShortname(eventShortname);
+ createTasks.add(createTask);
+ }
+ }
+
+ panel.add(comboBox);
+ panel.add(addPanel);
+
+ return addPanel;
+ }
+
+ /**
+ * Gets the split size.
+ *
+ * @return the split size
+ */
+ public synchronized int getSplitSize() {
+ return splitPaneH.getDividerLocation();
+ }
+
+ /**
+ * Gets the paint size.
+ *
+ * @return the paint size
+ */
+ public synchronized int getPaintSize() {
+ return splitPaneV.getDividerLocation();
+ }
+
+ /**
+ * Gets the selected process num.
+ *
+ * @return the selected process num
+ */
+ private int getSelectedProcessNum() {
+ return processesComboBox.getSelectedIndex();
+ }
+
+ /**
+ * Checks if 'all processes' is selected
+ *
+ * @return True, if 'all processes' are selected, else false
+ */
+ private boolean allProcessesAreSelected() {
+ return processesComboBox.getSelectedIndex() + 1
+ == processesComboBox.getItemCount();
+ }
+
+ /**
+ * Gets the selected process.
+ *
+ * @return the selected process
+ */
+ private VSInternalProcess getSelectedProcess() {
+ int processNum = getSelectedProcessNum();
+ return simulatorVisualization.getProcess(processNum);
+ }
+
+ /**
+ * Gets the concerned processes.
+ *
+ * @param localTasks true, if this table manages the local tasks. false
+ * if this table manages the global tasks.
+ *
+ * @return the concerned processes
+ */
+ private ArrayList<VSInternalProcess> getConcernedProcesses(
+ boolean localTasks) {
+ int processNum = localTasks
+ ? localPIDComboBox.getSelectedIndex()
+ : globalPIDComboBox.getSelectedIndex();
+
+ if (processNum == simulatorVisualization.getNumProcesses())
+ return simulatorVisualization.getProcessesArray();
+
+ ArrayList<VSInternalProcess> arr = new ArrayList<VSInternalProcess>();
+ arr.add(simulatorVisualization.getProcess(processNum));
+
+ return arr;
+ }
+
+ /**
+ * Update task manager table.
+ */
+ public synchronized void updateTaskManagerTable() {
+ VSInternalProcess process = getSelectedProcess();
+ boolean allProcesses = process == null;
+
+ taskManagerLocalEditor.stopEditing();
+ taskManagerGlobalEditor.stopEditing();
+
+ taskManagerLocalModel.set(process,
+ VSTaskManagerTableModel.LOCAL,
+ allProcesses);
+
+ taskManagerGlobalModel.set(process,
+ VSTaskManagerTableModel.GLOBAL,
+ allProcesses);
+ }
+
+ /**
+ * Update the processes combo box
+ */
+ private void updateProcessesComboBox() {
+ int numProcesses = simulatorVisualization.getNumProcesses();
+ String processString = prefs.getString("lang.process");
+
+ for (int i = 0; i < numProcesses; ++i) {
+ int processID = simulatorVisualization.getProcess(i).getProcessID();
+
+ processesComboBox.removeItemAt(i);
+ localPIDComboBox.removeItemAt(i);
+ globalPIDComboBox.removeItemAt(i);
+
+ processesComboBox.insertItemAt(processString + " " + processID, i);
+ localPIDComboBox.insertItemAt("PID: " + processID, i);
+ globalPIDComboBox.insertItemAt("PID: " + processID, i);
+ }
+ }
+
+ /**
+ * The simulator has finished.
+ */
+ public synchronized void finish() {
+ menuItemStates.setStart(false);
+ menuItemStates.setPause(false);
+ menuItemStates.setReset(true);
+ menuItemStates.setReplay(true);
+ simulatorFrame.updateSimulatorMenu();
+ }
+
+ /**
+ * Gets the simulator num.
+ *
+ * @return the simulator num
+ */
+ public synchronized int getSimulatorNum() {
+ return simulatorNum;
+ }
+
+ /**
+ * Gets the menu item states.
+ *
+ * @return the menu item states
+ */
+ public synchronized VSMenuItemStates getMenuItemStates() {
+ return menuItemStates;
+ }
+
+ /**
+ * Gets the simulator canvas.
+ *
+ * @return the simulator canvas
+ */
+ public synchronized VSSimulatorVisualization getSimulatorCanvas() {
+ return simulatorVisualization;
+ }
+
+ /**
+ * Gets the simulator frame.
+ *
+ * @return the simulator frame
+ */
+ public synchronized VSSimulatorFrame getSimulatorFrame() {
+ return simulatorFrame;
+ }
+
+ /**
+ * Update from prefs.
+ */
+ public synchronized void updateFromPrefs() {
+ simulatorVisualization.setBackground(prefs.getColor("col.background"));
+ simulatorVisualization.updateFromPrefs();
+ }
+
+ /**
+ * Removes the process at a specified index.
+ *
+ * @param index the index
+ */
+ public synchronized void removedAProcessAtIndex(int index) {
+ if (lastSelectedProcessNum > index)
+ --lastSelectedProcessNum;
+
+ globalTextFields.remove(index);
+ localTextFields.remove(index);
+
+ globalPIDComboBox.removeItemAt(index);
+ localPIDComboBox.removeItemAt(index);
+
+ processesComboBox.removeItemAt(index);
+ simulatorFrame.updateEditMenu();
+
+ updateTaskManagerTable();
+ }
+
+ /**
+ * Adds the process at a specified index.
+ *
+ * @param index the index
+ */
+ public synchronized void addProcessAtIndex(int index) {
+ int processID = simulatorVisualization.getProcess(index).getProcessID();
+ String processString = prefs.getString("lang.process");
+
+ localTextFields.add(index, "0000");
+ globalTextFields.add(index, "0000");
+
+ localPIDComboBox.insertItemAt("PID: " + processID, index);
+ globalPIDComboBox.insertItemAt("PID: " + processID, index);
+
+ processesComboBox.insertItemAt(processString + " " + processID, index);
+ simulatorFrame.updateEditMenu();
+ }
+
+ /**
+ * Fire expert mode changed. Tell, that the expert mode has changed.
+ */
+ public synchronized void fireExpertModeChanged() {
+ boolean expertMode = prefs.getBoolean("sim.mode.expert");
+
+ /* Update the Task Manager GUI */
+ int selectedIndex = tabbedPane.getSelectedIndex();
+
+ if (expertMode) {
+ tabbedPane.remove(localPanel);
+ tabbedPane.insertTab(prefs.getString("lang.events"), null,
+ splitPane1, null, 0);
+ splitPane1.setTopComponent(localPanel);
+ //splitPane1.setDividerLocation((int) (getPaintSize()/2) - 20);
+
+ /* addPanel */
+ localAddPanel.add(localPIDComboBox, 2);
+
+ } else {
+ tabbedPane.remove(splitPane1);
+ tabbedPane.insertTab(prefs.getString("lang.events"), null,
+ localPanel, null, 0);
+
+ /* addPanel */
+ localAddPanel.remove(2);
+ }
+
+ tabbedPane.setSelectedIndex(selectedIndex);
+
+ /* Update the 'Variables tab' */
+ if (getSelectedProcessNum() !=
+ simulatorVisualization.getNumProcesses()) {
+ VSInternalProcess process = getSelectedProcess();
+ VSProcessEditor editor = new VSProcessEditor(prefs, process);
+ tabbedPane.setComponentAt(1, editor.getContentPane());
+ }
+
+ /* Update the tools panel */
+ logingPanel.remove(1);
+ logingPanel.add(createToolsPanel(), BorderLayout.SOUTH);
+ updateUI();
+ }
+
+ /**
+ * Gets the prefs.
+ *
+ * @return the prefs
+ */
+ public synchronized VSPrefs getPrefs() {
+ return prefs;
+ }
+
+ /**
+ * Gets the create tasks objects. Those objects are for creating new tasks
+ * via the task manager GUI or via right click on the paint area of the
+ * simulator canvas!
+ *
+ * @return The create tasks objects
+ */
+ ArrayList<VSCreateTask> getCreateTaskObjects() {
+ return createTasks;
+ }
+
+ /* (non-Javadoc)
+ * @see serialize.VSSerializable#serialize(serialize.VSSerialize,
+ * java.io.ObjectOutputStream)
+ */
+ public synchronized void serialize(VSSerialize serialize,
+ ObjectOutputStream objectOutputStream)
+ throws IOException {
+ /** For later backwards compatibility, to add more stuff */
+ objectOutputStream.writeObject(Boolean.valueOf(false));
+
+ simulatorVisualization.serialize(serialize, objectOutputStream);
+
+ /** For later backwards compatibility, to add more stuff */
+ objectOutputStream.writeObject(Boolean.valueOf(false));
+
+ }
+
+ /* (non-Javadoc)
+ * @see serialize.VSSerializable#deserialize(serialize.VSSerialize,
+ * java.io.ObjectInputStream)
+ */
+ public synchronized void deserialize(VSSerialize serialize,
+ ObjectInputStream objectInputStream)
+ throws IOException, ClassNotFoundException {
+ if (VSSerialize.DEBUG)
+ System.out.println("Deserializing: VSSimulator");
+
+ serialize.setObject("simulator", this);
+ serialize.setObject("loging", loging);
+
+ /** For later backwards compatibility, to add more stuff */
+ objectInputStream.readObject();
+
+ simulatorVisualization.deserialize(serialize, objectInputStream);
+
+ /** For later backwards compatibility, to add more stuff */
+ objectInputStream.readObject();
+
+ updateFromPrefs();
+ updateTaskManagerTable();
+ updateProcessesComboBox();
+ processesComboBox.setSelectedIndex(processesComboBox.getItemCount()-1);
+ }
+}
diff --git a/src/main/java/simulator/VSSimulatorFrame.java b/src/main/java/simulator/VSSimulatorFrame.java
new file mode 100644
index 0000000..3cf4e91
--- /dev/null
+++ b/src/main/java/simulator/VSSimulatorFrame.java
@@ -0,0 +1,628 @@
+package simulator;
+
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.Container;
+import java.awt.Dimension;
+import java.awt.GridLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.util.ArrayList;
+import java.util.Vector;
+
+import javax.swing.ImageIcon;
+import javax.swing.JButton;
+import javax.swing.JFrame;
+import javax.swing.JMenu;
+import javax.swing.JMenuBar;
+import javax.swing.JMenuItem;
+import javax.swing.JTabbedPane;
+import javax.swing.JToolBar;
+import javax.swing.KeyStroke;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+
+import core.VSInternalProcess;
+import prefs.VSDefaultPrefs;
+import prefs.VSPrefs;
+import prefs.editors.VSEditorFrame;
+import prefs.editors.VSSimulatorEditor;
+import serialize.VSSerialize;
+import utils.VSAboutFrame;
+import utils.VSFrame;
+
+/**
+ * The class VSSimulatorFrame, an object of this class represents a window
+ * of the simulator. The window can have several tabs. Each tab contains
+ * an independent simulator.
+ *
+ * @author Paul C. Buetow
+ */
+public class VSSimulatorFrame extends VSFrame {
+ /** The serial version uid */
+ private static final long serialVersionUID = 1L;
+
+ /** The pause item. */
+ private JMenuItem pauseItem;
+
+ /** The replay item. */
+ private JMenuItem replayItem;
+
+ /** The reset item. */
+ private JMenuItem resetItem;
+
+ /** The start item. */
+ private JMenuItem startItem;
+
+ /** The pause button. */
+ private JButton pauseButton;
+
+ /** The replay button. */
+ private JButton replayButton;
+
+ /** The reset button. */
+ private JButton resetButton;
+
+ /** The start button. */
+ private JButton startButton;
+
+ /** The menu edit. */
+ private JMenu menuEdit;
+
+ /** The menu file. */
+ private JMenu menuFile;
+
+ /** The close item. */
+ private JMenuItem closeItem;
+
+ /** The save item. */
+ private JMenuItem saveItem;
+
+ /** The save as item. */
+ private JMenuItem saveAsItem;
+
+ /** The menu simulator. */
+ private JMenu menuSimulator;
+
+ /** The tool bar. */
+ private JToolBar toolBar;
+
+ /** The prefs. */
+ private VSPrefs prefs;
+
+ /** The simulators. */
+ private Vector<VSSimulator> simulators;
+
+ /** The current simulator. */
+ private VSSimulator currentSimulator;
+
+ /** The tabbed pane. */
+ private JTabbedPane tabbedPane;
+
+ /** The action listener */
+ private ActionListener actionListener;
+
+ /**
+ * Instantiates a new VSSimulatorFrame object.
+ *
+ * @param prefs the prefs
+ * @param relativeTo the component to open the window relative to
+ */
+ public VSSimulatorFrame(VSPrefs prefs, Component relativeTo) {
+ super(prefs.getString("lang.name"), relativeTo);
+ this.prefs = prefs;
+ this.simulators = new Vector<VSSimulator>();
+
+ final VSPrefs finalPrefs = this.prefs;
+ actionListener = new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ Object source = e.getSource();
+ String sourceText = null;
+
+ if (source instanceof JMenuItem)
+ sourceText = ((JMenuItem) source).getText();
+ else
+ sourceText = ((ImageIcon) ((JButton) source).getIcon()).
+ getDescription();
+
+ if (sourceText.equals(
+ finalPrefs.getString("lang.simulator.close"))) {
+ removeCurrentSimulator();
+
+ } else if (sourceText.equals(
+ finalPrefs.getString("lang.simulator.new"))) {
+ VSPrefs newPrefs = VSDefaultPrefs.init();
+ VSSimulatorEditor simulatorEditor =
+ new VSSimulatorEditor(newPrefs, VSSimulatorFrame.this,
+ VSSimulatorEditor.OPENED_NEW_TAB);
+ new VSEditorFrame(newPrefs, VSSimulatorFrame.this,
+ simulatorEditor);
+
+ } else if (sourceText.equals(
+ finalPrefs.getString("lang.window.new"))) {
+ new VSMain(VSDefaultPrefs.init(),
+ VSSimulatorFrame.this);
+
+ } else if (sourceText.equals(
+ finalPrefs.getString("lang.window.close"))) {
+ dispose();
+
+ } else if (sourceText.equals(
+ finalPrefs.getString("lang.open"))) {
+ VSSerialize serialize = new VSSerialize();
+ serialize.openSimulator(VSSimulatorFrame.this);
+
+ } else if (sourceText.equals(
+ finalPrefs.getString("lang.save"))) {
+ VSSimulatorVisualization simulatorVisualization =
+ currentSimulator.getSimulatorCanvas();
+ boolean flag = !simulatorVisualization.isPaused()
+ && !simulatorVisualization.isResetted()
+ && !simulatorVisualization.hasFinished();
+
+ if (flag)
+ pauseCurrentSimulator();
+
+ VSSerialize serialize = new VSSerialize();
+ serialize.saveSimulator(VSSerialize.LAST_FILENAME,
+ currentSimulator);
+ if (flag)
+ startCurrentSimulator();
+
+ } else if (sourceText.equals(
+ finalPrefs.getString("lang.saveas"))) {
+ VSSimulatorVisualization simulatorVisualization =
+ currentSimulator.getSimulatorCanvas();
+ boolean flag = !simulatorVisualization.isPaused()
+ && !simulatorVisualization.isResetted()
+ && !simulatorVisualization.hasFinished();
+ if (flag)
+ pauseCurrentSimulator();
+
+ VSSerialize serialize = new VSSerialize();
+ serialize.saveSimulator(currentSimulator);
+
+ if (flag)
+ startCurrentSimulator();
+
+ } else if (sourceText.equals(
+ finalPrefs.getString("lang.about"))) {
+ new VSAboutFrame(finalPrefs, VSSimulatorFrame.this);
+
+ } else if (sourceText.equals(
+ finalPrefs.getString("lang.quit"))) {
+ System.exit(0);
+
+ } else if (sourceText.equals(
+ finalPrefs.getString("lang.start"))) {
+ startCurrentSimulator();
+
+ } else if (sourceText.equals(
+ finalPrefs.getString("lang.pause"))) {
+ pauseCurrentSimulator();
+
+ } else if (sourceText.equals(
+ finalPrefs.getString("lang.reset"))) {
+ resetCurrentSimulator();
+
+ } else if (sourceText.equals(
+ finalPrefs.getString("lang.replay"))) {
+ VSMenuItemStates menuItemState =
+ currentSimulator.getMenuItemStates();
+ menuItemState.setStart(false);
+ menuItemState.setPause(true);
+ menuItemState.setReset(false);
+ menuItemState.setReplay(true);
+ currentSimulator.getSimulatorCanvas().reset();
+ currentSimulator.getSimulatorCanvas().play();
+ updateSimulatorMenu();
+ }
+ }
+ };
+
+ setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
+
+ setSize(prefs.getInteger("div.window.xsize"),
+ prefs.getInteger("div.window.ysize"));
+
+ setJMenuBar(createMenuBar());
+ setLayout(new BorderLayout());
+ setContentPane(createContentPane());
+ setVisible(true);
+
+ pauseButton.setEnabled(false);
+ replayButton.setEnabled(false);
+ resetButton.setEnabled(false);
+ startButton.setEnabled(false);
+ menuEdit.setEnabled(false);
+ //menuFile.setEnabled(false);
+ closeItem.setEnabled(false);
+ saveItem.setEnabled(false);
+ saveAsItem.setEnabled(false);
+ menuSimulator.setEnabled(false);
+ }
+
+ /**
+ * Creates the menu bar.
+ *
+ * @return the j menu bar
+ */
+ private JMenuBar createMenuBar() {
+ /* File menu */
+ menuFile = new JMenu(prefs.getString("lang.file"));
+ menuFile.setMnemonic(prefs.getInteger("keyevent.file"));
+ JMenuItem menuItem;
+
+ menuItem = new JMenuItem(prefs.getString("lang.simulator.new"));
+ menuItem.setAccelerator(KeyStroke.getKeyStroke(
+ prefs.getInteger("keyevent.new"),
+ ActionEvent.ALT_MASK));
+ menuItem.addActionListener(actionListener);
+ menuFile.add(menuItem);
+
+ closeItem = new JMenuItem(
+ prefs.getString("lang.simulator.close"));
+ closeItem.setAccelerator(KeyStroke.getKeyStroke(
+ prefs.getInteger("keyevent.close"),
+ ActionEvent.ALT_MASK));
+ closeItem.addActionListener(actionListener);
+ menuFile.add(closeItem);
+
+ menuFile.addSeparator();
+
+ menuItem = new JMenuItem(prefs.getString("lang.window.new"));
+ menuItem.addActionListener(actionListener);
+ menuFile.add(menuItem);
+
+ menuItem = new JMenuItem(prefs.getString("lang.window.close"));
+ menuItem.addActionListener(actionListener);
+ menuFile.add(menuItem);
+
+ menuFile.addSeparator();
+
+ menuItem = new JMenuItem(prefs.getString("lang.open"));
+ menuItem.setAccelerator(KeyStroke.getKeyStroke(
+ prefs.getInteger("keyevent.open"),
+ ActionEvent.ALT_MASK));
+ menuItem.addActionListener(actionListener);
+ menuFile.add(menuItem);
+
+ saveItem = new JMenuItem(prefs.getString("lang.save"));
+ saveItem.setAccelerator(KeyStroke.getKeyStroke(
+ prefs.getInteger("keyevent.save"),
+ ActionEvent.ALT_MASK));
+ saveItem.addActionListener(actionListener);
+ menuFile.add(saveItem);
+
+ saveAsItem = new JMenuItem(prefs.getString("lang.saveas"));
+ saveAsItem.setAccelerator(KeyStroke.getKeyStroke(
+ prefs.getInteger("keyevent.saveas"),
+ ActionEvent.ALT_MASK));
+ saveAsItem.addActionListener(actionListener);
+ menuFile.add(saveAsItem);
+
+ menuFile.addSeparator();
+
+ menuItem = new JMenuItem(prefs.getString("lang.about"));
+ menuItem.addActionListener(actionListener);
+ menuFile.add(menuItem);
+
+ menuItem = new JMenuItem(prefs.getString("lang.quit"));
+ menuItem.addActionListener(actionListener);
+ menuFile.add(menuItem);
+
+ /* Edit menu */
+ menuEdit = new JMenu(
+ prefs.getString("lang.edit"));
+ menuEdit.setMnemonic(prefs.getInteger("keyevent.edit"));
+ updateEditMenu();
+
+ /* Simulator menu */
+ toolBar = new JToolBar();
+ menuSimulator = new JMenu(
+ prefs.getString("lang.simulator"));
+ menuSimulator.setMnemonic(prefs.getInteger("keyevent.simulator"));
+
+ resetItem = new JMenuItem(prefs.getString("lang.reset"));
+ resetItem.setAccelerator(KeyStroke.getKeyStroke(
+ prefs.getInteger("keyevent.reset"),
+ ActionEvent.ALT_MASK));
+ resetItem.addActionListener(actionListener);
+ resetItem.setEnabled(false);
+ menuSimulator.add(resetItem);
+ resetButton = new JButton(getImageIcon("reset.png",
+ prefs.getString("lang.reset")));
+ resetButton.addActionListener(actionListener);
+ toolBar.add(resetButton);
+
+ replayItem = new JMenuItem(
+ prefs.getString("lang.replay"));
+ replayItem.setAccelerator(KeyStroke.getKeyStroke(
+ prefs.getInteger("keyevent.replay"),
+ ActionEvent.ALT_MASK));
+ replayItem.addActionListener(actionListener);
+ replayItem.setEnabled(false);
+ menuSimulator.add(replayItem);
+ replayButton = new JButton(
+ getImageIcon("replay.png", prefs.getString("lang.replay")));
+ replayButton.addActionListener(actionListener);
+ toolBar.add(replayButton);
+
+ pauseItem = new JMenuItem(prefs.getString("lang.pause"));
+ pauseItem.setAccelerator(KeyStroke.getKeyStroke(
+ prefs.getInteger("keyevent.pause"),
+ ActionEvent.ALT_MASK));
+ pauseItem.addActionListener(actionListener);
+ menuSimulator.add(pauseItem);
+ pauseItem.setEnabled(false);
+ pauseButton = new JButton(getImageIcon("pause.png",
+ prefs.getString("lang.pause")));
+ pauseButton.addActionListener(actionListener);
+ toolBar.add(pauseButton);
+
+ startItem = new JMenuItem(prefs.getString("lang.start"));
+ startItem.setAccelerator(KeyStroke.getKeyStroke(
+ prefs.getInteger("keyevent.start"),
+ ActionEvent.ALT_MASK));
+ startItem.addActionListener(actionListener);
+ menuSimulator.add(startItem);
+ startButton = new JButton(getImageIcon("start.png",
+ prefs.getString("lang.start")));
+ startButton.addActionListener(actionListener);
+ toolBar.add(startButton);
+
+
+ JMenuBar mainMenuBar = new JMenuBar();
+ mainMenuBar.add(menuFile);
+ mainMenuBar.add(menuEdit);
+ mainMenuBar.add(menuSimulator);
+
+ return mainMenuBar;
+ }
+
+ /**
+ * Creates the content pane.
+ *
+ * @return the container
+ */
+ private Container createContentPane() {
+ Container pane = getContentPane();
+ tabbedPane = new JTabbedPane(JTabbedPane.BOTTOM,
+ JTabbedPane.SCROLL_TAB_LAYOUT);
+
+ tabbedPane.addChangeListener(new ChangeListener() {
+ public void stateChanged(ChangeEvent ce) {
+ JTabbedPane pane = (JTabbedPane) ce.getSource();
+ currentSimulator = (VSSimulator) pane.getSelectedComponent();
+ if (currentSimulator != null) {
+ currentSimulator.getSimulatorCanvas().paint();
+ updateEditMenu();
+ updateSimulatorMenu();
+ }
+ }
+ });
+
+ pane.add(toolBar, BorderLayout.PAGE_START);
+ pane.add(tabbedPane, BorderLayout.CENTER);
+
+ return pane;
+ }
+
+ /**
+ * Updates the edit menu. Called if another simulator tab has been selected
+ * or if processes have been added or removed.
+ */
+ public void updateEditMenu() {
+ menuEdit.removeAll();
+
+ JMenuItem globalPrefsItem = new JMenuItem(
+ prefs.getString("lang.prefs"));
+
+ globalPrefsItem.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent ae) {
+ VSPrefs simulatorPrefs = currentSimulator.getPrefs();
+ VSSimulatorEditor.TAKEOVER_BUTTON = true;
+ VSSimulatorEditor simulatorEditor = new VSSimulatorEditor(
+ simulatorPrefs, VSSimulatorFrame.this, currentSimulator);
+ new VSEditorFrame(prefs, VSSimulatorFrame.this,
+ simulatorEditor);
+ }
+ });
+
+ menuEdit.add(globalPrefsItem);
+ menuEdit.addSeparator();
+
+ if (currentSimulator == null)
+ return;
+
+ String processString = prefs.getString("lang.process");
+ ArrayList<VSInternalProcess> arr =
+ currentSimulator.getSimulatorCanvas().getProcessesArray();
+
+ //int numProcesses = arr.size();
+ int processNum = 0;
+
+ for (VSInternalProcess process : arr) {
+ int processID = process.getProcessID();
+ JMenuItem processItem = new JMenuItem(processString + " " +
+ processID);
+ if (processNum < 9)
+ processItem.setAccelerator(
+ KeyStroke.getKeyStroke(0x31+processNum,
+ ActionEvent.ALT_MASK));
+ final int finalProcessNum = processNum++;
+ processItem.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent ae) {
+ currentSimulator.getSimulatorCanvas().editProcess(
+ finalProcessNum);
+ }
+ });
+ menuEdit.add(processItem);
+ }
+ }
+
+ /**
+ * Updates the simulator menu. Called if the simulator state has changed
+ * (e.g. start/play/stop/replay etc)
+ */
+ public synchronized void updateSimulatorMenu() {
+ VSMenuItemStates menuItemState = currentSimulator.getMenuItemStates();
+
+ pauseItem.setEnabled(menuItemState.getPause());
+ replayItem.setEnabled(menuItemState.getReplay());
+ resetItem.setEnabled(menuItemState.getReset());
+ startItem.setEnabled(menuItemState.getStart());
+
+ pauseButton.setEnabled(menuItemState.getPause());
+ replayButton.setEnabled(menuItemState.getReplay());
+ resetButton.setEnabled(menuItemState.getReset());
+ startButton.setEnabled(menuItemState.getStart());
+ }
+
+ /* (non-Javadoc)
+ * @see java.awt.Window#dispose()
+ */
+ public void dispose() {
+ synchronized (simulators) {
+ for (VSSimulator simulator : simulators)
+ simulator.getSimulatorCanvas().stopThread();
+ }
+ super.dispose();
+ }
+
+ /**
+ * Adds the simulator.
+ *
+ * @param simulator the simulator
+ */
+ public void addSimulator(VSSimulator simulator) {
+ simulator.setLayout(new GridLayout(1, 1, 3, 3));
+ simulator.setMinimumSize(new Dimension(0, 0));
+ simulator.setMaximumSize(new Dimension(0, 0));
+
+ simulators.add(simulator);
+ tabbedPane.addTab(prefs.getString("lang.simulator")
+ + " " + simulator.getSimulatorNum(), simulator);
+ tabbedPane.setSelectedComponent(simulator);
+
+ if (simulators.size() == 1) {
+ menuEdit.setEnabled(true);
+ //menuFile.setEnabled(true);
+ closeItem.setEnabled(true);
+ saveItem.setEnabled(true);
+ saveAsItem.setEnabled(true);
+ menuSimulator.setEnabled(true);
+ }
+ }
+
+ /**
+ * Removes the simulator.
+ *
+ * @param simulatorToRemove the simulator to remove
+ */
+ public void removeSimulator(VSSimulator simulatorToRemove) {
+ if (simulators.size() == 1) {
+ pauseButton.setEnabled(false);
+ replayButton.setEnabled(false);
+ resetButton.setEnabled(false);
+ startButton.setEnabled(false);
+ menuEdit.setEnabled(false);
+ //menuFile.setEnabled(false);
+ closeItem.setEnabled(false);
+ saveItem.setEnabled(false);
+ saveAsItem.setEnabled(false);
+ menuSimulator.setEnabled(false);
+ }
+
+ simulators.remove(simulatorToRemove);
+ tabbedPane.remove(simulatorToRemove);
+ simulatorToRemove.getSimulatorCanvas().stopThread();
+ }
+
+ /**
+ * Removes the current simulator.
+ */
+ private void removeCurrentSimulator() {
+ removeSimulator(currentSimulator);
+ }
+
+ /**
+ * Gets the current simulator.
+ *
+ * @return the current simulator
+ */
+ public VSSimulator getCurrentSimulator() {
+ return currentSimulator;
+ }
+
+ /**
+ * Resets the current simulator
+ */
+ public void resetCurrentSimulator() {
+ if (currentSimulator == null)
+ return;
+
+ VSMenuItemStates menuItemState =
+ currentSimulator.getMenuItemStates();
+ menuItemState.setStart(true);
+ menuItemState.setPause(false);
+ menuItemState.setReset(false);
+ menuItemState.setReplay(false);
+ currentSimulator.getSimulatorCanvas().reset();
+ updateSimulatorMenu();
+ }
+
+ /**
+ * Starts the current simulator
+ */
+ public void startCurrentSimulator() {
+ VSMenuItemStates menuItemState =
+ currentSimulator.getMenuItemStates();
+ menuItemState.setStart(false);
+ menuItemState.setPause(true);
+ menuItemState.setReset(false);
+ menuItemState.setReplay(true);
+ currentSimulator.getSimulatorCanvas().play();
+ updateSimulatorMenu();
+ }
+
+ /**
+ * Pauses the current simulator
+ */
+ public void pauseCurrentSimulator() {
+ VSMenuItemStates menuItemState =
+ currentSimulator.getMenuItemStates();
+ menuItemState.setStart(true);
+ menuItemState.setPause(false);
+ menuItemState.setReset(true);
+ menuItemState.setReplay(true);
+ currentSimulator.getSimulatorCanvas().pause();
+ updateSimulatorMenu();
+ }
+
+ /**
+ * Gets the image icon.
+ *
+ * @param name the name
+ * @param descr the descr
+ *
+ * @return the image icon
+ */
+ private ImageIcon getImageIcon(String name, String descr) {
+ java.net.URL imageURL = getClass().getResource("/icons/"+name);
+
+ if (imageURL == null)
+ return new ImageIcon("icons/"+name, descr);
+
+ return new ImageIcon(imageURL, descr);
+ }
+
+ /**
+ * Gets the prefs.
+ *
+ * @return the prefs
+ */
+ public VSPrefs getPrefs() {
+ return prefs;
+ }
+}
diff --git a/src/main/java/simulator/VSSimulatorVisualization.java b/src/main/java/simulator/VSSimulatorVisualization.java
new file mode 100644
index 0000000..2dc4a64
--- /dev/null
+++ b/src/main/java/simulator/VSSimulatorVisualization.java
@@ -0,0 +1,1814 @@
+package simulator;
+
+import java.awt.Canvas;
+import java.awt.Color;
+import java.awt.Graphics2D;
+import java.awt.RenderingHints;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.HierarchyBoundsListener;
+import java.awt.event.HierarchyEvent;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+import java.awt.event.MouseMotionListener;
+import java.awt.image.BufferStrategy;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.ArrayList;
+import java.util.LinkedList;
+
+import javax.swing.JMenu;
+import javax.swing.JMenuItem;
+import javax.swing.JPopupMenu;
+import javax.swing.SwingUtilities;
+
+import core.VSInternalProcess;
+import core.VSMessage;
+import core.VSTask;
+import core.VSTaskManager;
+import core.time.VSTime;
+import events.VSAbstractEvent;
+import events.implementations.VSProcessCrashEvent;
+import events.implementations.VSProcessRecoverEvent;
+import events.internal.VSMessageReceiveEvent;
+import prefs.VSPrefs;
+import prefs.editors.VSEditorFrame;
+import prefs.editors.VSProcessEditor;
+import serialize.VSSerializable;
+import serialize.VSSerialize;
+
+/**
+ * The class VSSimulatorVisualization. An instance of this object represents the
+ * graphical paint area of a simulator. It contains all graphic calculations.
+ * Also the simulator thread takes place in this class in a loop! This class
+ * is probably the most cryptic of the whole simulator source code. This is
+ * this way in order to gain more performance of the painting area!
+ *
+ * @author Paul C. Buetow
+ */
+public class VSSimulatorVisualization extends Canvas
+ implements Runnable, VSSerializable {
+
+ /** The serial version uid */
+ private static final long serialVersionUID = 1L;
+
+ /** The highlighted process. */
+ private VSInternalProcess highlightedProcess;
+
+ /** The simulator. */
+ private VSSimulator simulator;
+
+ /** The prefs. */
+ private VSPrefs prefs;
+
+ /** The loging. */
+ private VSLogging loging;
+
+ /** The num processes. */
+ private volatile int numProcesses;
+
+ /** The seconds spaceing. */
+ private int secondsSpaceing;
+
+ /** The thread sleep. */
+ private int threadSleep;
+
+ /** The until time. Until then goes the simulator? */
+ private long untilTime;
+
+ /** The simulator is paused. */
+ private volatile boolean isPaused = true;
+
+ /** The simulator thread is stopped. */
+ private volatile boolean hasThreadStopped = false;
+
+ /** The simulator is finished. */
+ private volatile boolean hasFinished = false;
+
+ /** The simulator is resetted. */
+ private volatile boolean isResetted = false;
+
+ /** The simulator is anti aliased. */
+ private volatile boolean isAntiAliased = false;
+
+ /** The simulator's anti aliasing has changed. */
+ private volatile boolean isAntiAliasedChanged = false;
+
+ /** The simulator shows the lamport time. */
+ private volatile boolean showLamport = false;
+
+ /** The simulator shows the vector time. */
+ private volatile boolean showVectorTime = false;
+
+ /** The pause time. */
+ private volatile long pauseTime;
+
+ /** The start time. */
+ private volatile long startTime;
+
+ /** The global time. */
+ private volatile long time;
+
+ /** The last global time. */
+ private volatile long lastTime;
+
+ /** The task manager. */
+ private VSTaskManager taskManager;
+
+ /** The message lines. */
+ private LinkedList<VSMessageLine> messageLines;
+
+ /** The message lines to remove. */
+ private LinkedList<VSMessageLine> messageLinesToRemove;
+
+ /** The processes. */
+ private ArrayList<VSInternalProcess> processes;
+
+ /** The clock speed. */
+ private double clockSpeed;
+
+ /** The clock offset. */
+ private double clockOffset;
+
+ /** The simulator time. */
+ private long simulatorTime;
+
+ /** The x paint size. */
+ double xPaintSize;
+
+ /** The paint size. */
+ double paintSize;
+
+ /** The y distance. */
+ double yDistance;
+
+ /** The global time x position. */
+ double globalTimeXPosition;
+
+ /** The xoffset_plus_xpaintsize. */
+ int xoffset_plus_xpaintsize;
+
+ /** The xpaintsize_dividedby_untiltime. */
+ double xpaintsize_dividedby_untiltime;
+
+ /** The paint processes offset. */
+ int paintProcessesOffset;
+
+ /** The paint secondlines seconds. */
+ int paintSecondlinesSeconds;
+
+ /** The paint secondlines line. */
+ int paintSecondlinesLine[] = new int[4];
+
+ /** The paint secondlines y string pos1. */
+ int paintSecondlinesYStringPos1;
+
+ /** The paint secondlines y string pos2. */
+ int paintSecondlinesYStringPos2;
+
+ /** The paint global time y position. */
+ int paintGlobalTimeYPosition;
+
+ /* GFX buffering */
+ /** The strategy for buffering. */
+ private BufferStrategy strategy;
+
+ /** The graphics object to paint at. */
+ private Graphics2D g;
+
+ /** The Constant LINE_WIDTH. */
+ private static final int LINE_WIDTH = 5;
+
+ /** The Constant SEPLINE_WIDTH. */
+ private static final int SEPLINE_WIDTH = 2;
+
+ /** The Constant XOFFSET. */
+ private static final int XOFFSET = 50;
+
+ /** The Constant YOFFSET. */
+ private static final int YOFFSET = 30;
+
+ /** The Constant YOUTER_SPACEING. */
+ private static final int YOUTER_SPACEING = 15;
+
+ /** The Constant YSEPLINE_SPACEING. */
+ private static final int YSEPLINE_SPACEING = 20;
+
+ /** The Constant TEXT_SPACEING. */
+ private static final int TEXT_SPACEING = 10;
+
+ /** The Constant ROW_HEIGHT. */
+ private static final int ROW_HEIGHT = 14;
+
+ /* Constats, which have to get calculated once after start */
+ /** The processline color. */
+ private Color processlineColor;
+
+ /** The process secondline color. */
+ private Color processSecondlineColor;
+
+ /** The process sepline color. */
+ private Color processSeplineColor;
+
+ /** The message arrived color. */
+ private Color messageArrivedColor;
+
+ /** The message sending color. */
+ private Color messageSendingColor;
+
+ /** The message lost color. */
+ private Color messageLostColor;
+
+ /** The background color. */
+ private Color backgroundColor;
+
+ /** The message line counter. */
+ private long messageLineCounter;
+
+ /** The process counter. Needed for the unique process id's. */
+ private int processCounter;
+
+ /**
+ * The class VSMessageLine, an object of this class represents a message
+ * line drawn into the painting area.
+ *
+ * @author Paul C. Buetow
+ */
+ public class VSMessageLine {
+ /** The receiver process. */
+ private VSInternalProcess receiverProcess;
+
+ /** The color. */
+ private Color color;
+
+ /** The send time. */
+ private long sendTime;
+
+ /** The recv time. */
+ private long recvTime;
+
+ /** The sender num. */
+ private int senderNum;
+
+ /** The receiver num. */
+ private int receiverNum;
+
+ /** The offset1. */
+ private int offset1;
+
+ /** The offset2. */
+ private int offset2;
+
+ /** The message has arrived. */
+ private boolean isArrived;
+
+ /** The message is lost. */
+ private boolean isLost;
+
+ /** The x1. */
+ private double x1;
+
+ /** The y1. */
+ private double y1;
+
+ /** The x2. */
+ private double x2;
+
+ /** The y2. */
+ private double y2;
+
+ /** The x. */
+ private double x;
+
+ /** The y. */
+ private double y;
+
+ /** The outage time. */
+ private long outageTime;
+
+ /** The z. */
+ private long z;
+
+ /** The message line num. */
+ private long messageLineNum;
+
+ /** The task. */
+ private VSTask task;
+
+ /**
+ * Instantiates a new VSMessageLine object.
+ *
+ * @param receiverProcess the receiver process
+ * @param sendTime the send time
+ * @param recvTime the recv time
+ * @param outageTime the outage time
+ * @param senderNum the sender num
+ * @param receiverNum the receiver num
+ * @param task the task
+ */
+ public VSMessageLine(VSInternalProcess receiverProcess, long sendTime,
+ long recvTime, long outageTime, int senderNum,
+ int receiverNum, VSTask task) {
+ this.receiverProcess = receiverProcess;
+ this.sendTime = sendTime;
+ this.recvTime = recvTime;
+ this.outageTime = outageTime;
+ this.senderNum = senderNum;
+ this.receiverNum = receiverNum;
+ this.isArrived = false;
+ this.isLost = false;
+ this.messageLineNum = ++messageLineCounter;
+ this.task = task;
+
+ if (senderNum > receiverNum) {
+ //offset1 = 1;
+ offset2 = LINE_WIDTH;
+ } else {
+ offset1 = LINE_WIDTH - 1;
+ //offset2 = 1;
+ }
+
+ /* Needed if the message gets lost after 0ms */
+ this.x = getTimeXPosition(sendTime);
+ this.y = getProcessYPosition(senderNum+1) + offset1;
+
+ recalcOnChange();
+ paint();
+ }
+
+ /**
+ * Recalc on change.
+ */
+ public void recalcOnChange() {
+ x1 = getTimeXPosition(sendTime);
+ y1 = getProcessYPosition(senderNum+1) + offset1;
+ x2 = getTimeXPosition(recvTime);
+ y2 = getProcessYPosition(receiverNum+1) + offset2;
+
+ if (isLost) {
+ x = getTimeXPosition(z);
+ y = y1 + ( ( (y2-y1) / (x2-x1)) * (x-x1));
+ }
+
+ }
+
+ /**
+ * Draws the message line.
+ *
+ * @param g the grpahics object to draw at
+ * @param globalTime the global time
+ */
+ public void draw(final Graphics2D g, final long globalTime) {
+ if (isArrived) {
+ g.setColor(color);
+ g.drawLine((int) x1, (int) y1, (int) x2, (int) y2);
+
+ } else if (isLost) {
+ g.setColor(messageLostColor);
+ g.drawLine((int) x1, (int) y1, (int) x, (int) y);
+
+ } else if (globalTime >= recvTime) {
+ checkIfMessageIsRelevant();
+ isArrived = true;
+
+ if (receiverProcess.isCrashed())
+ color = messageLostColor;
+ else
+ color = messageArrivedColor;
+
+ draw(g, globalTime);
+
+ } else if (outageTime >= 0 && outageTime <= globalTime) {
+ checkIfMessageIsRelevant();
+ isLost = true;
+ draw(g, globalTime);;
+
+ } else {
+ z = globalTime;
+ x = globalTimeXPosition;
+ y = y1 + ( ( (y2-y1) / (x2-x1)) * (x-x1));
+ g.setColor(messageSendingColor);
+ g.drawLine((int) x1, (int) y1, (int) x, (int) y);
+ }
+ }
+
+ /**
+ * Checks if the message is relevant. If it's not relevant, then it will
+ * get removed.
+ */
+ private void checkIfMessageIsRelevant() {
+ if (prefs.getBoolean("sim.messages.relevant")) {
+ VSMessageReceiveEvent event =
+ (VSMessageReceiveEvent) task.getEvent();
+ event.init(receiverProcess);
+ if (!event.isRelevantMessage())
+ removeMessageLine(this);
+ }
+ }
+
+ /**
+ * Called if a process within the simulator has been removed at a
+ * specified index.
+ *
+ * @param index the index
+ *
+ * @return true, if the sender or the receiver of the message has been
+ * removed from the simulator. Else false is returned.
+ */
+ public boolean removedAProcessAtIndex(int index) {
+ if (index == receiverNum || index == senderNum)
+ return true;
+
+ if (index < receiverNum)
+ --receiverNum;
+
+ if (index < senderNum)
+ --senderNum;
+
+ recalcOnChange();
+
+ return false;
+ }
+
+ /**
+ * Gets the message line num.
+ *
+ * @return the message line num
+ */
+ public long getMessageLineNum() {
+ return messageLineNum;
+ }
+
+ /**
+ * Checks one line to another if they equal (have the same message line
+ * id)
+ *
+ * @param line the line to compare against
+ *
+ * @return true, if they equal
+ */
+ public boolean equals(VSMessageLine line) {
+ return messageLineNum == line.getMessageLineNum();
+ }
+
+ /**
+ * Gets the task.
+ *
+ * @return the task
+ */
+ public VSTask getTask() {
+ return task;
+ }
+ }
+
+ /**
+ * Instantiates a new VSSimulatorVisualization object.
+ *
+ * @param prefs the prefs
+ * @param simulator the simulator
+ * @param loging the loging
+ */
+ public VSSimulatorVisualization(VSPrefs prefs, VSSimulator simulator,
+ VSLogging loging) {
+ init(prefs, simulator, loging);
+ }
+
+ /**
+ * Instantiates inits the VSSimulatorVisualization object.
+ *
+ * @param prefs the prefs
+ * @param simulator the simulator
+ * @param loging the loging
+ */
+ private void init(VSPrefs prefs, VSSimulator simulator,
+ VSLogging loging) {
+ this.prefs = prefs;
+ this.simulator = simulator;
+ this.loging = loging;
+ this.messageLines = new LinkedList<VSMessageLine>();
+ this.messageLinesToRemove = new LinkedList<VSMessageLine>();
+
+ /* May be not null if called from deserialization */
+ if (this.taskManager == null)
+ this.taskManager = new VSTaskManager(prefs, this);
+
+ /* May be not null if called from deserialization */
+ if (this.processes == null) {
+ this.processes = new ArrayList<VSInternalProcess>();
+
+ numProcesses = prefs.getInteger("sim.process.num");
+ for (int i = 0; i < numProcesses; ++i)
+ processes.add(createProcess(i));
+ }
+
+ updateFromPrefs();
+
+ final VSPrefs finalPrefs = prefs;
+ final VSSimulator finalSimulator = simulator;
+
+ addMouseListener(new MouseListener() {
+ public void mouseClicked(MouseEvent me) {
+ final VSInternalProcess process = getProcessAtYPos(me.getY());
+
+ if (SwingUtilities.isRightMouseButton(me)) {
+ ActionListener actionListener = new ActionListener() {
+ public void actionPerformed(ActionEvent ae) {
+ String command = ae.getActionCommand();
+ if (command.equals(
+ finalPrefs.getString("lang.process.edit"))) {
+ editProcess(process);
+
+ } else if (command.equals(
+ finalPrefs.getString("lang.process.crash"))) {
+ VSAbstractEvent event =
+ new VSProcessCrashEvent();
+
+ taskManager.addTask(new VSTask(
+ process.getGlobalTime(),
+ process, event,
+ VSTask.GLOBAL));
+
+ } else if (command.equals(
+ finalPrefs.getString("lang.process.recover"))) {
+ VSAbstractEvent event =
+ new VSProcessRecoverEvent();
+
+ taskManager.addTask(new VSTask(
+ process.getGlobalTime(),
+ process, event,
+ VSTask.GLOBAL));
+
+ } else if (command.equals(
+ finalPrefs.getString("lang.process.remove"))) {
+ removeProcess(process);
+
+ } else if (command.equals(
+ finalPrefs.getString("lang.process.add.new"))) {
+ addProcess();
+ }
+ }
+ };
+
+ JPopupMenu popup = new JPopupMenu();
+ JMenuItem item = null;
+
+ if (process != null)
+ item = new JMenuItem(
+ finalPrefs.getString("lang.process.selected") +
+ ": " + process.getProcessID());
+ else
+ item = new JMenuItem(
+ finalPrefs.getString("lang.process.not.selected"));
+
+ item.setEnabled(false);
+ popup.add(item);
+ popup.addSeparator();
+
+ item = new JMenuItem(
+ finalPrefs.getString("lang.process.edit"));
+ if (process == null)
+ item.setEnabled(false);
+ else
+ item.addActionListener(actionListener);
+ popup.add(item);
+
+ item = new JMenuItem(
+ finalPrefs.getString("lang.process.crash"));
+
+ if (process == null || process.isCrashed() || isPaused ||
+ time == 0 || hasFinished)
+ item.setEnabled(false);
+ else
+ item.addActionListener(actionListener);
+ popup.add(item);
+
+ item = new JMenuItem(
+ finalPrefs.getString("lang.process.recover"));
+
+ if (process == null || !process.isCrashed() || isPaused ||
+ time == 0 || hasFinished)
+ item.setEnabled(false);
+ else
+ item.addActionListener(actionListener);
+ popup.add(item);
+
+ item = new JMenuItem(
+ finalPrefs.getString("lang.process.remove"));
+
+ if (process == null)
+ item.setEnabled(false);
+ else
+ item.addActionListener(actionListener);
+ popup.add(item);
+
+ popup.addSeparator();
+
+ final long xPosTime = getXPositionTime(me.getX());
+ String timeString = finalPrefs.getString(
+ "lang.event.add.time") +
+ " " + xPosTime + "ms";
+
+ JMenu subMenu = new JMenu(
+ finalPrefs.getString("lang.event.add.local")
+ + " " + timeString);
+
+ ArrayList<VSCreateTask> createTasks =
+ finalSimulator.getCreateTaskObjects();
+
+ if (process == null) {
+ subMenu.setEnabled(false);
+ } else {
+ JMenu subSubMenu = null;
+ for (final VSCreateTask createTask : createTasks) {
+ if (createTask.isDummy()) {
+ if (subSubMenu != null)
+ subMenu.add(subSubMenu);
+ subSubMenu = new JMenu(
+ createTask.getMenuText());
+ } else {
+ item = new JMenuItem(createTask.getMenuText());
+ item.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ VSTask task =
+ createTask.createTask(process,
+ xPosTime,
+ true);
+ taskManager.addTask(
+ task, VSTaskManager.PROGRAMMED);
+ finalSimulator.updateTaskManagerTable();
+ }
+ });
+ subSubMenu.add(item);
+ }
+ }
+ }
+
+ popup.add(subMenu);
+
+ subMenu = new JMenu(
+ finalPrefs.getString("lang.event.add.global")
+ + " " + timeString);
+ if (process == null) {
+ subMenu.setEnabled(false);
+ } else {
+ JMenu subSubMenu = null;
+ for (final VSCreateTask createTask : createTasks) {
+ if (createTask.isDummy()) {
+ if (subSubMenu != null)
+ subMenu.add(subSubMenu);
+ subSubMenu = new JMenu(
+ createTask.getMenuText());
+ } else {
+ item = new JMenuItem(createTask.getMenuText());
+ item.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ VSTask task =
+ createTask.createTask(process,
+ xPosTime,
+ false);
+ taskManager.addTask(
+ task, VSTaskManager.PROGRAMMED);
+ finalSimulator.updateTaskManagerTable();
+ }
+ });
+ subSubMenu.add(item);
+ }
+ }
+ }
+
+ if (finalPrefs.getBoolean("sim.mode.expert"))
+ popup.add(subMenu);
+
+ popup.addSeparator();
+
+ item = new JMenuItem(
+ finalPrefs.getString("lang.process.add.new"));
+
+ item.addActionListener(actionListener);
+ popup.add(item);
+
+
+ popup.show(me.getComponent(), me.getX(), me.getY());
+
+ } else {
+ editProcess(process);
+ }
+ }
+
+ public void mouseExited(MouseEvent e) {
+ if (highlightedProcess != null) {
+ highlightedProcess.highlightOff();
+ highlightedProcess = null;
+ paint();
+ }
+ }
+
+ public void mouseEntered(MouseEvent e) { }
+
+ public void mousePressed(MouseEvent e) { }
+
+ public void mouseReleased(MouseEvent e) { }
+
+ });
+ addMouseMotionListener(new MouseMotionListener() {
+ public void mouseDragged(MouseEvent e) { }
+
+ public void mouseMoved(MouseEvent e) {
+ VSInternalProcess p = getProcessAtYPos(e.getY());
+
+ if (p == null) {
+ if (highlightedProcess != null) {
+ highlightedProcess.highlightOff();
+ highlightedProcess = null;
+ }
+
+ if (isPaused)
+ paint();
+
+ return;
+ }
+
+ if (highlightedProcess != null) {
+ if (highlightedProcess.getProcessID() != p.getProcessID()) {
+ highlightedProcess.highlightOff();
+ highlightedProcess = p;
+ p.highlightOn();
+ }
+ } else {
+ highlightedProcess = p;
+ p.highlightOn();
+ }
+
+ if (isPaused)
+ paint();
+ }
+
+ });
+
+ addHierarchyBoundsListener(new HierarchyBoundsListener() {
+ public void ancestorMoved(HierarchyEvent e) { }
+
+ public void ancestorResized(HierarchyEvent e) {
+ recalcOnChange();
+ }
+ });
+ }
+
+ /**
+ * This method gets called if the window border of the simulator canvas
+ * has changed. This method contains very ugly code. But this has to be in
+ * order to gain performance!
+ */
+ private void recalcOnChange() {
+ synchronized (processes) {
+ if (processes.size() == 0)
+ return;
+ }
+
+ processlineColor = prefs.getColor("col.process.line");
+ processSecondlineColor = prefs.getColor("col.process.secondline");
+ processSeplineColor = prefs.getColor("col.process.sepline");
+ messageArrivedColor = prefs.getColor("col.message.arrived");
+ messageSendingColor = prefs.getColor("col.message.sending");
+ messageLostColor = prefs.getColor("col.message.lost");
+ backgroundColor = prefs.getColor("col.background");
+
+ paintSize = simulator.getPaintSize();
+ xPaintSize = simulator.getWidth() -
+ (3 * XOFFSET + simulator.getSplitSize());
+ yDistance = (simulator.getPaintSize() -
+ 2 * (YOFFSET + YOUTER_SPACEING))/ numProcesses;
+ xpaintsize_dividedby_untiltime = xPaintSize / (double) untilTime;
+
+
+ synchronized (messageLines) {
+ for (VSMessageLine messageLine : messageLines)
+ messageLine.recalcOnChange();
+ }
+
+ /* paintProcesses optimization, precalc things */
+ {
+ xoffset_plus_xpaintsize = XOFFSET + (int) xPaintSize;
+ if (numProcesses > 1)
+ paintProcessesOffset =
+ (int) ((paintSize-2* (YOFFSET+
+ YOUTER_SPACEING+YSEPLINE_SPACEING))/
+ (numProcesses-1));
+ else
+ paintProcessesOffset =
+ (int) ((paintSize-2*(YOFFSET+
+ YOUTER_SPACEING+YSEPLINE_SPACEING)));
+ }
+
+ /* paintSecondlines optimization, precalc things */
+ {
+ int yMax = YOFFSET + YOUTER_SPACEING +
+ (int) (numProcesses * yDistance);
+ paintSecondlinesSeconds = (int) untilTime / 1000;
+ paintSecondlinesLine[1] = YOFFSET;
+ paintSecondlinesLine[3] = yMax;
+ paintSecondlinesYStringPos1 = paintSecondlinesLine[1] - 5;
+ paintSecondlinesYStringPos2 = paintSecondlinesLine[3] + 15;
+ }
+
+ /* paitnGlobalTime optimization, precalc things */
+ {
+ paintGlobalTimeYPosition = YOFFSET + YOUTER_SPACEING +
+ (int) (numProcesses * yDistance);
+ }
+
+ if (strategy != null) {
+ synchronized (strategy) {
+ g = (Graphics2D) strategy.getDrawGraphics();
+ g.setColor(backgroundColor);
+ if (isAntiAliased)
+ g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
+ RenderingHints.VALUE_ANTIALIAS_ON);
+ }
+ }
+ }
+
+ /**
+ * Updates the simulator.
+ *
+ * @param globalTime the global time
+ * @param lastGlobalTime the last global time
+ */
+ private void updateSimulator(long globalTime, long lastGlobalTime) {
+ if (isPaused || hasFinished)
+ return;
+
+ long lastSimulatorTime = simulatorTime;
+ long offset = globalTime - lastGlobalTime;
+
+ clockOffset += offset * clockSpeed;
+
+ while (clockOffset >= 1) {
+ --clockOffset;
+ ++simulatorTime;
+ }
+
+ if (simulatorTime > untilTime)
+ simulatorTime = untilTime;
+
+ offset = simulatorTime - lastSimulatorTime;
+
+ for (long l = 0; l < offset; ++l)
+ taskManager.runTasks(l, offset, lastSimulatorTime);
+
+ synchronized (processes) {
+ for (VSInternalProcess process : processes)
+ process.syncTime(simulatorTime);
+ }
+ }
+
+ /**
+ * Paints the simulator.
+ */
+ public void paint() {
+ while (getBufferStrategy() == null) {
+ createBufferStrategy(3);
+ strategy = getBufferStrategy();
+
+ if (strategy != null) {
+ g = (Graphics2D) strategy.getDrawGraphics();
+ g.setColor(backgroundColor);
+ }
+ }
+
+ synchronized (strategy) {
+ if (isAntiAliasedChanged) {
+ if (isAntiAliased)
+ g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
+ RenderingHints.VALUE_ANTIALIAS_ON);
+ else
+ g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
+ RenderingHints.VALUE_ANTIALIAS_OFF);
+ isAntiAliasedChanged = false;
+ }
+
+ g.fillRect(0, 0, getWidth(), getHeight());
+ long globalTime = simulatorTime;
+
+ globalTimeXPosition = getTimeXPosition(globalTime);
+ paintSecondlines(g);
+ paintProcesses(g, globalTime);
+ paintGlobalTime(g, globalTime);
+
+ synchronized (messageLines) {
+ synchronized (messageLinesToRemove) {
+ if (messageLinesToRemove.size() > 0) {
+ for (VSMessageLine removeThis : messageLinesToRemove)
+ messageLines.remove(removeThis);
+ messageLinesToRemove.clear();
+ }
+ }
+
+ for (VSMessageLine line : messageLines)
+ line.draw(g, globalTime);
+ }
+
+ g.setColor(backgroundColor);
+ strategy.show();
+ }
+ }
+
+ /**
+ * Paints the processes.
+ *
+ * @param g the graphics object
+ * @param globalTime the global time
+ */
+ private void paintProcesses(Graphics2D g, long globalTime) {
+ /* First paint the horizontal process timelines
+ * Second paint the processes
+ */
+ final int yOffset = YOFFSET + YOUTER_SPACEING + YSEPLINE_SPACEING;
+ final int xPoints[] = { XOFFSET, xoffset_plus_xpaintsize,
+ xoffset_plus_xpaintsize, XOFFSET, XOFFSET
+ };
+ final int yPoints[] = { yOffset, yOffset, yOffset + LINE_WIDTH,
+ yOffset + LINE_WIDTH, yOffset
+ };
+
+ synchronized (processes) {
+ for (VSInternalProcess process : processes) {
+ final long localTime = process.getTime();
+
+ g.setColor(process.getColor());
+ g.fillPolygon(xPoints, yPoints, 5);
+
+ if (process.hasCrashed()) {
+ g.setColor(process.getCrashedColor());
+ final Long crashHistory[] = process.getCrashHistoryArray();
+ final int length = crashHistory.length;
+
+ for (int i = 0; i < length; i += 2) {
+ final int crashStartPos =
+ (int) getTimeXPosition(
+ crashHistory[i].longValue());
+ int crashEndPos;
+
+ if (i == length - 1)
+ crashEndPos = xoffset_plus_xpaintsize;
+ else
+ crashEndPos = (int) getTimeXPosition(
+ crashHistory[i+1].longValue());
+
+ final int xPointsCrashed[] = {
+ crashStartPos, crashEndPos,
+ crashEndPos, crashStartPos, crashStartPos
+ };
+ g.fillPolygon(xPointsCrashed, yPoints, 5);
+ }
+ }
+
+ g.setColor(process.getColor());
+ g.drawString("P" + process.getProcessID() + ":", XOFFSET - 30,
+ yPoints[0] + LINE_WIDTH);
+
+ final long tmp = localTime > untilTime ? untilTime : localTime;
+ final int xPos = 1 + (int) getTimeXPosition(tmp);
+ final int yStart = yPoints[0] - 14;
+ final int yEnd = yPoints[0];
+
+ g.setColor(processlineColor);
+ g.drawLine(xPos, yStart, xPos, yEnd);
+ g.drawString(localTime+"ms", xPos + 2, yStart + TEXT_SPACEING);
+
+ if (showLamport)
+ paintTime(g, process.getLamportTimeArray(), process,
+ yStart, 25);
+ else if (showVectorTime)
+ paintTime(g, process.getVectorTimeArray(), process,
+ yStart, 20 * numProcesses);
+
+ for (int i = 0; i < 5; ++i)
+ yPoints[i] += paintProcessesOffset;
+ }
+ }
+ }
+
+ /**
+ * Paints the time. (e.g. lamport time or vector time)
+ *
+ * @param g the graphics object
+ * @param times the times
+ * @param process the process
+ * @param yStart the y start
+ * @param distance the distance
+ */
+ private void paintTime(final Graphics2D g, final VSTime times[],
+ final VSInternalProcess process, final int yStart,
+ final int distance) {
+
+ final int lastPos[] = { -1, -1, -1, -1 };
+
+ for (VSTime time : times) {
+ int xPos = (int) getTimeXPosition(time.getGlobalTime());
+ int bestRow[] = { -1, -1 };
+
+ for (int i = 0; i < 4; ++i) {
+ if (lastPos[i] != -1) {
+ int diff = xPos - lastPos[i];
+ if (diff > distance) {
+ bestRow[0] = i;
+ bestRow[1] = -1;
+ break;
+ } else if (bestRow[0] == -1) {
+ bestRow[0] = i;
+ bestRow[1] = diff;
+ } else if (diff > bestRow[1]) {
+ bestRow[0] = i;
+ bestRow[1] = diff;
+ }
+ } else {
+ bestRow[0] = i;
+ bestRow[1] = -1;
+ break;
+ }
+ }
+
+ final int row = bestRow[0];
+ if (bestRow[1] != -1)
+ xPos += distance - bestRow[1];
+
+ g.drawString(time.toString(), xPos + 2, yStart + 3 *
+ TEXT_SPACEING + row * ROW_HEIGHT);
+ lastPos[row] = xPos;
+ }
+ }
+
+ /**
+ * Paint the second lines.
+ *
+ * @param g the graphics object
+ */
+ private void paintSecondlines(Graphics2D g) {
+ g.setColor(processSecondlineColor);
+
+ int i;
+ for (i = 0; i <= paintSecondlinesSeconds; i += secondsSpaceing) {
+ paintSecondlinesLine[0] = paintSecondlinesLine[2] =
+ (int) getTimeXPosition(i*1000);
+ g.drawLine(paintSecondlinesLine[0], paintSecondlinesLine[1],
+ paintSecondlinesLine[2], paintSecondlinesLine[3]);
+
+ final int xStringPos = paintSecondlinesLine[0] - 5;
+ g.drawString(i+"s", xStringPos, paintSecondlinesYStringPos1);
+ if (!showVectorTime && !showLamport)
+ g.drawString(i+"s", xStringPos, paintSecondlinesYStringPos2);
+ }
+
+ if (i > paintSecondlinesSeconds) {
+ paintSecondlinesLine[0] = paintSecondlinesLine[2] =
+ (int) getTimeXPosition(untilTime);
+ g.drawLine(paintSecondlinesLine[0], paintSecondlinesLine[1],
+ paintSecondlinesLine[2], paintSecondlinesLine[3]);
+ }
+ }
+
+ /**
+ * Paints the global time.
+ *
+ * @param g the graphics object
+ * @param globalTime the global time
+ */
+ private void paintGlobalTime(Graphics2D g, long globalTime) {
+ g.setColor(processSeplineColor);
+ final int xOffset = (int) globalTimeXPosition;
+
+ final int xPoints[] = {
+ xOffset, xOffset + SEPLINE_WIDTH,
+ xOffset + SEPLINE_WIDTH, xOffset, xOffset
+ };
+ final int yOffset = YOFFSET - 8;
+ final int yPoints[] = {
+ yOffset, yOffset, paintGlobalTimeYPosition,
+ paintGlobalTimeYPosition, yOffset
+ };
+
+ g.fillPolygon(xPoints, yPoints, 5);
+ g.drawString(globalTime+"ms", xPoints[1]+1, yPoints[0]+TEXT_SPACEING);
+ }
+
+ /**
+ * Gets the process at a specified y pos.
+ *
+ * @param yPos the y pos
+ *
+ * @return the process at y pos
+ */
+ private VSInternalProcess getProcessAtYPos(int yPos) {
+ final int reachDistance = (int) (yDistance/3);
+ int y = YOFFSET + YOUTER_SPACEING + YSEPLINE_SPACEING;
+
+ int yOffset = numProcesses > 1
+ ? (int) ((paintSize-2*
+ (YOFFSET+YOUTER_SPACEING+YSEPLINE_SPACEING))/
+ (numProcesses-1))
+ : (int) ((paintSize-2*
+ (YOFFSET+YOUTER_SPACEING+YSEPLINE_SPACEING)));
+
+ for (int i = 0; i < numProcesses; ++i) {
+ if (yPos < y + reachDistance && yPos > y - reachDistance -
+ LINE_WIDTH) {
+ VSInternalProcess process = null;
+ synchronized (processes) {
+ process = processes.get(i);
+ }
+ return process;
+ }
+ y += yOffset;
+ }
+
+ return null;
+ }
+
+ /**
+ * Gets the x position of the given time.
+ *
+ * @param time the time
+ *
+ * @return the time x position
+ */
+ private double getTimeXPosition(long time) {
+ return XOFFSET + xpaintsize_dividedby_untiltime * time;
+ }
+
+ /**
+ * Gets the time of a given x position
+ *
+ * @param xPos the x position
+ *
+ * @return the time
+ */
+ private long getXPositionTime(double xPos) {
+ xPos -= XOFFSET;
+
+ if (xPos <= 0)
+ return 0;
+
+ else if (xPos >= xPaintSize)
+ return untilTime;
+
+ return (long) ((untilTime/xPaintSize) * xPos);
+ }
+
+ /**
+ * Gets the process y position.
+ *
+ * @param i the process num
+ *
+ * @return the process y position
+ */
+ private int getProcessYPosition(int i) {
+ int y;
+
+ if (numProcesses > 1)
+ y = (int) ((paintSize -
+ 2 * (YOFFSET + YOUTER_SPACEING + YSEPLINE_SPACEING))/
+ (numProcesses-1));
+ else
+ y = (int) ((paintSize -
+ 2 * (YOFFSET + YOUTER_SPACEING + YSEPLINE_SPACEING)));
+
+ return y * (i - 1) + YOFFSET + YOUTER_SPACEING + YSEPLINE_SPACEING;
+ }
+
+ /**
+ * Gets the time.
+ *
+ * @return the time
+ */
+ public long getTime() {
+ return simulatorTime;
+ }
+
+ /**
+ * Gets the until time.
+ *
+ * @return the until time
+ */
+ public long getUntilTime() {
+ return untilTime;
+ }
+
+ /**
+ * Gets the start time.
+ *
+ * @return the start time
+ */
+ public long getStartTime() {
+ return startTime;
+ }
+
+ /**
+ * Gets the next process id.
+ *
+ * @return the next process id
+ */
+ public int processIDCount() {
+ return ++processCounter;
+ }
+
+ /**
+ * Gets the task manager.
+ *
+ * @return the task manager
+ */
+ public VSTaskManager getTaskManager() {
+ return taskManager;
+ }
+
+ /**
+ * Gets the num of processes.
+ *
+ * @return the num of processes
+ */
+ public int getNumProcesses() {
+ return numProcesses;
+ }
+
+ /**
+ * Gets the specified process.
+ *
+ * @param processNum the process num to get the process of
+ *
+ * @return the process
+ */
+ public VSInternalProcess getProcess(int processNum) {
+ synchronized (processes) {
+ if (processNum >= processes.size())
+ return null;
+
+ return processes.get(processNum);
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Runnable#run()
+ */
+ public void run() {
+ while (true) {
+ while (!hasThreadStopped && (isPaused || hasFinished ||
+ isResetted)) {
+ try {
+ Thread.sleep(100);
+ paint();
+
+ } catch (Exception e) {
+ System.out.println(e);
+ }
+ }
+
+ if (hasThreadStopped)
+ break; /* Exit the thread */
+
+ while (!isPaused && !hasThreadStopped) {
+ try {
+ Thread.sleep(threadSleep);
+ } catch (Exception e) {
+ System.out.println(e);
+ }
+
+ updateSimulator(time, lastTime);
+
+ if (simulatorTime == untilTime) {
+ finish();
+ break;
+ }
+
+ paint();
+ lastTime = time;
+ time = System.currentTimeMillis() - startTime;
+ }
+
+ updateSimulator(time, lastTime);
+ paint();
+ }
+ }
+
+ /**
+ * Starts/plays the simulator.
+ */
+ public void play() {
+ loging.log(prefs.getString("lang.simulator.started"));
+ final long currentTime = System.currentTimeMillis();
+
+ synchronized (processes) {
+ for (VSInternalProcess p : processes)
+ p.play();
+ }
+
+ if (isResetted)
+ isResetted = false;
+
+ else if (hasFinished)
+ hasFinished = false;
+
+ if (isPaused) {
+ isPaused = false;
+ startTime += currentTime - pauseTime;
+ time = currentTime - startTime;
+
+ } else {
+ startTime = currentTime;
+ time = 0;
+ }
+
+ paint();
+ }
+
+ /**
+ * Called if the simulator has finished.
+ */
+ public void finish() {
+ synchronized (processes) {
+ for (VSInternalProcess p : processes)
+ p.finish();
+ }
+
+ simulator.finish();
+ hasFinished = true;
+ loging.log(prefs.getString("lang.simulator.finished"));
+ paint();
+
+ if (prefs.getBoolean("sim.periodic")) {
+ VSSimulatorFrame simulatorFrame = simulator.getSimulatorFrame();
+ simulatorFrame.resetCurrentSimulator();
+ simulatorFrame.startCurrentSimulator();
+ }
+ }
+
+ /**
+ * Call this, in order to pause the simulator.
+ */
+ public void pause() {
+ isPaused = true;
+ synchronized (processes) {
+ for (VSInternalProcess p : processes)
+ p.pause();
+ }
+
+ pauseTime = System.currentTimeMillis();
+ loging.log(prefs.getString("lang.simulator.paused"));
+ paint();
+ }
+
+ /**
+ * Call this, in order to reset the simulator.
+ */
+ public void reset() {
+ if (!isResetted) {
+ loging.log(prefs.getString("lang.simulator.resetted"));
+
+ isResetted = true;
+ isPaused = false;
+ hasFinished = false;
+ startTime = System.currentTimeMillis();
+ time = 0;
+ lastTime = 0;
+ clockOffset = 0;
+ simulatorTime = 0;
+
+ synchronized (processes) {
+ for (VSInternalProcess process : processes)
+ process.reset();
+ }
+
+ /* Reset the task manager AFTER the processes, for the programmed
+ tasks */
+ taskManager.reset();
+
+ synchronized (processes) {
+ for (VSInternalProcess process : processes)
+ process.createRandomCrashTask();
+ }
+
+ synchronized (messageLines) {
+ messageLines.clear();
+ }
+
+ synchronized (messageLinesToRemove) {
+ messageLinesToRemove.clear();
+ }
+
+ paint();
+ loging.clear();
+ }
+ }
+
+ /**
+ * Stops the thread of the simulator.
+ */
+ public void stopThread() {
+ hasThreadStopped = true;
+ }
+
+ /**
+ * Checks if the thread has been stopped.
+ *
+ * @return true, if is thread has stopped
+ */
+ public boolean hasThreadStopped() {
+ return hasThreadStopped;
+ }
+
+ /**
+ * Sets, if the the lamport time should be shown. It implicitly disables
+ * the vector time.
+ *
+ * @param showLamport true, if the lamport time should be shown
+ */
+ public void showLamport(boolean showLamport) {
+ this.showLamport = showLamport;
+ if (isPaused)
+ paint();
+ }
+
+ /**
+ * Sets, if the vector time should be shown. It implicitly disables the
+ * lamport time.
+ *
+ * @param showVectorTime true, if the vector time should be shown
+ */
+ public void showVectorTime(boolean showVectorTime) {
+ this.showVectorTime = showVectorTime;
+ if (isPaused)
+ paint();
+ }
+
+ /**
+ * Sets if the simulator graphics are anti aliased.
+ *
+ * @param isAntiAliased true, if the simulator is anti aliased
+ */
+ public void isAntiAliased(boolean isAntiAliased) {
+ this.isAntiAliased = isAntiAliased;
+ this.isAntiAliasedChanged = true;
+ if (isPaused)
+ paint();
+ }
+
+ /**
+ * Sends a message.
+ *
+ * @param message the message
+ */
+ public void sendMessage(VSMessage message) {
+ VSTask task = null;
+ VSAbstractEvent receiveEvent = null;
+ VSInternalProcess sendingProcess = (VSInternalProcess)
+ message.getSendingProcess();
+ long deliverTime, outageTime, durationTime;
+ boolean recvOwn = prefs.getBoolean("sim.message.own.recv");
+
+ synchronized (processes) {
+ for (VSInternalProcess receiverProcess : processes) {
+ if (receiverProcess.equals(sendingProcess)) {
+ if (recvOwn) {
+ deliverTime = sendingProcess.getGlobalTime();
+ receiveEvent = new VSMessageReceiveEvent(message);
+ task = new VSTask(deliverTime, receiverProcess,
+ receiveEvent, VSTask.GLOBAL);
+ taskManager.addTask(task);
+ }
+
+ } else {
+ durationTime = sendingProcess.getDurationTime();
+
+ if (prefs.getBoolean("sim.message.sendingtime.mean")) {
+ durationTime += receiverProcess.getDurationTime();
+ durationTime /= 2;
+ }
+
+ deliverTime = sendingProcess.getGlobalTime() +
+ durationTime;
+
+ if (prefs.getBoolean("sim.message.prob.mean"))
+ outageTime = sendingProcess.getARandomMessageOutageTime(
+ durationTime, receiverProcess);
+ else
+ outageTime = sendingProcess.getARandomMessageOutageTime(
+ durationTime, null);
+
+ receiveEvent = new VSMessageReceiveEvent(message);
+ task = new VSTask(deliverTime, receiverProcess,
+ receiveEvent, VSTask.GLOBAL);
+
+ /* Only add a 'receiving message' task if the message will
+ not get lost! */
+ if (outageTime == -1)
+ taskManager.addTask(task);
+
+ synchronized (messageLines) {
+ messageLines.add(
+ new VSMessageLine(receiverProcess,
+ sendingProcess.getGlobalTime(),
+ deliverTime, outageTime,
+ sendingProcess.getProcessNum(),
+ receiverProcess.getProcessNum(),
+ task));
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Edits the process.
+ *
+ * @param processNum the process num
+ */
+ public void editProcess(int processNum) {
+ synchronized (processes) {
+ VSInternalProcess process = processes.get(processNum);
+ /* May be null if another thread changed the processes arraylist
+ before this process actually called editProcess */
+ if (process != null)
+ editProcess(process);
+ }
+ }
+
+ /**
+ * Edits the process.
+ *
+ * @param process the process
+ */
+ public void editProcess(VSInternalProcess process) {
+ if (process != null) {
+ process.updatePrefs();
+ new VSEditorFrame(prefs, simulator.getSimulatorFrame(),
+ new VSProcessEditor(prefs, process));
+ }
+ }
+
+ /**
+ * Gets the processes array.
+ *
+ * @return the processes array
+ */
+ public ArrayList<VSInternalProcess> getProcessesArray() {
+ ArrayList<VSInternalProcess> arr = new ArrayList<VSInternalProcess>();
+
+ synchronized (processes) {
+ for (VSInternalProcess process : processes)
+ arr.add(process);
+ }
+
+ return arr;
+ }
+
+ /**
+ * Gets the processes IDs.
+ *
+ * @return the processes IDs
+ */
+ public Integer[] getProcessIDs() {
+ Integer pids[] = null;
+
+ synchronized (processes) {
+ pids = new Integer[numProcesses];
+ for (int i = 0; i < numProcesses; ++i)
+ pids[i] = Integer.valueOf(processes.get(i).getProcessID());
+ }
+
+ return pids;
+ }
+
+ /**
+ * Gets the processes.
+ *
+ * @return the processes
+ */
+ public ArrayList<VSInternalProcess> getProcesses() {
+ return processes;
+ }
+
+ /**
+ * Updates from the prefs. Called by the VSSimulatorEditor if values
+ * have been saved.
+ */
+ public void updateFromPrefs() {
+ untilTime = prefs.getInteger("sim.seconds") * 1000;
+ clockSpeed = prefs.getFloat("sim.clock.speed");
+
+ secondsSpaceing = (int) (untilTime / 15000);
+ if (secondsSpaceing == 0)
+ secondsSpaceing = 1;
+
+ threadSleep = (int) (untilTime / 7500);
+ if (threadSleep == 0)
+ threadSleep = 1;
+
+ recalcOnChange();
+ }
+
+ /**
+ * Removes a specific message line from the painting area.
+ *
+ * @param messageLine the message line to remove
+ */
+ private void removeMessageLine(VSMessageLine messageLine) {
+ synchronized (messageLinesToRemove) {
+ messageLinesToRemove.add(messageLine);
+ }
+ }
+
+ /**
+ * Removes a process from the simulator.
+ *
+ * @param process the process
+ */
+ private void removeProcess(VSInternalProcess process) {
+ if (numProcesses == 1) {
+ simulator.getSimulatorFrame().removeSimulator(simulator);
+
+ } else {
+ int index = 0;
+ synchronized (processes) {
+ index = processes.indexOf(process);
+ processes.remove(index);
+
+ for (VSInternalProcess p : processes)
+ p.removedAProcessAtIndex(index);
+
+ numProcesses = processes.size();
+ }
+
+ taskManager.removeTasksOf(process);
+ simulator.removedAProcessAtIndex(index);
+ recalcOnChange();
+
+ ArrayList<VSMessageLine> removeThose =
+ new ArrayList<VSMessageLine>();
+
+ synchronized (messageLines) {
+ for (VSMessageLine line : messageLines)
+ if (line.removedAProcessAtIndex(index))
+ removeThose.add(line);
+
+ for (VSMessageLine line : removeThose) {
+ VSTask deliverTask = line.getTask();
+
+ if (deliverTask != null)
+ taskManager.removeTask(deliverTask);
+
+ messageLines.remove(line);
+ }
+ }
+ }
+ }
+
+ /**
+ * Creates a process with the specified num.
+ *
+ * @param processNum the process num
+ *
+ * @return the new process
+ */
+ private VSInternalProcess createProcess(int processNum) {
+ VSInternalProcess process =
+ new VSInternalProcess(prefs, processNum, this, loging);
+ loging.log(prefs.getString("lang.process.new") + "; " + process);
+ return process;
+ }
+
+ /**
+ * Adds a new process to the simulator.
+ *
+ * @return The process which has been added
+ */
+ private VSInternalProcess addProcess() {
+ VSInternalProcess newProcess = null;
+ //int foo = -1;
+ //System.out.println("ADD " + ++foo);
+ synchronized (processes) {
+ //System.out.println("ADD " + ++foo);
+ numProcesses = processes.size() + 1;
+ //System.out.println("ADD " + ++foo);
+ newProcess = createProcess(processes.size());
+ //System.out.println("ADD " + ++foo);
+ //System.out.println("ADD " + ++foo);
+ }
+
+ //System.out.println("ADD " + ++foo);
+ addProcess(newProcess);
+ //System.out.println("ADD " + ++foo);
+ return newProcess;
+ }
+
+ /**
+ * Adds a the given process to the simulator.
+ *
+ * @newProcess The process to add
+ */
+ private void addProcess(VSInternalProcess newProcess) {
+ //int foo = -1;
+ //System.out.println("ADD_ " + ++foo);
+ synchronized (processes) {
+ //System.out.println("ADD_ " + ++foo);
+ processes.add(newProcess);
+
+ for (VSInternalProcess process : processes)
+ if (!process.equals(newProcess))
+ process.addedAProcess();
+ //System.out.println("ADD_ " + ++foo);
+ }
+
+ //System.out.println("ADD_ " + ++foo);
+ recalcOnChange();
+ //System.out.println("ADD_ " + ++foo);
+ simulator.addProcessAtIndex(processes.size()-1);
+ //System.out.println("ADD_ " + ++foo);
+ }
+
+ /**
+ * Checks if the simulation is paused.
+ *
+ * @return true, if the simulation is paused
+ */
+ boolean isPaused() {
+ return isPaused;
+ }
+
+ /**
+ * Checks if the simulation is resetted.
+ *
+ * @return true, if the simulation is resetted
+ */
+ boolean isResetted() {
+ return isResetted;
+ }
+
+ /**
+ * Checks if the simulation has finished
+ *
+ * @return true, if the simulation has finished
+ */
+ boolean hasFinished() {
+ return hasFinished;
+ }
+
+ /* (non-Javadoc)
+ * @see serialize.VSSerializable#serialize(serialize.VSSerialize,
+ * java.io.ObjectOutputStream)
+ */
+ public synchronized void serialize(VSSerialize serialize,
+ ObjectOutputStream objectOutputStream)
+ throws IOException {
+ /** For later backwards compatibility, to add more stuff */
+ objectOutputStream.writeObject(Boolean.valueOf(false));
+
+ objectOutputStream.writeObject(Integer.valueOf(processCounter));
+
+ synchronized (processes) {
+ objectOutputStream.writeObject(Integer.valueOf(numProcesses));
+ for (VSInternalProcess process : processes)
+ process.serialize(serialize, objectOutputStream);
+ }
+
+ taskManager.serialize(serialize, objectOutputStream);
+
+ /** For later backwards compatibility, to add more stuff */
+ objectOutputStream.writeObject(Boolean.valueOf(false));
+ }
+
+ /* (non-Javadoc)
+ * @see serialize.VSSerializable#deserialize(serialize.VSSerialize,
+ * java.io.ObjectInputStream)
+ */
+ public synchronized void deserialize(VSSerialize serialize,
+ ObjectInputStream objectInputStream)
+ throws IOException, ClassNotFoundException {
+ if (VSSerialize.DEBUG)
+ System.out.println("Deserializing: VSSimulatorVisualization");
+
+ /** For later backwards compatibility, to add more stuff */
+ objectInputStream.readObject();
+
+ processCounter = ((Integer) objectInputStream.readObject()).intValue();
+
+ int num = ((Integer) objectInputStream.readObject()).intValue();
+ loging.clear();
+
+ if (num > numProcesses) {
+ for (int i = numProcesses; i < num; ++i)
+ addProcess();
+ } else {
+ int oldNum = numProcesses;
+ for (int i = num; i < oldNum; ++i)
+ removeProcess(getProcess(0));
+ }
+
+ for (int i = 0; i < num; ++i)
+ processes.get(i).deserialize(serialize, objectInputStream);
+
+ taskManager.deserialize(serialize, objectInputStream);
+
+ /** For later backwards compatibility, to add more stuff */
+ objectInputStream.readObject();
+ }
+}