Warning: Can't use blame annotator:
svn blame failed on trunk/src/scriptbuilder/gui/panels/IncidentTimelinePanel.java: ("Can't find a temporary directory: Internal error", 20014)

source: tmcsimulator-scriptbuilder/trunk/src/scriptbuilder/gui/panels/IncidentTimelinePanel.java @ 98

Revision 98, 17.0 KB checked in by bmcguffin, 9 years ago (diff)

Added "Add 15 minutes" button, btnAddTime, to both Script Builder and Incident Editor windows. Clicking the button allows the user to add 15 minutes of scrollable space to the end of the timeline window, so that new events can be added after the end. This extra time does not interact with the model and so does not enter the save file, or persist between iterations of the program.

RevLine 
1package scriptbuilder.gui.panels;
2
3import event.editor.frame.Editor;
4import event.editor.frame.Properties;
5import java.awt.BorderLayout;
6import java.awt.Dimension;
7import java.awt.Graphics;
8import java.awt.Graphics2D;
9import java.awt.event.ActionEvent;
10import java.awt.event.ActionListener;
11import java.awt.event.MouseEvent;
12import java.io.File;
13import java.util.HashMap;
14import java.util.Map;
15import javax.swing.JFrame;
16import javax.swing.JMenuItem;
17import javax.swing.JOptionPane;
18import javax.swing.JPanel;
19import javax.swing.JPopupMenu;
20import javax.swing.event.MouseInputAdapter;
21import scriptbuilder.gui.IncidentEditorFrame;
22import scriptbuilder.gui.ScriptBuilderFrame;
23import scriptbuilder.gui.ScriptBuilderGuiConstants;
24import scriptbuilder.gui.drawers.CursorDrawer;
25import scriptbuilder.gui.drawers.EventIconDrawer;
26import scriptbuilder.gui.drawers.IncidentTimelineDrawer;
27import scriptbuilder.structures.ScriptEvent;
28import scriptbuilder.structures.ScriptEvent.ScriptEventType;
29import scriptbuilder.structures.ScriptIncident;
30import scriptbuilder.structures.SimulationScript;
31import scriptbuilder.structures.TimeSlice;
32import scriptbuilder.structures.events.I_ScriptEvent;
33
34/**
35 * Represents a single incident timeline in the GUI. Listens for mouse actions.
36 *
37 * @author Greg Eddington <geddingt@calpoly.edu>
38 * @author Bryan McGuffin
39 * @version 2017/06/30
40 */
41public class IncidentTimelinePanel extends JPanel
42{
43
44    /**
45     * The incident this panel represents.
46     */
47    ScriptIncident incident;
48    /**
49     * If true, this panel is in its minimized state.
50     */
51    //boolean collapsed;
52    /**
53     * If false, this panel won't be drawn.
54     */
55    boolean visible;
56    /**
57     * If true, this panel has focus.
58     */
59    boolean focused;
60
61    int cursorTime, lastSlice, x, y;
62
63    /**
64     * Filler time at the end of the screen for a particular incident
65     */
66    public int requestedEditorFillerTime;
67
68    /**
69     * Filler time at the end of the screen for the whole script
70     */
71    public static int requestedScriptBuilderFillerTime = 0;
72
73    /**
74     * Constant for amount of filler to add, in seconds. Set to 15 minutes
75     */
76    public static final int FILLER_INTERVAL_SECONDS = 900;
77
78    /**
79     * The map representing the properties of this incident's events. Keys:
80     * event types. Values: Properties objects for those events.
81     */
82    Map<ScriptEventType, Properties> eventTypeToPropertyMap;
83
84    /**
85     * Listener for the mouse. Receives notifications when the mouse enters,
86     * exits, moves through, or clicks inside the panel.
87     */
88    public class IncidentTimelineMouseListener extends MouseInputAdapter
89    {
90
91        /**
92         * Action to take when the mouse enters the panel. Here, the incident
93         * corresponding to this panel gains focus.
94         *
95         * @param e the mouse event
96         */
97        @Override
98        public void mouseEntered(MouseEvent e)
99        {
100            incident.setIncidentActive();
101            focused = true;
102        }
103
104        /**
105         * Action to take when the mouse leaves the panel. Here, the incident
106         * loses focus and the panel gets repainted.
107         *
108         * @param e the mouse event
109         */
110        @Override
111        public void mouseExited(MouseEvent e)
112        {
113            focused = false;
114            repaint();
115        }
116
117        /*
118         *   Popup menu for incident actions
119         */
120        private JPopupMenu createPopup()
121        {
122            JPopupMenu menu = new JPopupMenu();
123            JMenuItem eventsMenuItem = new JMenuItem("Events");
124            JMenuItem propsMenuItem = new JMenuItem("Properties");
125            eventsMenuItem.setActionCommand("Edit Events");
126            propsMenuItem.setActionCommand("Modify Incident Properties");
127
128            PopupMenuItemListener menuItemListener = new PopupMenuItemListener();
129
130            eventsMenuItem.addActionListener(menuItemListener);
131            propsMenuItem.addActionListener(menuItemListener);
132
133            menu.add(eventsMenuItem);
134            menu.add(propsMenuItem);
135            return menu;
136        }
137
138        class PopupMenuItemListener implements ActionListener
139        {
140
141            public void actionPerformed(ActionEvent e)
142            {
143                JFrame topFrame = (JFrame) getTopLevelAncestor();
144                if (topFrame instanceof ScriptBuilderFrame)
145                {
146                    SimulationScript script = ((ScriptBuilderFrame) topFrame).getScript();
147                    if (e.getActionCommand().equals("Edit Events"))
148                    {
149                        IncidentEditorFrame editor = new IncidentEditorFrame(incident);
150                        script.addObserver(editor);
151                        editor.setVisible(true);
152                        ((ScriptBuilderFrame) topFrame).update(script, script);
153                    }
154                    if (e.getActionCommand().equals("Modify Incident Properties"))
155                    {
156                        ((ScriptBuilderFrame) topFrame).incidentDetailsScreen(incident);
157                        ((ScriptBuilderFrame) topFrame).update(script, script);
158                    }
159                }
160                topFrame.repaint();
161            }
162        }
163
164        @Override
165        public void mousePressed(MouseEvent e)
166        {
167            int currentMouseX = e.getX();
168            int currentMouseY = e.getY();
169
170            // Does user want a popup menu?
171            if (e.isPopupTrigger())
172            {
173                JPopupMenu popup = createPopup();
174                popup.show(e.getComponent(), currentMouseX, currentMouseY);
175            }
176        }
177
178        /**
179         * Determine if the mouse click happened within a valid timeSlice on
180         * this incident; if so, activate the Editor window for that timeSlice.
181         *
182         * @param e the mouse event
183         */
184        @Override
185        public void mouseClicked(MouseEvent e)
186        {
187            Editor ed = null;
188            ScriptBuilderFrame f = null;
189            IncidentEditorFrame g = null;
190            if (getTopLevelAncestor() instanceof ScriptBuilderFrame)
191            {
192                f = (ScriptBuilderFrame) getTopLevelAncestor();
193
194            }
195            else if (getTopLevelAncestor() instanceof IncidentEditorFrame)
196            {
197                g = (IncidentEditorFrame) getTopLevelAncestor();
198                ed = new Editor(g);
199            }
200
201            x = cursorTime = e.getX();
202            y = e.getY();
203
204            if (e.getX() % ScriptBuilderGuiConstants.PIXEL_WIDTH_PER_HORIZONTAL_TICK
205                    > ScriptBuilderGuiConstants.PIXEL_WIDTH_PER_HORIZONTAL_TICK / 2)
206            {
207                cursorTime += ScriptBuilderGuiConstants.PIXEL_WIDTH_PER_HORIZONTAL_TICK
208                        - e.getX()
209                        % ScriptBuilderGuiConstants.PIXEL_WIDTH_PER_HORIZONTAL_TICK;
210            }
211            else
212            {
213                cursorTime -= e.getX()
214                        % ScriptBuilderGuiConstants.PIXEL_WIDTH_PER_HORIZONTAL_TICK;
215            }
216
217            int newSlice = (cursorTime / ScriptBuilderGuiConstants.PIXEL_WIDTH_PER_HORIZONTAL_TICK);
218            newSlice *= ScriptBuilderGuiConstants.HORIZONTAL_TICK_RESOLUTION;
219            /**
220             * Check if click is out of bounds *
221             */
222            if (newSlice < 0 || incident == null)
223            {
224                return;
225            }
226
227            if (incident.slices.get(newSlice) != null)
228
229            {
230                for (I_ScriptEvent se : incident.slices.get(newSlice).events)
231                {
232                    if (ed != null)
233                    {
234                        ed.addProperty(eventTypeToPropertyMap.get(se.getScriptEventType()), se);
235                    }
236                }
237            }
238
239            /**
240             * Add a new icon if left mouse button was clicked *
241             */
242            if (e.getButton() == MouseEvent.BUTTON1)
243            {
244
245                if (getTopLevelAncestor() instanceof IncidentEditorFrame)
246                {
247                    if (g.currentEventType != null)
248                    {
249                        I_ScriptEvent s = ScriptEvent.factoryByType(g.currentEventType);
250                        if (ed != null)
251                        {
252                            ed.addProperty(eventTypeToPropertyMap.get(g.currentEventType), s);
253                        }
254                        if (incident.slices.get(newSlice) == null)
255                        {
256                            incident.addNewEvent(s, newSlice);
257                        }
258                        else
259                        {
260                            incident.slices.get(newSlice).addEvent(s);
261                        }
262                        g.update(null, g.getIncident());
263                    }
264                }
265            }
266
267            if (incident.slices.get(newSlice) != null
268                    && getTopLevelAncestor() instanceof IncidentEditorFrame)
269            {
270                ed.setVisible(true);
271            }
272        }
273
274        /**
275         * Determine if the mouse is now hovering over a valid timeslice; if so,
276         * alter tooltip text and info window text to reflect the new timeslice.
277         *
278         * @param e the mouse event
279         */
280        @Override
281        public void mouseMoved(MouseEvent e)
282        {
283            x = cursorTime = e.getX();
284            y = e.getY();
285
286            if (e.getX() % ScriptBuilderGuiConstants.PIXEL_WIDTH_PER_HORIZONTAL_TICK
287                    > ScriptBuilderGuiConstants.PIXEL_WIDTH_PER_HORIZONTAL_TICK / 2)
288            {
289                cursorTime += ScriptBuilderGuiConstants.PIXEL_WIDTH_PER_HORIZONTAL_TICK
290                        - e.getX()
291                        % ScriptBuilderGuiConstants.PIXEL_WIDTH_PER_HORIZONTAL_TICK;
292            }
293            else
294            {
295                cursorTime -= e.getX()
296                        % ScriptBuilderGuiConstants.PIXEL_WIDTH_PER_HORIZONTAL_TICK;
297            }
298
299            if (incident != null)
300            {
301                int newSlice = (cursorTime / ScriptBuilderGuiConstants.PIXEL_WIDTH_PER_HORIZONTAL_TICK);
302                newSlice *= ScriptBuilderGuiConstants.HORIZONTAL_TICK_RESOLUTION;
303                if (newSlice >= 0 && incident.slices.get(newSlice) != null)
304                {
305                    incident.setSliceActive(newSlice);
306                    lastSlice = newSlice;
307                    String newToolTip;
308
309                    newToolTip = incident.slices.get(newSlice).getToolTipText(y);
310
311                    setToolTipText((newToolTip == null || newToolTip.equals(""))
312                            ? null : newToolTip);
313                }
314            }
315
316            repaint();
317        }
318    }
319
320    /**
321     * Constructor. Generates a HashMap of all possible event types.
322     */
323    public IncidentTimelinePanel()
324    {
325        super();
326
327        requestedEditorFillerTime = 0;
328//        FACILITATOR_EVAL_EVENT, RADIO_EVAL_EVENT
329        eventTypeToPropertyMap = new HashMap();
330        eventTypeToPropertyMap.put(ScriptEventType.AUDIO_EVENT, Properties.Audio);
331        eventTypeToPropertyMap.put(ScriptEventType.CAD_EVENT, Properties.CADLog);
332        eventTypeToPropertyMap.put(ScriptEventType.CCTV_EVENT, Properties.CCTV);
333        eventTypeToPropertyMap.put(ScriptEventType.CHP_RADIO_EVENT, Properties.CHPRadio);
334        eventTypeToPropertyMap.put(ScriptEventType.PARAMICS_EVENT, Properties.Paramics);
335        eventTypeToPropertyMap.put(ScriptEventType.TOW_EVENT, Properties.Tow);
336        eventTypeToPropertyMap.put(ScriptEventType.UNIT_EVENT, Properties.Unit);
337        eventTypeToPropertyMap.put(ScriptEventType.WITNESS_EVENT, Properties.Witness);
338        eventTypeToPropertyMap.put(ScriptEventType.MAINTENANCE_RADIO_EVENT, Properties.MaintenanceRadio);
339        eventTypeToPropertyMap.put(ScriptEventType.TMT_RADIO_EVENT, Properties.TMTRadio);
340        eventTypeToPropertyMap.put(ScriptEventType.TELEPHONE_EVENT, Properties.Telephone);
341        eventTypeToPropertyMap.put(ScriptEventType.ATMS_EVAL_EVENT, Properties.ATMS);
342        eventTypeToPropertyMap.put(ScriptEventType.ACTIVITY_LOG_EVAL_EVENT, Properties.ActivityLog);
343        eventTypeToPropertyMap.put(ScriptEventType.CAD_EVAL_EVENT, Properties.CAD);
344        eventTypeToPropertyMap.put(ScriptEventType.CMS_EVAL_EVENT, Properties.CMS);
345        eventTypeToPropertyMap.put(ScriptEventType.FACILITATOR_EVAL_EVENT, Properties.Facilitator);
346        eventTypeToPropertyMap.put(ScriptEventType.RADIO_EVAL_EVENT, Properties.Radio);
347
348        // Add the mouse listener
349        IncidentTimelineMouseListener mouseListener
350                = new IncidentTimelineMouseListener();
351        addMouseMotionListener(mouseListener);
352        addMouseListener(mouseListener);
353    }
354
355    /**
356     * Update the panel if it's changed collapsed status. Redraw it with the
357     * correct dimensions for its status.
358     *
359     * @param incident the incident this panel represents
360     */
361    public void timelinePanelUpdate(ScriptIncident incident)
362    {
363        this.incident = incident;
364        this.visible = incident != null;
365
366        Dimension newSize;
367        if (visible)
368        {
369
370            if (getTopLevelAncestor() instanceof IncidentEditorFrame)
371            {
372
373                newSize = new Dimension(((incident.length + incident.offset + requestedEditorFillerTime)
374                        / ScriptBuilderGuiConstants.HORIZONTAL_TICK_RESOLUTION
375                        * ScriptBuilderGuiConstants.PIXEL_WIDTH_PER_HORIZONTAL_TICK)
376                        + ScriptBuilderGuiConstants.EVENT_ICON_WIDTH,
377                        ScriptBuilderGuiConstants.TIMELINE_COLLAPSED_HEIGHT
378                        + ScriptBuilderGuiConstants.SCRIPT_EVENT_ICON_STEP * 2);
379            }
380            else
381            {
382                newSize = new Dimension(((incident.length + incident.offset + requestedScriptBuilderFillerTime)
383                        / ScriptBuilderGuiConstants.HORIZONTAL_TICK_RESOLUTION
384                        * ScriptBuilderGuiConstants.PIXEL_WIDTH_PER_HORIZONTAL_TICK)
385                        + ScriptBuilderGuiConstants.EVENT_ICON_WIDTH,
386                        ScriptBuilderGuiConstants.TIMELINE_COLLAPSED_HEIGHT
387                        + ScriptBuilderGuiConstants.SCRIPT_EVENT_ICON_STEP * 2);
388            }
389
390        }
391        else
392        {
393            newSize = new Dimension(0, 0);
394        }
395        this.setSize(newSize);
396        this.setPreferredSize(newSize);
397
398        invalidate();
399    }
400
401    /**
402     * Redraw this panel and all the icons inside it. If user is holding an
403     * event, draw that icon under the mouse.
404     *
405     * @param g the graphics component
406     */
407    @Override
408    public void paint(Graphics g)
409    {
410        super.paint(g);
411
412        if (!visible)
413        {
414            return;
415        }
416
417        Graphics2D g2d = (Graphics2D) g;
418//        jdalbey removed this decision and replaced it with ELSE clause
419//                so it will work with any alternate ancestor.
420//        if (getTopLevelAncestor() instanceof ScriptBuilderFrame)
421//        {
422//            IncidentTimelineDrawer.DrawScriptBuilderTimeline(g2d, incident);
423//        }
424        if (getTopLevelAncestor() instanceof IncidentEditorFrame)
425        {
426            IncidentTimelineDrawer.DrawIncidentTimeline(g2d, incident, false);
427        }
428        else
429        {
430            IncidentTimelineDrawer.DrawScriptBuilderTimeline(g2d, incident);
431        }
432
433        if (focused)
434        {
435            CursorDrawer.DrawCursor(g2d, cursorTime, false);
436            if (this.getTopLevelAncestor() instanceof ScriptBuilderFrame)
437            {
438                if (((ScriptBuilderFrame) this.getTopLevelAncestor()).currentEventType != null)
439                {
440                    EventIconDrawer.DrawEventIcon(g2d,
441                            ((ScriptBuilderFrame) this.getTopLevelAncestor()).currentEventType,
442                            x + 5, y + 10);
443                }
444            }
445            if (this.getTopLevelAncestor() instanceof IncidentEditorFrame)
446            {
447                if (((IncidentEditorFrame) this.getTopLevelAncestor()).currentEventType != null)
448                {
449                    EventIconDrawer.DrawEventIcon(g2d,
450                            ((IncidentEditorFrame) this.getTopLevelAncestor()).currentEventType,
451                            x + 5, y + 10);
452                }
453            }
454        }
455    }
456
457    /**
458     * Local main for viewing this panel only.
459     *
460     * @author jdalbey
461     * @param args not used
462     */
463    public static void main(String[] args)
464    {
465        JFrame frame = new JFrame("ScriptBuilderTimelinePanel Demo");
466        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
467
468        IncidentTimelinePanel pnl = new IncidentTimelinePanel();
469
470        // Create a script
471        File inFile = new File("test/scriptbuilder/structures/test_input_file.xml");
472        SimulationScript script = new SimulationScript();
473        script.loadScriptFromFile(inFile);
474        // retrieve a single incident from the script
475        ScriptIncident inci = script.incidents.get(2);
476        // update this panel with an incident
477        pnl.timelinePanelUpdate(inci);
478
479        frame.getContentPane().add(pnl, BorderLayout.CENTER);
480        frame.pack();
481
482        frame.setVisible(true);
483
484    }
485}
Note: See TracBrowser for help on using the repository browser.