summaryrefslogtreecommitdiff
path: root/sources/simulator/VSSimulatorCanvas.java
diff options
context:
space:
mode:
Diffstat (limited to 'sources/simulator/VSSimulatorCanvas.java')
-rw-r--r--sources/simulator/VSSimulatorCanvas.java949
1 files changed, 949 insertions, 0 deletions
diff --git a/sources/simulator/VSSimulatorCanvas.java b/sources/simulator/VSSimulatorCanvas.java
new file mode 100644
index 0000000..6e24270
--- /dev/null
+++ b/sources/simulator/VSSimulatorCanvas.java
@@ -0,0 +1,949 @@
+package simulator;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.awt.geom.*;
+import java.awt.image.*;
+import java.util.*;
+import javax.swing.*;
+
+import core.*;
+import core.time.*;
+import events.*;
+import events.implementations.*;
+import events.internal.*;
+import prefs.*;
+import prefs.editors.*;
+import utils.*;
+
+public class VSSimulatorCanvas extends Canvas implements Runnable, MouseMotionListener, MouseListener, HierarchyBoundsListener {
+ private VSProcess highlightedProcess;
+ private VSSimulator simulation;
+ private VSPrefs prefs;
+ private VSLogging logging;
+ private volatile int numProcesses;
+ private int secondsSpaceing;
+ private int threadSleep;
+ private long untilTime;
+ private volatile boolean isPaused = true;
+ private volatile boolean isThreadStopped = false;
+ private volatile boolean isFinished = false;
+ private volatile boolean isResetted = false;
+ private volatile boolean isAntiAliased = false;
+ private volatile boolean isAntiAliasedChanged = false;
+ private volatile boolean showLamport = false;
+ private volatile boolean showVectorTime = 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 Vector<VSProcess> processes;
+ private double clockSpeed;
+ private double clockOffset;
+ private long simulationTime;
+
+ /* GFX buffering */
+ private BufferStrategy strategy;
+ private Graphics2D g;
+
+ /* 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 = 15;
+ private static final int YSEPLINE_SPACEING = 20;
+ private static final int TEXT_SPACEING = 10;
+ private static final int ROW_HEIGHT = 14;
+
+ /* 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 Color backgroundColor;
+
+ private long messageLineCounter;
+ 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;
+ private long messageLineNum;
+ private VSTask task;
+
+ public VSMessageLine(VSProcess 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();
+ }
+
+ 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));
+ }
+
+ }
+
+ 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 boolean removeProcessAtIndex(int index) {
+ if (index == receiverNum || index == senderNum)
+ return true;
+
+ if (index < receiverNum)
+ --receiverNum;
+
+ if (index < senderNum)
+ --senderNum;
+
+ recalcOnChange();
+
+ return false;
+ }
+
+ public long getMessageLineNum() {
+ return messageLineNum;
+ }
+
+ public boolean equals(VSMessageLine line) {
+ return messageLineNum == line.getMessageLineNum();
+ }
+
+ public VSTask getTask() {
+ return task;
+ }
+ }
+
+ public VSSimulatorCanvas(VSPrefs prefs, VSSimulator 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 Vector<VSProcess>();
+
+ numProcesses = prefs.getInteger("sim.process.num");
+ updateFromPrefs();
+
+ VSProcess.resetProcessCounter();
+ for (int i = 0; i < numProcesses; ++i)
+ processes.add(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 recalcOnChange() {
+ 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 = 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.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);
+ }
+ }
+ }
+
+ private void updateSimulation(final long globalTime, final long lastGlobalTime) {
+ if (isPaused || isFinished)
+ return;
+
+ final long lastSimulationTime = simulationTime;
+ long offset = globalTime - lastGlobalTime;
+
+ clockOffset += offset * clockSpeed;
+
+ while (clockOffset >= 1) {
+ --clockOffset;
+ ++simulationTime;
+ }
+
+ if (simulationTime > untilTime)
+ simulationTime = untilTime;
+
+ offset = simulationTime - lastSimulationTime;
+
+ for (long l = 0; l < offset; ++l)
+ taskManager.runTasks(l, offset, lastSimulationTime);
+
+ synchronized (processes) {
+ for (VSProcess process : processes)
+ process.syncTime(simulationTime);
+ }
+ }
+
+ 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());
+ final long globalTime = simulationTime;
+
+ globalTimeXPosition = getTimeXPosition(globalTime);
+ paintSecondlines(g);
+ paintProcesses(g, globalTime);
+ paintGlobalTime(g, globalTime);
+
+ synchronized (messageLines) {
+ for (VSMessageLine line : messageLines)
+ line.draw(g, globalTime);
+ }
+
+ g.setColor(backgroundColor);
+
+ strategy.show();
+ }
+ }
+
+ 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 (VSProcess 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;
+ }
+ }
+ }
+
+ private void paintTime(final Graphics2D g, final VSTime times[], final VSProcess 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;
+ }
+ }
+
+ 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]);
+ }
+ }
+
+ 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)));
+
+ //System.out.println("JO " + yPos + " " + yDistance + " " + yOffset);
+ 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 simulationTime;
+ }
+
+ public long getUntilTime() {
+ return untilTime;
+ }
+
+ public long getStartTime() {
+ return startTime;
+ }
+
+ public VSTaskManager getTaskManager() {
+ return taskManager;
+ }
+
+ public int getNumProcesses() {
+ return numProcesses;
+ }
+
+ public VSProcess getProcess(int processNum) {
+ if (processNum >= processes.size())
+ return null;
+
+ return processes.get(processNum);
+ }
+
+ public void run() {
+ while (true) {
+ while (!isThreadStopped && (isPaused || isFinished || isResetted)) {
+ try {
+ Thread.sleep(100);
+ paint();
+ } catch (Exception e) {
+ System.out.println(e);
+ }
+ }
+
+ if (isThreadStopped)
+ break; /* Exit the thread */
+
+ while (!isPaused && !isThreadStopped) {
+ try {
+ Thread.sleep(threadSleep);
+ } catch (Exception e) {
+ System.out.println(e);
+ }
+
+ updateSimulation(time, lastTime);
+
+ if (simulationTime == untilTime) {
+ finish();
+ break;
+ }
+
+ paint();
+ lastTime = time;
+ time = System.currentTimeMillis() - startTime;
+
+ }
+
+ updateSimulation(time, lastTime);
+ paint();
+ }
+ }
+
+ public void play() {
+ logging.logg(prefs.getString("lang.simulation.started"));
+ final long currentTime = System.currentTimeMillis();
+
+ synchronized (processes) {
+ 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;
+ }
+
+ paint();
+ }
+
+ public void finish() {
+ synchronized (processes) {
+ for (VSProcess p : processes)
+ p.finish();
+ }
+
+ simulation.finish();
+ isFinished = true;
+
+ logging.logg(prefs.getString("lang.simulation.finished"));
+ paint();
+ }
+
+ public void pause() {
+ isPaused = true;
+ synchronized (processes) {
+ for (VSProcess p : processes)
+ p.pause();
+ }
+
+ pauseTime = System.currentTimeMillis();
+
+ logging.logg(prefs.getString("lang.simulation.paused"));
+ paint();
+ }
+
+ 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;
+ clockOffset = 0;
+ simulationTime = 0;
+
+ synchronized (processes) {
+ for (VSProcess process : processes)
+ process.reset();
+ }
+
+ /* Reset the task manager AFTER the processes, for the programmed tasks */
+ taskManager.reset();
+
+ synchronized (processes) {
+ for (VSProcess process : processes)
+ process.createRandomCrashTask();
+ }
+
+ synchronized (messageLines) {
+ messageLines.clear();
+ }
+
+ paint();
+ logging.clear();
+ }
+ }
+
+ public void stopThread() {
+ isThreadStopped = true;
+ }
+
+ public boolean isThreadStopped() {
+ return isThreadStopped;
+ }
+
+ public void showLamport(boolean showLamport) {
+ this.showLamport = showLamport;
+ if (isPaused)
+ paint();
+ }
+
+ public void showVectorTime(boolean showVectorTime) {
+ this.showVectorTime = showVectorTime;
+ if (isPaused)
+ paint();
+ }
+
+ public void isAntiAliased(boolean isAntiAliased) {
+ this.isAntiAliased = isAntiAliased;
+ this.isAntiAliasedChanged = true;
+ if (isPaused)
+ paint();
+ }
+
+ public void sendMessage(VSMessage message) {
+ VSTask task = null;
+ VSEvent messageReceiveEvent = null;
+ VSProcess sendingProcess = message.getSendingProcess();
+ long deliverTime, outageTime, durationTime;
+ boolean recvOwn = prefs.getBoolean("sim.message.own.recv");
+
+ synchronized (processes) {
+ for (VSProcess receiverProcess : processes) {
+ if (receiverProcess.equals(sendingProcess)) {
+ if (recvOwn) {
+ deliverTime = sendingProcess.getGlobalTime();
+ messageReceiveEvent = new MessageReceiveEvent(message);
+ task = new VSTask(deliverTime, receiverProcess, messageReceiveEvent, VSTask.GLOBAL);
+ 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) {
+ messageReceiveEvent = new MessageReceiveEvent(message);
+ task = new VSTask(deliverTime, receiverProcess, messageReceiveEvent, VSTask.GLOBAL);
+ taskManager.addTask(task);
+ }
+
+ synchronized (messageLines) {
+ messageLines.add(
+ new VSMessageLine(receiverProcess, sendingProcess.getGlobalTime(),
+ deliverTime, outageTime, sendingProcess.getProcessNum(),
+ receiverProcess.getProcessNum(), task));
+ }
+ }
+ }
+ }
+ }
+
+ public void mouseClicked(MouseEvent me) {
+ final VSProcess process = getProcessAtYPos(me.getY());
+
+ if (SwingUtilities.isRightMouseButton(me)) {
+ ActionListener actionListener = new ActionListener() {
+ public void actionPerformed(ActionEvent ae) {
+ String actionCommand = ae.getActionCommand();
+ if (actionCommand.equals(prefs.getString("lang.process.edit"))) {
+ editProcess(process);
+
+ } else if (actionCommand.equals(prefs.getString("lang.process.crash"))) {
+ VSEvent event = new ProcessCrashEvent();
+ taskManager.addTask(new VSTask(process.getGlobalTime(), process, event, VSTask.GLOBAL));
+
+ } else if (actionCommand.equals(prefs.getString("lang.process.recover"))) {
+ VSEvent event = new ProcessRecoverEvent();
+ taskManager.addTask(new VSTask(process.getGlobalTime(), process, event, VSTask.GLOBAL));
+
+ } else if (actionCommand.equals(prefs.getString("lang.process.remove"))) {
+ removeProcess(process);
+
+ } else if (actionCommand.equals(prefs.getString("lang.process.add.new"))) {
+ addProcess();
+ }
+ }
+ };
+
+
+ JPopupMenu popup = new JPopupMenu();
+ JMenuItem item = new JMenuItem(prefs.getString("lang.process.edit"));
+ if (process == null)
+ item.setEnabled(false);
+ else
+ item.addActionListener(actionListener);
+ popup.add(item);
+
+ item = new JMenuItem(prefs.getString("lang.process.crash"));
+ if (process == null || process.isCrashed() || isPaused || time == 0 || isFinished)
+ item.setEnabled(false);
+ else
+ item.addActionListener(actionListener);
+ popup.add(item);
+
+ item = new JMenuItem(prefs.getString("lang.process.recover"));
+ if (process == null || !process.isCrashed() || isPaused || time == 0 || isFinished)
+ item.setEnabled(false);
+ else
+ item.addActionListener(actionListener);
+ popup.add(item);
+
+ item = new JMenuItem(prefs.getString("lang.process.remove"));
+ if (process == null)
+ item.setEnabled(false);
+ else
+ item.addActionListener(actionListener);
+ popup.add(item);
+
+ popup.addSeparator();
+
+ item = new JMenuItem(prefs.getString("lang.process.add.new"));
+ item.addActionListener(actionListener);
+ popup.add(item);
+
+
+ popup.show(me.getComponent(), me.getX(), me.getY());
+
+ } else {
+ editProcess(process);
+ }
+ }
+
+ public void editProcess(int processNum) {
+ VSProcess process = processes.get(processNum);
+ editProcess(process);
+ }
+
+ public void editProcess(VSProcess process) {
+ if (process != null) {
+ process.updatePrefs();
+ new VSEditorFrame(prefs, simulation.getSimulatorFrame(),
+ new VSProcessEditor(prefs, process));
+ }
+ }
+
+ public void mouseEntered(MouseEvent e) { }
+
+ public void mouseExited(MouseEvent e) {
+ if (highlightedProcess != null) {
+ highlightedProcess.highlightOff();
+ highlightedProcess = null;
+ paint();
+ }
+ }
+
+ 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;
+ }
+
+ 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();
+ }
+
+ public void ancestorMoved(HierarchyEvent e) { }
+
+ public void ancestorResized(HierarchyEvent e) {
+ recalcOnChange();
+ }
+
+ public ArrayList<VSProcess> getProcessesArray() {
+ ArrayList<VSProcess> arr = new ArrayList<VSProcess>();
+
+ synchronized (processes) {
+ for (VSProcess process : processes)
+ arr.add(process);
+ }
+
+ return arr;
+ }
+
+ 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();
+ }
+
+ private void removeProcess(VSProcess process) {
+ if (numProcesses == 1) {
+ simulation.getSimulatorFrame().removeSimulation(simulation);
+
+ } else {
+ int index = processes.indexOf(process);
+ processes.remove(index);
+ synchronized (processes) {
+ for (VSProcess p : processes) {
+ p.removeProcessAtIndex(index);
+ }
+ }
+ numProcesses = processes.size();
+ simulation.removeProcessAtIndex(index);
+ recalcOnChange();
+
+ ArrayList<VSMessageLine> removeThose = new ArrayList<VSMessageLine>();
+ synchronized (messageLines) {
+ for (VSMessageLine line : messageLines)
+ if (line.removeProcessAtIndex(index))
+ removeThose.add(line);
+ for (VSMessageLine line : removeThose) {
+ VSTask deliverTask = line.getTask();
+ if (deliverTask != null)
+ taskManager.removeTask(deliverTask);
+ messageLines.remove(line);
+ }
+ }
+
+ taskManager.removeTasksOf(process);
+ }
+ }
+
+ private VSProcess createProcess(int processNum) {
+ VSProcess process = new VSProcess(prefs, processNum, this, logging);
+ logging.logg(prefs.getString("lang.process.new") + "; " + process);
+ return process;
+ }
+
+ private void addProcess() {
+ numProcesses = processes.size() + 1;
+ VSProcess newProcess = createProcess(processes.size());
+ processes.add(newProcess);
+ synchronized (processes) {
+ for (VSProcess process : processes)
+ if (!process.equals(newProcess))
+ process.addedAProcess();
+ }
+ recalcOnChange();
+ simulation.addProcessAtIndex(processes.size()-1);
+ }
+}