diff options
| author | Paul Buetow <paul@buetow.org> | 2008-05-15 23:08:33 +0000 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2008-05-15 23:08:33 +0000 |
| commit | d4c1ddcc90c1e2e8660598fc36b3772d2bff6816 (patch) | |
| tree | 28a0afc255e42f92adbca0d102e785301bc43a58 /sources/simulator | |
| parent | 61599471a5978c1521b9c89c044ac2ce9a88c398 (diff) | |
1 Moved the stuff to trunk!
Diffstat (limited to 'sources/simulator')
| -rw-r--r-- | sources/simulator/VSAbout.java | 63 | ||||
| -rw-r--r-- | sources/simulator/VSLogging.java | 57 | ||||
| -rw-r--r-- | sources/simulator/VSMain.java | 34 | ||||
| -rw-r--r-- | sources/simulator/VSSimulation.java | 311 | ||||
| -rw-r--r-- | sources/simulator/VSSimulationPanel.java | 619 |
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(); + } +} |
