/* Copyright 2006 by Sean Luke and George Mason University Licensed under the Academic Free License version 3.0 See the file "LICENSE" for more information */ package sim.portrayal.inspector; import java.awt.*; import java.awt.event.*; import sim.util.*; import java.io.*; import sim.display.*; import sim.engine.*; import javax.swing.*; import sim.util.gui.*; /** A PropertyInspector which streams its result out to a file, window, or stream. */ public class StreamingPropertyInspector extends PropertyInspector { PrintWriter out; boolean shouldCloseOnStop = true; int streamingTo; int interval = 1; static final int CUSTOM = -1; static final int FILE = 0; static final int WINDOW = 1; static final int STDOUT = 2; JTextArea area; JScrollPane pane; JFrame frame; double lastTime = Schedule.BEFORE_SIMULATION; public static String name() { return "Stream"; } public static Class[] types() { return null; } // accepts all types /** Creates a custom StreamingPropertyInspector which writes to the provided stream, with the associated short name streamName. This constructor is intended for people who want to create custom streaming inspectors programmatically. */ public StreamingPropertyInspector(Properties properties, int index, Frame parent, GUIState simulation, PrintWriter stream, String streamName) { super(properties,index,parent,simulation); out = stream; setLayout(new BorderLayout()); add(new JLabel("Streaming to..."), BorderLayout.NORTH); add(new JLabel(streamName), BorderLayout.CENTER); streamingTo = CUSTOM; setValidInspector(true); } public StreamingPropertyInspector(final Properties properties, final int index, final Frame parent, final GUIState simulation) { super(properties,index,parent,simulation); Object[] possibilities = {"A file (overwriting)", "A file (appending)", "A window", "Standard Out"}; String s = (String)JOptionPane.showInputDialog( parent, "Stream the property to:", "Stream", JOptionPane.PLAIN_MESSAGE, null, possibilities, possibilities[0]); if (s!=null) // valid inspector maybe? { // make the interval (skip) field NumberTextField skipField = new NumberTextField("Skip: ", 1, false) { public double newValue(double newValue) { int val = (int) newValue; if (val < 1) val = (int)currentValue; interval = val; return val; } }; skipField.setToolTipText("Specify the number of steps between stream fetches"); skipField.setBorder(BorderFactory.createEmptyBorder(2,2,0,2)); if (s.equals(possibilities[0]) || s.equals(possibilities[1])) { streamingTo = FILE; FileDialog fd = new FileDialog(parent,"Stream the Property " + (s.equals(possibilities[1]) ? "(appending) " : "") + "\"" + properties.getName(index) + "\" to File...", FileDialog.SAVE); fd.setFile(properties.getName(index)+".out"); fd.setVisible(true); if (fd.getFile()!=null) try { File file = new File(fd.getDirectory(), Utilities.ensureFileEndsWith(fd.getFile(),".out")); // we'll make a writer that appends or doesn't append -- note we use // new FileWriter(String,appends) because new FileWriter(file,appends) // is only available in Java 1.4 and up. out = new PrintWriter(new BufferedWriter(new FileWriter(file.getCanonicalPath(), s.equals(possibilities[1])))); setLayout(new BorderLayout()); Box b = new Box(BoxLayout.Y_AXIS); b.add(skipField); b.add(new JLabel("Streaming to" + (s.equals(possibilities[1]) ? " (appending)" : "") + "...")); b.add(new JLabel(file.getPath())); b.add(new JLabel("Format: \"timestamp: value\"")); b.add(Box.createGlue()); add(b,BorderLayout.NORTH); setValidInspector(true); } catch (IOException e) { e.printStackTrace(); } } else if (s.equals(possibilities[2])) { streamingTo = WINDOW; area = new JTextArea(); pane = new JScrollPane(area); setLayout(new BorderLayout()); add(pane,BorderLayout.CENTER); add(skipField, BorderLayout.NORTH); Box box = new Box(BoxLayout.X_AXIS); JButton saveButton = new JButton("Save Contents"); box.add(saveButton); saveButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { synchronized(simulation.state.schedule) // stop the simulation for a sec { FileDialog fd = new FileDialog(frame,"Save the (Present) Contents to File...", FileDialog.SAVE); fd.setFile(properties.getName(index)+".out"); fd.setVisible(true); if (fd.getFile()!=null) try { File file = new File(fd.getDirectory(), Utilities.ensureFileEndsWith(fd.getFile(),".out")); // we'll make a writer that appends or doesn't append -- note we use // new FileWriter(String,appends) because new FileWriter(file,appends) // is only available in Java 1.4 and up. PrintWriter p = new PrintWriter(new BufferedWriter(new FileWriter(file))); p.println(area.getText()); p.close(); } catch (IOException ex) { ex.printStackTrace(); } } } }); box.add(new JLabel("Format: \"timestamp: value\"")); box.add(Box.createGlue()); add(box, BorderLayout.SOUTH); setValidInspector(true); } else // s.equals(possibilities[3]) { streamingTo = STDOUT; shouldCloseOnStop = false; // don't want to close System.out! setLayout(new BorderLayout()); Box b = new Box(BoxLayout.Y_AXIS); b.add(skipField); b.add(new JLabel("Streaming to Standard Out"),BorderLayout.CENTER); b.add(new JLabel("Format: \"timestamp/object/property: value\"")); b.add(Box.createGlue()); add(b,BorderLayout.NORTH); setValidInspector(true); } } } public void updateInspector() { double time = simulation.state.schedule.getTime(); if (time >= Schedule.EPOCH && time < Schedule.AFTER_SIMULATION && lastTime <= time - interval) { lastTime = time; switch(streamingTo) { case FILE: case CUSTOM: if (out != null) out.println(time + ": " + properties.getValue(index)); break; case WINDOW: area.append(time + ": " + properties.getValue(index) + "\n"); break; case STDOUT: System.out.println(properties.getObject() + "/" + properties.getName(index) + "/" + time + ": " + properties.getValue(index)); break; default: throw new RuntimeException("default case should never occur"); } } } public Stoppable reviseStopper(Stoppable stopper) { // we want to flush our streams if we've been stopped final Stoppable newStopper = super.reviseStopper(stopper); return new Stoppable() { public void stop() { if (newStopper != null) newStopper.stop(); if (out!=null) { if (streamingTo == STDOUT) out.flush(); else if (streamingTo == FILE || streamingTo == CUSTOM) out.close(); } out = null; // so we don't write to it any more } }; } public JFrame createFrame(final Stoppable stopper) { frame = super.createFrame(stopper); frame.getContentPane().setLayout(new BorderLayout()); // just in case frame.getContentPane().removeAll(); // get rid of the built-in scroller frame.getContentPane().add(this, BorderLayout.CENTER); if (pane!=null) frame.setSize(400,300); else frame.pack(); return frame; } }