summaryrefslogtreecommitdiff
path: root/sources/simulator
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2008-05-15 23:08:33 +0000
committerPaul Buetow <paul@buetow.org>2008-05-15 23:08:33 +0000
commitd4c1ddcc90c1e2e8660598fc36b3772d2bff6816 (patch)
tree28a0afc255e42f92adbca0d102e785301bc43a58 /sources/simulator
parent61599471a5978c1521b9c89c044ac2ce9a88c398 (diff)
1 Moved the stuff to trunk!
Diffstat (limited to 'sources/simulator')
-rw-r--r--sources/simulator/VSAbout.java63
-rw-r--r--sources/simulator/VSLogging.java57
-rw-r--r--sources/simulator/VSMain.java34
-rw-r--r--sources/simulator/VSSimulation.java311
-rw-r--r--sources/simulator/VSSimulationPanel.java619
5 files changed, 1084 insertions, 0 deletions
diff --git a/sources/simulator/VSAbout.java b/sources/simulator/VSAbout.java
new file mode 100644
index 0000000..4b68598
--- /dev/null
+++ b/sources/simulator/VSAbout.java
@@ -0,0 +1,63 @@
+package simulator;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import javax.swing.border.*;
+import javax.swing.filechooser.*;
+import java.util.*;
+import java.io.File;
+
+import prefs.*;
+import utils.*;
+
+public class VSAbout extends VSFrame implements ActionListener {
+ private VSPrefs prefs;
+
+ public VSAbout(VSPrefs prefs, Component relativeTo) {
+ super(prefs.getString("name") + " - "
+ + prefs.getString("lang.about"), relativeTo);
+
+ this.prefs = prefs;
+ disposeWithParent();
+ setContentPane(createContentPane());
+ setSize(350, 250);
+ setResizable(false);
+ setVisible(true);
+ }
+
+
+ public Container createContentPane() {
+ Container contentPane = getContentPane();
+
+ VSInfoArea infoArea = new VSInfoArea(prefs.getString("lang.about.info!"));
+ JPanel buttonPane = createButtonPane();
+ JScrollPane scrollPane = new JScrollPane(infoArea);
+
+ contentPane.add(scrollPane, BorderLayout.CENTER);
+ contentPane.add(buttonPane, BorderLayout.SOUTH);
+
+ return contentPane;
+ }
+
+ public JPanel createButtonPane() {
+ JPanel buttonPane = new JPanel();
+ buttonPane.setBackground(Color.WHITE);
+
+ JButton closeButton = new JButton(
+ prefs.getString("lang.close"));
+ closeButton.setMnemonic(prefs.getInteger("keyevent.close"));
+ closeButton.addActionListener(this);
+ buttonPane.add(closeButton);
+
+ return buttonPane;
+ }
+
+
+ public void actionPerformed(ActionEvent e) {
+ String actionCommand = e.getActionCommand();
+
+ if (actionCommand.equals(prefs.getString("lang.close")))
+ dispose();
+ }
+}
diff --git a/sources/simulator/VSLogging.java b/sources/simulator/VSLogging.java
new file mode 100644
index 0000000..c65198b
--- /dev/null
+++ b/sources/simulator/VSLogging.java
@@ -0,0 +1,57 @@
+package simulator;
+
+import javax.swing.*;
+import java.util.*;
+
+import utils.*;
+
+public class VSLogging {
+ private JTextArea loggingArea;
+ private VSSimulationPanel simulationPanel;
+ private volatile boolean isPaused;
+ private StringBuffer pauseBuffer;
+
+ public VSLogging() {
+ loggingArea = new JTextArea(0, 0);
+ loggingArea.setEditable(false);
+ pauseBuffer = new StringBuffer();
+ }
+
+ public void setSimulationPanel(VSSimulationPanel simulationPanel) {
+ this.simulationPanel = simulationPanel;
+ }
+
+ public JTextArea getLoggingArea() {
+ return loggingArea;
+ }
+
+ public void logg(String message) {
+ if (simulationPanel == null)
+ logg(message, 0);
+ else
+ logg(message, simulationPanel.getTime());
+ }
+
+ public void logg(String message, long time) {
+ if (isPaused) {
+ pauseBuffer.append(VSTools.getTimeString(time));
+ pauseBuffer.append(": ");
+ pauseBuffer.append(message);
+ pauseBuffer.append("\n");
+
+ } else {
+ loggingArea.append(VSTools.getTimeString(time) + ": " + message + "\n");
+ loggingArea.setCaretPosition(loggingArea.getDocument().getLength());
+ }
+ }
+
+ public void isPaused(boolean isPaused) {
+ this.isPaused = isPaused;
+
+ if (!isPaused) {
+ loggingArea.append(pauseBuffer.toString());
+ loggingArea.setCaretPosition(loggingArea.getDocument().getLength());
+ pauseBuffer.delete(0, pauseBuffer.length());
+ }
+ }
+}
diff --git a/sources/simulator/VSMain.java b/sources/simulator/VSMain.java
new file mode 100644
index 0000000..9280eeb
--- /dev/null
+++ b/sources/simulator/VSMain.java
@@ -0,0 +1,34 @@
+package simulator;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+
+import editors.*;
+import prefs.*;
+import protocols.*;
+
+public class VSMain {
+ public VSMain(VSPrefs prefs) {
+ initialize(prefs, null);
+ }
+
+ public VSMain(VSPrefs prefs, Component relativeTo) {
+ initialize(prefs, relativeTo);
+ }
+
+ private void initialize(VSPrefs prefs, Component relativeTo) {
+ new VSSimulationEditor(prefs, relativeTo);
+ }
+
+ public static void main(String[] args) {
+ try {
+ UIManager.setLookAndFeel(
+ UIManager.getCrossPlatformLookAndFeelClassName());
+ } catch (Exception e) { }
+
+ VSPrefs prefs = VSDefaultPrefs.initialize();
+ RegisteredProtocols.initialize(prefs);
+ new VSMain(prefs);
+ }
+}
diff --git a/sources/simulator/VSSimulation.java b/sources/simulator/VSSimulation.java
new file mode 100644
index 0000000..2bc90d8
--- /dev/null
+++ b/sources/simulator/VSSimulation.java
@@ -0,0 +1,311 @@
+package simulator;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.util.*;
+import javax.swing.*;
+import javax.swing.event.*;
+
+import prefs.*;
+import core.*;
+import utils.*;
+
+public class VSSimulation extends VSFrame implements ActionListener {
+ private JMenuItem pauseItem;
+ private JMenuItem replayItem;
+ private JMenuItem resetItem;
+ private JMenuItem startItem;
+ private JSplitPane splitPaneH;
+ private JSplitPane splitPaneV;
+ private JPanel processEditPanel;
+ private VSSimulationPanel simulationPanel;
+ private Thread thread;
+ private VSPrefs prefs;
+ private boolean hasStarted = false;
+ private VSLogging logging;
+
+ public VSSimulation (VSPrefs prefs, Component relativeTo) {
+ super(prefs.getString("name"), relativeTo);
+ this.prefs = prefs;
+ this.logging = new VSLogging();
+
+ setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
+
+ setSize(prefs.getInteger("window.xsize")+100,
+ prefs.getInteger("window.ysize"));
+ setJMenuBar(createJMenuBar());
+ setContentPane(createContentPane());
+ setVisible(true);
+
+ thread = new Thread(simulationPanel);
+ //logging.start();
+ logging.logg(prefs.getString("lang.simulation.new"));
+ }
+
+ private JMenuBar createJMenuBar() {
+ /* File menu */
+ JMenu menuFile = new JMenu(prefs.getString("lang.file"));
+ menuFile.setMnemonic(prefs.getInteger("keyevent.file"));
+ JMenuItem menuItem;
+
+ menuItem = new JMenuItem(prefs.getString("lang.new"));
+ menuItem.setAccelerator(KeyStroke.getKeyStroke(
+ prefs.getInteger("keyevent.new"),
+ ActionEvent.ALT_MASK));
+ menuItem.addActionListener(this);
+ menuFile.add(menuItem);
+
+ menuItem = new JMenuItem(
+ prefs.getString("lang.close"));
+ menuItem.setAccelerator(KeyStroke.getKeyStroke(
+ prefs.getInteger("keyevent.close"),
+ ActionEvent.ALT_MASK));
+ menuItem.addActionListener(this);
+ menuFile.add(menuItem);
+
+ menuFile.addSeparator();
+
+ menuItem = new JMenuItem(prefs.getString("lang.about"));
+ menuItem.setAccelerator(KeyStroke.getKeyStroke(
+ prefs.getInteger("keyevent.about"),
+ ActionEvent.ALT_MASK));
+ menuItem.addActionListener(this);
+ menuFile.add(menuItem);
+
+ menuItem = new JMenuItem(prefs.getString("lang.quit"));
+ menuItem.setAccelerator(KeyStroke.getKeyStroke(
+ prefs.getInteger("keyevent.quit"),
+ ActionEvent.ALT_MASK));
+ menuItem.addActionListener(this);
+ menuFile.add(menuItem);
+
+ /* VSSimulation menu */
+ JMenu menuVSSimulation = new JMenu(
+ prefs.getString("lang.simulation"));
+ menuVSSimulation.setMnemonic(prefs.getInteger("keyevent.simulation"));
+
+ startItem = new JMenuItem(
+ prefs.getString("lang.start"));
+ startItem.setAccelerator(KeyStroke.getKeyStroke(
+ prefs.getInteger("keyevent.start"),
+ ActionEvent.ALT_MASK));
+ startItem.addActionListener(this);
+ menuVSSimulation.add(startItem);
+
+ pauseItem = new JMenuItem(
+ prefs.getString("lang.pause"));
+ pauseItem.setAccelerator(KeyStroke.getKeyStroke(
+ prefs.getInteger("keyevent.pause"),
+ ActionEvent.ALT_MASK));
+ pauseItem.addActionListener(this);
+ menuVSSimulation.add(pauseItem);
+ pauseItem.setEnabled(false);
+
+ resetItem = new JMenuItem(
+ prefs.getString("lang.reset"));
+ resetItem.setAccelerator(KeyStroke.getKeyStroke(
+ prefs.getInteger("keyevent.reset"),
+ ActionEvent.ALT_MASK));
+ resetItem.addActionListener(this);
+ resetItem.setEnabled(false);
+ menuVSSimulation.add(resetItem);
+
+ replayItem = new JMenuItem(
+ prefs.getString("lang.replay"));
+ replayItem.setAccelerator(KeyStroke.getKeyStroke(
+ prefs.getInteger("keyevent.replay"),
+ ActionEvent.ALT_MASK));
+ replayItem.addActionListener(this);
+ replayItem.setEnabled(false);
+ menuVSSimulation.add(replayItem);
+
+ JMenuBar mainMenuBar = new JMenuBar();
+ mainMenuBar.add(menuFile);
+ mainMenuBar.add(menuVSSimulation);
+
+ return mainMenuBar;
+ }
+
+ private Container createContentPane() {
+ JTextArea loggingArea = logging.getLoggingArea();
+
+ /*
+ splitPaneH = new JSplitPane();
+ splitPaneH.setDividerLocation(
+ prefs.getInteger("window.splitsize"));
+
+ */
+ splitPaneV = new JSplitPane();
+ splitPaneV.setDividerLocation(
+ prefs.getInteger("window.ysize")
+ - prefs.getInteger("window.loggsize"));
+
+ simulationPanel = new VSSimulationPanel(prefs, this, logging);
+ logging.setSimulationPanel(simulationPanel);
+ simulationPanel.setBackground(new Color(0xFD, 0xFC, 0xF7));
+ //processEditPanel = createProcessEditPanel();
+
+ JScrollPane paintScrollPane = new JScrollPane(simulationPanel);
+ JScrollPane textScrollPane = new JScrollPane(loggingArea);
+ JPanel toolsPanel = createToolsPanel();
+
+ JPanel loggingPane = new JPanel(new BorderLayout());
+ loggingPane.add(textScrollPane, BorderLayout.CENTER);
+ loggingPane.add(toolsPanel, BorderLayout.SOUTH);
+ loggingPane.setPreferredSize(new Dimension(200, 1));
+
+ //JScrollPane processEditScrollPane = new JScrollPane(processEditPanel);
+
+ /*
+ splitPaneH.setOrientation(JSplitPane.HORIZONTAL_SPLIT);
+ splitPaneH.setLeftComponent(processEditScrollPane);
+ splitPaneH.setRightComponent(paintScrollPane);
+ splitPaneH.setContinuousLayout(true);
+ splitPaneH.setOneTouchExpandable(true);
+ */
+
+ splitPaneV.setOrientation(JSplitPane.VERTICAL_SPLIT);
+ //splitPaneV.setTopComponent(splitPaneH);
+ splitPaneV.setTopComponent(paintScrollPane);
+ splitPaneV.setBottomComponent(loggingPane);
+ splitPaneV.setOneTouchExpandable(true);
+ splitPaneV.setContinuousLayout(true);
+
+ Container contentPane = getContentPane();
+ contentPane.add(splitPaneV, BorderLayout.CENTER);
+
+
+ return contentPane;
+ }
+
+ private JPanel createToolsPanel() {
+ JPanel toolsPanel = new JPanel();
+
+ toolsPanel.setLayout(new BoxLayout(toolsPanel, BoxLayout.X_AXIS));
+ JCheckBox loggingActiveCheckBox = new JCheckBox(prefs.getString("lang.logging.active"));
+ loggingActiveCheckBox.setSelected(true);
+ loggingActiveCheckBox.addChangeListener(new ChangeListener() {
+ public void stateChanged(ChangeEvent ce) {
+ AbstractButton abstractButton = (AbstractButton) ce.getSource();
+ ButtonModel buttonModel = abstractButton.getModel();
+ logging.isPaused(!buttonModel.isSelected());
+ }
+ });
+ toolsPanel.add(loggingActiveCheckBox);
+
+ JCheckBox 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();
+ simulationPanel.showLamport(buttonModel.isSelected());
+ }
+ });
+ toolsPanel.add(lamportActiveCheckBox);
+
+ return toolsPanel;
+ }
+
+ /*
+ private JPanel createProcessEditPanel() {
+ JPanel editPanel = new JPanel(new GridBagLayout());
+ editPanel.setBackground(Color.WHITE);
+
+ GridBagConstraints constraints = new GridBagConstraints();
+ constraints.fill = GridBagConstraints.HORIZONTAL;
+
+ Insets insets = new Insets(5, 5, 5, 5);
+ constraints.insets = insets;
+ constraints.ipady = 5;
+ constraints.ipadx = 5;
+ int row = 0;
+
+ Vector<VSProcess> processes = simulationPanel.getProcesses();
+
+ for (VSProcess p : processes) {
+ constraints.gridy = row++;
+ //editPanel.add(new VSProcessEditor(prefs, p), constraints);
+ }
+
+ return editPanel;
+ }
+ */
+
+ public int getSplitSize() {
+ return 0;//splitPaneH.getDividerLocation();
+ }
+
+ public int getPaintSize() {
+ return splitPaneV.getDividerLocation();
+ }
+
+ public void dispose() {
+ simulationPanel.finalize();
+ super.dispose();
+ }
+
+ public void actionPerformed(ActionEvent e) {
+ JMenuItem source = (JMenuItem) e.getSource();
+
+ if (source.getText().equals(prefs.getString("lang.close"))) {
+ dispose();
+
+ } else if (source.getText().equals(prefs.getString("lang.new"))) {
+ new VSMain(VSDefaultPrefs.initialize(), VSSimulation.this);
+
+ } else if (source.getText().equals(prefs.getString("lang.about"))) {
+ new VSAbout(prefs, VSSimulation.this);
+
+ } else if (source.getText().equals(prefs.getString("lang.quit"))) {
+ System.exit(0);
+
+ } else if (source.getText().equals(prefs.getString("lang.start"))) {
+ startItem.setEnabled(false);
+ pauseItem.setEnabled(true);
+ resetItem.setEnabled(false);
+ replayItem.setEnabled(true);
+ runThread();
+
+ } else if (source.getText().equals(prefs.getString("lang.pause"))) {
+ startItem.setEnabled(true);
+ pauseItem.setEnabled(false);
+ resetItem.setEnabled(true);
+ replayItem.setEnabled(true);
+ simulationPanel.pause();
+
+ } else if (source.getText().equals(prefs.getString("lang.reset"))) {
+ startItem.setEnabled(true);
+ pauseItem.setEnabled(false);
+ resetItem.setEnabled(false);
+ replayItem.setEnabled(false);
+ simulationPanel.reset();
+
+ } else if (source.getText().equals(prefs.getString("lang.replay"))) {
+ startItem.setEnabled(false);
+ pauseItem.setEnabled(true);
+ resetItem.setEnabled(false);
+ replayItem.setEnabled(true);
+ simulationPanel.reset();
+ runThread();
+ }
+ }
+
+ private void runThread() {
+ if (hasStarted) {
+ simulationPanel.play();
+
+ } else {
+ hasStarted = true;
+ thread = new Thread(simulationPanel);
+ thread.start();
+ }
+ }
+
+ public void finish() {
+ startItem.setEnabled(false);
+ pauseItem.setEnabled(false);
+ resetItem.setEnabled(true);
+ replayItem.setEnabled(true);
+ }
+}
diff --git a/sources/simulator/VSSimulationPanel.java b/sources/simulator/VSSimulationPanel.java
new file mode 100644
index 0000000..f0d3d75
--- /dev/null
+++ b/sources/simulator/VSSimulationPanel.java
@@ -0,0 +1,619 @@
+package simulator;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.awt.geom.*;
+import java.util.*;
+import javax.swing.*;
+
+import core.*;
+import editors.*;
+import prefs.*;
+import utils.*;
+import events.*;
+
+public class VSSimulationPanel extends JPanel implements Runnable, MouseMotionListener, MouseListener, HierarchyBoundsListener {
+ private VSProcess highlightedProcess;
+ private VSSimulation simulation;
+ private VSPrefs prefs;
+ private VSLogging logging;
+ private int numProcesses;
+ private int secondsSpaceing;
+ private int threadSleep;
+ private long untilTime;
+ private volatile boolean isPaused = false;
+ private volatile boolean isFinalized = false;
+ private volatile boolean isFinished = false;
+ private volatile boolean isResetted = false;
+ private volatile boolean showLamport = false;
+ private volatile long pauseTime;
+ private volatile long startTime;
+ private volatile long time;
+ private volatile long lastTime;
+ private VSTaskManager taskManager;
+ private LinkedList<VSMessageLine> messageLines;
+ private LinkedList<VSProcess> processes;
+
+ /* Static constats */
+ private static final int LINE_WIDTH = 5;
+ private static final int SEPLINE_WIDTH = 2;
+ private static final int XOFFSET = 50;
+ private static final int YOFFSET = 30;
+ private static final int YOUTER_SPACEING = 10;
+ private static final int YSEPLINE_SPACEING = 20;
+ private static final int TEXT_SPACEING = 10;
+
+ /* Constats, which have to get calculated once after start */
+ private Color processlineColor;
+ private Color processSecondlineColor;
+ private Color processSeplineColor;
+ private Color messageArrivedColor;
+ private Color messageSendingColor;
+ private Color messageLostColor;
+
+ private class VSMessageLine {
+ private VSProcess receiverProcess;
+ private Color color;
+ private long sendTime;
+ private long recvTime;
+ private int senderNum;
+ private int receiverNum;
+ private int offset1;
+ private int offset2;
+ private boolean isArrived;
+ private boolean isLost;
+ private double x1;
+ private double y1;
+ private double x2;
+ private double y2;
+ private double x;
+ private double y;
+ private long outageTime;
+ private long z;
+
+ public VSMessageLine(VSProcess receiverProcess, long sendTime, long recvTime, long outageTime, int senderNum , int receiverNum) {
+ this.receiverProcess = receiverProcess;
+ this.sendTime = sendTime;
+ this.recvTime = recvTime;
+ this.outageTime = outageTime;
+ this.senderNum = senderNum;
+ this.receiverNum = receiverNum;
+ this.isArrived = false;
+ this.isLost = false;
+
+ 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) + offset1;
+
+ recalcOnWindowChanged();
+ }
+
+ public void recalcOnWindowChanged() {
+ x1 = getTimeXPosition(sendTime);
+ y1 = getProcessYPosition(senderNum) + offset1;
+ x2 = getTimeXPosition(recvTime);
+ y2 = getProcessYPosition(receiverNum) + offset2;
+
+ if (isLost) {
+ x = getTimeXPosition(z);
+ y = y1 + ( ( (y2-y1) / (x2-x1)) * (x-x1));
+ }
+ }
+
+ 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) {
+ isArrived = true;
+ if (receiverProcess.isCrashed())
+ color = messageLostColor;
+ else
+ color = messageArrivedColor;
+ draw(g, globalTime);
+
+ } else if (outageTime >= 0 && outageTime <= globalTime){
+ 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);
+ }
+ }
+ }
+
+ public VSSimulationPanel(VSPrefs prefs, VSSimulation simulation, VSLogging logging) {
+ this.prefs = prefs;
+ this.simulation = simulation;
+ this.logging = logging;
+ this.taskManager = new VSTaskManager(prefs);
+ this.messageLines = new LinkedList<VSMessageLine>();
+ this.processes = new LinkedList<VSProcess>();
+
+ numProcesses = prefs.getInteger("sim.process.num");
+ untilTime = prefs.getInteger("sim.seconds") * 1000;
+ recalcOnWindowChanged();
+
+ secondsSpaceing = (int) untilTime / 15000;
+ if (secondsSpaceing == 0)
+ secondsSpaceing = 1;
+
+ threadSleep = (int) untilTime / 7500;
+ if (threadSleep == 0)
+ threadSleep = 1;
+
+ VSProcess.resetProcessCounter();
+ for (int i = 0; i < numProcesses; ++i)
+ createProcess(i);
+
+ addMouseListener(this);
+ addMouseMotionListener(this);
+ addHierarchyBoundsListener(this);
+ }
+
+ double xPaintSize;
+ double paintSize;
+ double yDistance;
+ double globalTimeXPosition;
+
+ int xoffset_plus_xpaintsize;
+ double xpaintsize_dividedby_untiltime;
+ int paintProcessesOffset;
+
+ int paintSecondlinesSeconds;
+ int paintSecondlinesLine[] = new int[4];
+ int paintSecondlinesYStringPos1;
+ int paintSecondlinesYStringPos2;
+ int paintGlobalTimeYPosition;
+
+ /* This method contains very ugly code. But this has to be in order to gain performance! */
+ private void recalcOnWindowChanged() {
+ processlineColor = prefs.getColor("process.line");
+ processSecondlineColor = prefs.getColor("process.secondline");
+ processSeplineColor = prefs.getColor("process.sepline");
+ messageArrivedColor = prefs.getColor("message.arrived");
+ messageSendingColor = prefs.getColor("message.sending");
+ messageLostColor = prefs.getColor("message.lost");
+
+ paintSize = simulation.getPaintSize();
+ xPaintSize = simulation.getWidth() - (3 * XOFFSET + simulation.getSplitSize());
+ yDistance = (simulation.getPaintSize() - 2 * (YOFFSET + YOUTER_SPACEING))/ numProcesses;
+ xpaintsize_dividedby_untiltime = xPaintSize / (double) untilTime;
+
+ for (VSMessageLine messageLine : messageLines)
+ messageLine.recalcOnWindowChanged();
+
+ /* 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);
+ }
+ }
+
+ public VSProcess createProcess(int i) {
+ VSProcess process = new VSProcess(prefs, this, logging, i+1);
+ processes.add(process);
+ logging.logg(prefs.getString("lang.process.new") + "; " + process);
+
+ return process;
+ }
+
+ private void updateSimulation(final long globalTime, final long lastGlobalTime) {
+ final long offset = globalTime - lastGlobalTime;
+ for (long l = 0; l < offset; ++l)
+ taskManager.runVSTasks(l, offset, lastGlobalTime);
+
+ for (VSProcess process : processes)
+ process.syncTime(globalTime);
+ }
+
+ public void paintComponent(Graphics g) {
+ super.paintComponent(g);
+
+ final long globalTime = time;
+ final Graphics2D g2d = (Graphics2D) g;
+
+ globalTimeXPosition = getTimeXPosition(globalTime);
+
+ paintSecondlines(g2d);
+ paintProcesses(g2d, globalTime);
+ paintGlobalTime(g2d, globalTime);
+
+ synchronized (messageLines) {
+ for (VSMessageLine line : messageLines)
+ line.draw(g2d, globalTime);
+ }
+
+ }
+
+ 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 };
+
+ for (VSProcess process : processes) {
+ final long localTime = process.getTime();
+
+ g.setColor(process.getColor());
+ g.fillPolygon(xPoints, yPoints, 5);
+ if (process.isCrashed()) {
+ final VSTask crashTask = process.getCrashTask();
+ final int crashPos = (int) getTimeXPosition(crashTask.getTaskTime());
+ final int xPointsCrashed[] = { crashPos, xoffset_plus_xpaintsize, xoffset_plus_xpaintsize, crashPos, crashPos };
+ g.setColor(process.getCrashedColor());
+ g.fillPolygon(xPointsCrashed, yPoints, 5);
+ }
+
+ 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) {
+ int last = -1;
+ final int distance = 20;
+ final VSLamport[] lamportStamps = process.getLamportArray();
+ for (VSLamport lamport : lamportStamps) {
+ int xPos_ = (int) getTimeXPosition(lamport.getTime());
+ if (last >= 0) {
+ int diff = xPos_ - last;
+ if (diff < distance)
+ xPos_ += distance - diff;
+ }
+ g.drawString(""+lamport.getLamportTime(), xPos_ + 2, yStart + 3 * TEXT_SPACEING);
+ last = xPos_;
+ }
+ }
+
+ for (int i = 0; i < 5; ++i)
+ yPoints[i] += paintProcessesOffset;
+ }
+ }
+
+ 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);
+ 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]);
+ }
+ }
+
+ 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);
+ }
+
+ private VSProcess 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)
+ return processes.get(i);
+ y += yOffset;
+ }
+
+ return null;
+ }
+
+ private double getTimeXPosition(long time) {
+ return XOFFSET + xpaintsize_dividedby_untiltime * time;
+ }
+
+ 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;
+ }
+
+ public long getTime() {
+ return time;
+ }
+
+ public long getUntilTime() {
+ return untilTime;
+ }
+
+ public long getStartTime() {
+ return startTime;
+ }
+
+ public VSTaskManager getTaskManager() {
+ return taskManager;
+ }
+
+ public int getNumProcesses() {
+ return numProcesses;
+ }
+
+ public void run() {
+ play();
+
+ while (true) {
+ while (!isPaused && !isFinalized) {
+ try {
+ Thread.sleep(threadSleep);
+ } catch (Exception e) {
+ System.out.println(e);
+ }
+
+ updateSimulation(time, lastTime);
+ repaint();
+
+ lastTime = time;
+ time = System.currentTimeMillis() - startTime;
+
+ if (time > untilTime)
+ time = untilTime;
+
+ if (time == untilTime) {
+ finish();
+ break;
+ }
+ }
+
+ if (isPaused) {
+ for (VSProcess p : processes)
+ p.pause();
+
+ pauseTime = System.currentTimeMillis();
+
+ logging.logg(prefs.getString("lang.simulation.paused"));
+ repaint();
+ }
+
+ updateSimulation(time, lastTime);
+ repaint();
+
+ while (!isFinalized && (isPaused || isFinished || isResetted)) {
+ try {
+ Thread.sleep(100);
+ repaint();
+ } catch (Exception e) {
+ System.out.println(e);
+ }
+ }
+
+ if (isFinalized)
+ break; /* Exit the thread */
+ }
+ }
+
+ public void play() {
+ logging.logg(prefs.getString("lang.simulation.started"));
+ final long currentTime = System.currentTimeMillis();
+
+ for (VSProcess p : processes)
+ p.play();
+
+ if (isResetted)
+ isResetted = false;
+
+ else if (isFinished)
+ isFinished = false;
+
+ if (isPaused) {
+ isPaused = false;
+ startTime += currentTime - pauseTime;
+ time = currentTime - startTime;
+
+ } else {
+ startTime = currentTime;
+ time = 0;
+ }
+
+ repaint();
+ }
+
+ public void finish() {
+ for (VSProcess p : processes)
+ p.finish();
+
+ simulation.finish();
+ isFinished = true;
+
+ logging.logg(prefs.getString("lang.simulation.finished"));
+ repaint();
+ }
+
+ public void pause() {
+ isPaused = true;
+ }
+
+ public void reset() {
+ if (!isResetted) {
+ logging.logg(prefs.getString("lang.simulation.resetted"));
+
+ isResetted = true;
+ isPaused = false;
+ isFinished = false;
+ startTime = System.currentTimeMillis();
+ time = 0;
+ lastTime = 0;
+
+ taskManager.reset();
+
+ for (VSProcess p : processes)
+ p.reset();
+
+ synchronized (messageLines) {
+ messageLines.clear();
+ }
+ repaint();
+ }
+ }
+
+ public void finalize() {
+ isFinalized = true;
+ }
+
+ public boolean isFinalized() {
+ return isFinalized;
+ }
+
+ public void showLamport(boolean showLamport) {
+ this.showLamport = showLamport;
+ repaint();
+ }
+
+ public void sendMessage(VSMessage message) {
+ VSTask task = null;
+ VSProcess sendingProcess = message.getSendingProcess();
+ long deliverTime, outageTime, durationTime;
+
+ for (VSProcess receiverProcess : processes) {
+ if (receiverProcess.equals(sendingProcess)) {
+ deliverTime = sendingProcess.getGlobalTime();
+ task = new VSTask(deliverTime, receiverProcess, message);
+ taskManager.addTask(task);
+
+ } else {
+ durationTime = sendingProcess.getDurationTime();
+ deliverTime = sendingProcess.getGlobalTime() + durationTime;
+ outageTime = sendingProcess.getARandomMessageOutageTime(durationTime);
+
+ /* Only add a 'receiving message' task if the message will not get lost! */
+ if (outageTime == -1) {
+ task = new VSTask(deliverTime, receiverProcess, message);
+ taskManager.addTask(task);
+ }
+
+ synchronized (messageLines) {
+ messageLines.add(new VSMessageLine(receiverProcess,
+ sendingProcess.getGlobalTime(), deliverTime, outageTime,
+ sendingProcess.getNum(), receiverProcess.getNum()));
+ }
+ }
+ }
+ }
+
+ public void mouseClicked(MouseEvent e) {
+ VSProcess process = getProcessAtYPos(e.getY());
+ if (process != null) {
+ process.updatePrefs();
+ new VSProcessEditor(prefs, simulation, process);
+ }
+ }
+
+ public void mouseEntered(MouseEvent e) { }
+
+ public void mouseExited(MouseEvent e) {
+ if (highlightedProcess != null) {
+ highlightedProcess.highlightOff();
+ highlightedProcess = null;
+ repaint();
+ }
+ }
+
+ public void mousePressed(MouseEvent e) { }
+
+ public void mouseReleased(MouseEvent e) { }
+
+ public void mouseDragged(MouseEvent e) { }
+
+ public void mouseMoved(MouseEvent e) {
+ VSProcess p = getProcessAtYPos(e.getY());
+
+ if (p == null) {
+ if (highlightedProcess != null) {
+ highlightedProcess.highlightOff();
+ highlightedProcess = null;
+ repaint();
+ }
+
+ return;
+ }
+
+ if (highlightedProcess != null) {
+ if (highlightedProcess.getProcessID() != p.getProcessID()) {
+ highlightedProcess.highlightOff();
+ highlightedProcess = p;
+ p.highlightOn();
+ repaint();
+ }
+ } else {
+ highlightedProcess = p;
+ p.highlightOn();
+ repaint();
+ }
+ }
+
+ public void ancestorMoved(HierarchyEvent e) { }
+
+ public void ancestorResized(HierarchyEvent e) {
+ recalcOnWindowChanged();
+ }
+}