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 @ 106

Revision 106, 16.8 KB checked in by bmcguffin, 9 years ago (diff)

Fixed a bug which prevented the length of an incident from being properly preserved whenever the offset of the incident was changed.

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    public static 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, (ScriptBuilderFrame)topFrame);
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 (ed != null)
228            {
229                ed.setSlice(incident.slices.get(newSlice));
230            }
231           
232
233            /**
234             * Add a new icon if left mouse button was clicked *
235             */
236            if (e.getButton() == MouseEvent.BUTTON1)
237            {
238
239                if (getTopLevelAncestor() instanceof IncidentEditorFrame)
240                {
241                    if (g.currentEventType != null)
242                    {
243                        I_ScriptEvent s = ScriptEvent.factoryByType(g.currentEventType);
244                        if (ed != null)
245                        {
246                            ed.addEvent(eventTypeToPropertyMap.get(g.currentEventType), s);
247                        }
248                        if (incident.slices.get(newSlice) == null)
249                        {
250                            incident.addNewEvent(s, newSlice);
251                        }
252                        else
253                        {
254                            incident.slices.get(newSlice).addEvent(s);
255                        }
256                        g.update(null, g.getIncident());
257                    }
258                }
259            }
260
261            if (incident.slices.get(newSlice) != null
262                    && getTopLevelAncestor() instanceof IncidentEditorFrame)
263            {
264                ed.setVisible(true);
265            }
266        }
267
268        /**
269         * Determine if the mouse is now hovering over a valid timeslice; if so,
270         * alter tooltip text and info window text to reflect the new timeslice.
271         *
272         * @param e the mouse event
273         */
274        @Override
275        public void mouseMoved(MouseEvent e)
276        {
277            x = cursorTime = e.getX();
278            y = e.getY();
279
280            if (e.getX() % ScriptBuilderGuiConstants.PIXEL_WIDTH_PER_HORIZONTAL_TICK
281                    > ScriptBuilderGuiConstants.PIXEL_WIDTH_PER_HORIZONTAL_TICK / 2)
282            {
283                cursorTime += ScriptBuilderGuiConstants.PIXEL_WIDTH_PER_HORIZONTAL_TICK
284                        - e.getX()
285                        % ScriptBuilderGuiConstants.PIXEL_WIDTH_PER_HORIZONTAL_TICK;
286            }
287            else
288            {
289                cursorTime -= e.getX()
290                        % ScriptBuilderGuiConstants.PIXEL_WIDTH_PER_HORIZONTAL_TICK;
291            }
292
293            if (incident != null)
294            {
295                int newSlice = (cursorTime / ScriptBuilderGuiConstants.PIXEL_WIDTH_PER_HORIZONTAL_TICK);
296                newSlice *= ScriptBuilderGuiConstants.HORIZONTAL_TICK_RESOLUTION;
297                if (newSlice >= 0 && incident.slices.get(newSlice) != null)
298                {
299                    incident.setSliceActive(newSlice);
300                    lastSlice = newSlice;
301                    String newToolTip;
302
303                    newToolTip = incident.slices.get(newSlice).getToolTipText(y);
304
305                    setToolTipText((newToolTip == null || newToolTip.equals(""))
306                            ? null : newToolTip);
307                }
308            }
309
310            repaint();
311        }
312    }
313
314    /**
315     * Constructor. Generates a HashMap of all possible event types.
316     */
317    public IncidentTimelinePanel()
318    {
319        super();
320
321        requestedEditorFillerTime = 0;
322//        FACILITATOR_EVAL_EVENT, RADIO_EVAL_EVENT
323        eventTypeToPropertyMap = new HashMap();
324        eventTypeToPropertyMap.put(ScriptEventType.AUDIO_EVENT, Properties.Audio);
325        eventTypeToPropertyMap.put(ScriptEventType.CAD_EVENT, Properties.CADLog);
326        eventTypeToPropertyMap.put(ScriptEventType.CCTV_EVENT, Properties.CCTV);
327        eventTypeToPropertyMap.put(ScriptEventType.CHP_RADIO_EVENT, Properties.CHPRadio);
328        eventTypeToPropertyMap.put(ScriptEventType.PARAMICS_EVENT, Properties.Paramics);
329        eventTypeToPropertyMap.put(ScriptEventType.TOW_EVENT, Properties.Tow);
330        eventTypeToPropertyMap.put(ScriptEventType.UNIT_EVENT, Properties.Unit);
331        eventTypeToPropertyMap.put(ScriptEventType.WITNESS_EVENT, Properties.Witness);
332        eventTypeToPropertyMap.put(ScriptEventType.MAINTENANCE_RADIO_EVENT, Properties.MaintenanceRadio);
333        eventTypeToPropertyMap.put(ScriptEventType.TMT_RADIO_EVENT, Properties.TMTRadio);
334        eventTypeToPropertyMap.put(ScriptEventType.TELEPHONE_EVENT, Properties.Telephone);
335        eventTypeToPropertyMap.put(ScriptEventType.ATMS_EVAL_EVENT, Properties.ATMS);
336        eventTypeToPropertyMap.put(ScriptEventType.ACTIVITY_LOG_EVAL_EVENT, Properties.ActivityLog);
337        eventTypeToPropertyMap.put(ScriptEventType.CAD_EVAL_EVENT, Properties.CAD);
338        eventTypeToPropertyMap.put(ScriptEventType.CMS_EVAL_EVENT, Properties.CMS);
339        eventTypeToPropertyMap.put(ScriptEventType.FACILITATOR_EVAL_EVENT, Properties.Facilitator);
340        eventTypeToPropertyMap.put(ScriptEventType.RADIO_EVAL_EVENT, Properties.Radio);
341
342        // Add the mouse listener
343        IncidentTimelineMouseListener mouseListener
344                = new IncidentTimelineMouseListener();
345        addMouseMotionListener(mouseListener);
346        addMouseListener(mouseListener);
347    }
348
349    /**
350     * Update the panel if it's changed collapsed status. Redraw it with the
351     * correct dimensions for its status.
352     *
353     * @param incident the incident this panel represents
354     */
355    public void timelinePanelUpdate(ScriptIncident incident)
356    {
357        this.incident = incident;
358        this.visible = (incident != null);
359
360        Dimension newSize;
361        if (visible)
362        {
363
364            if (getTopLevelAncestor() instanceof IncidentEditorFrame)
365            {
366
367                newSize = new Dimension(((incident.length + incident.offset + requestedEditorFillerTime)
368                        / ScriptBuilderGuiConstants.HORIZONTAL_TICK_RESOLUTION
369                        * ScriptBuilderGuiConstants.PIXEL_WIDTH_PER_HORIZONTAL_TICK)
370                        + ScriptBuilderGuiConstants.EVENT_ICON_WIDTH,
371                        ScriptBuilderGuiConstants.TIMELINE_COLLAPSED_HEIGHT
372                        + ScriptBuilderGuiConstants.SCRIPT_EVENT_ICON_STEP * 2);
373            }
374            else
375            {
376                newSize = new Dimension(((incident.length + incident.offset + requestedScriptBuilderFillerTime)
377                        / ScriptBuilderGuiConstants.HORIZONTAL_TICK_RESOLUTION
378                        * ScriptBuilderGuiConstants.PIXEL_WIDTH_PER_HORIZONTAL_TICK)
379                        + ScriptBuilderGuiConstants.EVENT_ICON_WIDTH,
380                        ScriptBuilderGuiConstants.TIMELINE_COLLAPSED_HEIGHT
381                        + ScriptBuilderGuiConstants.SCRIPT_EVENT_ICON_STEP * 2);
382            }
383
384        }
385        else
386        {
387            newSize = new Dimension(0, 0);
388        }
389        this.setSize(newSize);
390        this.setPreferredSize(newSize);
391
392        invalidate();
393    }
394
395    /**
396     * Redraw this panel and all the icons inside it. If user is holding an
397     * event, draw that icon under the mouse.
398     *
399     * @param g the graphics component
400     */
401    @Override
402    public void paint(Graphics g)
403    {
404        super.paint(g);
405
406        if (!visible)
407        {
408            return;
409        }
410
411        Graphics2D g2d = (Graphics2D) g;
412//        jdalbey removed this decision and replaced it with ELSE clause
413//                so it will work with any alternate ancestor.
414//        if (getTopLevelAncestor() instanceof ScriptBuilderFrame)
415//        {
416//            IncidentTimelineDrawer.DrawScriptBuilderTimeline(g2d, incident);
417//        }
418        if (getTopLevelAncestor() instanceof IncidentEditorFrame)
419        {
420            IncidentTimelineDrawer.DrawIncidentTimeline(g2d, incident, false);
421        }
422        else
423        {
424            IncidentTimelineDrawer.DrawScriptBuilderTimeline(g2d, incident);
425        }
426
427        if (focused)
428        {
429            CursorDrawer.DrawCursor(g2d, cursorTime, false);
430            if (this.getTopLevelAncestor() instanceof ScriptBuilderFrame)
431            {
432                if (((ScriptBuilderFrame) this.getTopLevelAncestor()).currentEventType != null)
433                {
434                    EventIconDrawer.DrawEventIcon(g2d,
435                            ((ScriptBuilderFrame) this.getTopLevelAncestor()).currentEventType,
436                            x + 5, y + 10);
437                }
438            }
439            if (this.getTopLevelAncestor() instanceof IncidentEditorFrame)
440            {
441                if (((IncidentEditorFrame) this.getTopLevelAncestor()).currentEventType != null)
442                {
443                    EventIconDrawer.DrawEventIcon(g2d,
444                            ((IncidentEditorFrame) this.getTopLevelAncestor()).currentEventType,
445                            x + 5, y + 10);
446                }
447            }
448        }
449    }
450
451    /**
452     * Local main for viewing this panel only.
453     *
454     * @author jdalbey
455     * @param args not used
456     */
457    public static void main(String[] args)
458    {
459        JFrame frame = new JFrame("ScriptBuilderTimelinePanel Demo");
460        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
461
462        IncidentTimelinePanel pnl = new IncidentTimelinePanel();
463
464        // Create a script
465        File inFile = new File("test/scriptbuilder/structures/test_input_file.xml");
466        SimulationScript script = new SimulationScript();
467        script.loadScriptFromFile(inFile);
468        // retrieve a single incident from the script
469        ScriptIncident inci = script.incidents.get(2);
470        // update this panel with an incident
471        pnl.timelinePanelUpdate(inci);
472
473        frame.getContentPane().add(pnl, BorderLayout.CENTER);
474        frame.pack();
475
476        frame.setVisible(true);
477
478    }
479}
Note: See TracBrowser for help on using the repository browser.