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

Revision 133, 20.2 KB checked in by jdalbey, 9 years ago (diff)

IncidentTImelinePanel.java: Added mousereleased event handler for popuptrigger on Windows.

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    /**
62     * If true, right-clicking on this panel will produce the popup menu.
63     */
64    private boolean hasPopupAccess;
65
66    int cursorTime, lastSlice, x, y;
67
68    /**
69     * Filler time at the end of the screen for a particular incident
70     */
71    public int requestedEditorFillerTime;
72
73    /**
74     * Filler time at the end of the screen for the whole script
75     */
76    public static int requestedScriptBuilderFillerTime = 0;
77
78    /**
79     * Constant for amount of filler to add, in seconds. Set to 15 minutes
80     */
81    public static final int FILLER_INTERVAL_SECONDS = 900;
82
83    /**
84     * The map representing the properties of this incident's events. Keys:
85     * event types. Values: Properties objects for those events.
86     */
87    public static Map<ScriptEventType, Properties> eventTypeToPropertyMap;
88
89    /**
90     * Listener for the mouse. Receives notifications when the mouse enters,
91     * exits, moves through, or clicks inside the panel.
92     */
93    public class IncidentTimelineMouseListener extends MouseInputAdapter
94    {
95
96        /**
97         * Action to take when the mouse enters the panel. Here, the incident
98         * corresponding to this panel gains focus.
99         *
100         * @param e the mouse event
101         */
102        @Override
103        public void mouseEntered(MouseEvent e)
104        {
105            incident.setIncidentActive();
106            focused = true;
107        }
108
109        /**
110         * Action to take when the mouse leaves the panel. Here, the incident
111         * loses focus and the panel gets repainted.
112         *
113         * @param e the mouse event
114         */
115        @Override
116        public void mouseExited(MouseEvent e)
117        {
118            focused = false;
119            repaint();
120        }
121
122        /*
123         *   Popup menu for incident actions
124         */
125        private JPopupMenu createPopup()
126        {
127            JPopupMenu menu = new JPopupMenu();
128            JMenuItem eventsMenuItem = new JMenuItem("Events");
129            JMenuItem propsMenuItem = new JMenuItem("Properties");
130            eventsMenuItem.setActionCommand("Edit Events");
131            propsMenuItem.setActionCommand("Modify Incident Properties");
132
133            PopupMenuItemListener menuItemListener = new PopupMenuItemListener();
134
135            eventsMenuItem.addActionListener(menuItemListener);
136            propsMenuItem.addActionListener(menuItemListener);
137
138            menu.add(eventsMenuItem);
139            menu.add(propsMenuItem);
140            return menu;
141        }
142
143        class PopupMenuItemListener implements ActionListener
144        {
145
146            public void actionPerformed(ActionEvent e)
147            {
148                JFrame topFrame = (JFrame) getTopLevelAncestor();
149                if (topFrame instanceof ScriptBuilderFrame)
150                {
151                    SimulationScript script = ((ScriptBuilderFrame) topFrame).getScript();
152                    if (e.getActionCommand().equals("Edit Events"))
153                    {
154                        IncidentEditorFrame editor = new IncidentEditorFrame(incident, (ScriptBuilderFrame) topFrame);
155                        script.addObserver(editor);
156                        editor.setVisible(true);
157                        ((ScriptBuilderFrame) topFrame).update(script, script);
158                    }
159                    if (e.getActionCommand().equals("Modify Incident Properties"))
160                    {
161                        ((ScriptBuilderFrame) topFrame).incidentDetailsScreen(incident);
162                        ((ScriptBuilderFrame) topFrame).update(script, script);
163                    }
164                }
165                topFrame.repaint();
166            }
167        }
168        /**
169         * Note: Popup menus are triggered differently on different systems.
170         * Therefore, isPopupTrigger should be checked in both mousePressed and
171         * mouseReleased for proper cross-platform functionality.
172         * @param e event that triggered this method
173         */
174        @Override
175        public void mousePressed(MouseEvent e)
176        {
177            int currentMouseX = e.getX();
178            int currentMouseY = e.getY();
179
180            // Does user want a popup menu?
181            if (e.isPopupTrigger() && hasPopupAccess)
182            {
183                JPopupMenu popup = createPopup();
184                popup.show(e.getComponent(), currentMouseX, currentMouseY);
185            }
186        }
187        @Override
188        public void mouseReleased(MouseEvent e)
189        {
190            int currentMouseX = e.getX();
191            int currentMouseY = e.getY();
192
193            // Does user want a popup menu?
194            if (e.isPopupTrigger() && hasPopupAccess)
195            {
196                JPopupMenu popup = createPopup();
197                popup.show(e.getComponent(), currentMouseX, currentMouseY);
198            }
199        }
200
201        /**
202         * Determine if the mouse click happened within a valid timeSlice on
203         * this incident; if so, activate the Editor window for that timeSlice.
204         *
205         * @param e the mouse event
206         */
207        @Override
208        public void mouseClicked(MouseEvent e)
209        {
210            Editor ed = null;
211            ScriptBuilderFrame f = null;
212            IncidentEditorFrame g = null;
213            if (getTopLevelAncestor() instanceof ScriptBuilderFrame)
214            {
215                f = (ScriptBuilderFrame) getTopLevelAncestor();
216
217            }
218            else if (getTopLevelAncestor() instanceof IncidentEditorFrame)
219            {
220                g = (IncidentEditorFrame) getTopLevelAncestor();
221                ed = new Editor(g);
222            }
223
224            x = cursorTime = e.getX();
225            y = e.getY();
226
227            if (e.getX() % ScriptBuilderGuiConstants.PIXEL_WIDTH_PER_HORIZONTAL_TICK
228                    > ScriptBuilderGuiConstants.PIXEL_WIDTH_PER_HORIZONTAL_TICK / 2)
229            {
230                cursorTime += ScriptBuilderGuiConstants.PIXEL_WIDTH_PER_HORIZONTAL_TICK
231                        - e.getX()
232                        % ScriptBuilderGuiConstants.PIXEL_WIDTH_PER_HORIZONTAL_TICK;
233            }
234            else
235            {
236                cursorTime -= e.getX()
237                        % ScriptBuilderGuiConstants.PIXEL_WIDTH_PER_HORIZONTAL_TICK;
238            }
239
240            int newSlice = (cursorTime / ScriptBuilderGuiConstants.PIXEL_WIDTH_PER_HORIZONTAL_TICK);
241            newSlice *= ScriptBuilderGuiConstants.HORIZONTAL_TICK_RESOLUTION;
242            /**
243             * Check if click is out of bounds *
244             */
245            if (newSlice < 0 || incident == null)
246            {
247                return;
248            }
249
250            if (ed != null)
251            {
252                ed.setSlice(incident.slices.get(newSlice));
253            }
254
255            /**
256             * Add a new icon if left mouse button was clicked *
257             */
258            if (e.getButton() == MouseEvent.BUTTON1)
259            {
260
261                if (getTopLevelAncestor() instanceof IncidentEditorFrame)
262                {
263                    if (incident.slices.size() == 0 && newSlice != 0)
264                    {
265                        JOptionPane.showMessageDialog(g, "This is the first event in the incident.\n"
266                                + "Therefore, it will be automatically positioned at time 00:00:00,\n"
267                                + "relative to the start of the incident.", "Event will be moved", JOptionPane.INFORMATION_MESSAGE);
268                        newSlice = 0;
269                    }
270                    if (g.currentEventType != null)
271                    {
272                        I_ScriptEvent s = ScriptEvent.factoryByType(g.currentEventType);
273                        if (ed != null)
274                        {
275                            ed.addEvent(eventTypeToPropertyMap.get(g.currentEventType), s);
276                        }
277                        if (incident.slices.get(newSlice) == null)
278                        {
279                            incident.addNewEvent(s, newSlice);
280                        }
281                        else
282                        {
283                            incident.slices.get(newSlice).addEvent(s);
284                        }
285                        g.update(null, g.getIncident());
286                    }
287                }
288            }
289
290            if (incident.slices.get(newSlice) != null
291                    && getTopLevelAncestor() instanceof IncidentEditorFrame)
292            {
293                ed.setVisible(true);
294            }
295        }
296
297        /**
298         * Determine if the mouse is now hovering over a valid timeslice; if so,
299         * alter tooltip text and info window text to reflect the new timeslice.
300         *
301         * @param e the mouse event
302         */
303        @Override
304        public void mouseMoved(MouseEvent e)
305        {
306            x = cursorTime = e.getX();
307            y = e.getY();
308
309            if (e.getX() % ScriptBuilderGuiConstants.PIXEL_WIDTH_PER_HORIZONTAL_TICK
310                    > ScriptBuilderGuiConstants.PIXEL_WIDTH_PER_HORIZONTAL_TICK / 2)
311            {
312                cursorTime += ScriptBuilderGuiConstants.PIXEL_WIDTH_PER_HORIZONTAL_TICK
313                        - e.getX()
314                        % ScriptBuilderGuiConstants.PIXEL_WIDTH_PER_HORIZONTAL_TICK;
315            }
316            else
317            {
318                cursorTime -= e.getX()
319                        % ScriptBuilderGuiConstants.PIXEL_WIDTH_PER_HORIZONTAL_TICK;
320            }
321
322            if (incident != null)
323            {
324                int newSlice = (cursorTime / ScriptBuilderGuiConstants.PIXEL_WIDTH_PER_HORIZONTAL_TICK);
325                newSlice *= ScriptBuilderGuiConstants.HORIZONTAL_TICK_RESOLUTION;
326                if (newSlice >= 0 && incident.slices.get(newSlice) != null)
327                {
328                    incident.setSliceActive(newSlice);
329                    lastSlice = newSlice;
330                    String newToolTip;
331
332                    newToolTip = incident.slices.get(newSlice).getToolTipText(y);
333
334                    setToolTipText((newToolTip == null || newToolTip.equals(""))
335                            ? null : newToolTip);
336                }
337            }
338
339            repaint();
340        }
341    }
342
343    /**
344     * Constructor. Generates a HashMap of all possible event types.
345     */
346    public IncidentTimelinePanel()
347    {
348        super();
349
350        hasPopupAccess = true;
351
352        requestedEditorFillerTime = 0;
353//        FACILITATOR_EVAL_EVENT, RADIO_EVAL_EVENT
354        eventTypeToPropertyMap = new HashMap();
355        eventTypeToPropertyMap.put(ScriptEventType.AUDIO_EVENT, Properties.Audio);
356        eventTypeToPropertyMap.put(ScriptEventType.CAD_EVENT, Properties.CADLog);
357        eventTypeToPropertyMap.put(ScriptEventType.CCTV_EVENT, Properties.CCTV);
358        eventTypeToPropertyMap.put(ScriptEventType.CHP_RADIO_EVENT, Properties.CHPRadio);
359        eventTypeToPropertyMap.put(ScriptEventType.PARAMICS_EVENT, Properties.Paramics);
360        eventTypeToPropertyMap.put(ScriptEventType.TOW_EVENT, Properties.Tow);
361        eventTypeToPropertyMap.put(ScriptEventType.UNIT_EVENT, Properties.Unit);
362        eventTypeToPropertyMap.put(ScriptEventType.WITNESS_EVENT, Properties.Witness);
363        eventTypeToPropertyMap.put(ScriptEventType.MAINTENANCE_RADIO_EVENT, Properties.MaintenanceRadio);
364        eventTypeToPropertyMap.put(ScriptEventType.TMT_RADIO_EVENT, Properties.TMTRadio);
365        eventTypeToPropertyMap.put(ScriptEventType.TELEPHONE_EVENT, Properties.Telephone);
366        eventTypeToPropertyMap.put(ScriptEventType.ATMS_EVAL_EVENT, Properties.ATMS);
367        eventTypeToPropertyMap.put(ScriptEventType.ACTIVITY_LOG_EVAL_EVENT, Properties.ActivityLog);
368        eventTypeToPropertyMap.put(ScriptEventType.CAD_EVAL_EVENT, Properties.CAD);
369        eventTypeToPropertyMap.put(ScriptEventType.CMS_EVAL_EVENT, Properties.CMS);
370        eventTypeToPropertyMap.put(ScriptEventType.FACILITATOR_EVAL_EVENT, Properties.Facilitator);
371        eventTypeToPropertyMap.put(ScriptEventType.RADIO_EVAL_EVENT, Properties.Radio);
372
373        // Add the mouse listener
374        IncidentTimelineMouseListener mouseListener
375                = new IncidentTimelineMouseListener();
376        addMouseMotionListener(mouseListener);
377        addMouseListener(mouseListener);
378    }
379
380    /**
381     * Constructor. Generates a HashMap of all possible event types.
382     *
383     * @param usesPopup determines whether or not right-clicking on this panel
384     * will display a popup menu.
385     */
386    public IncidentTimelinePanel(boolean usesPopup)
387    {
388        super();
389
390        hasPopupAccess = usesPopup;
391
392        requestedEditorFillerTime = 0;
393//        FACILITATOR_EVAL_EVENT, RADIO_EVAL_EVENT
394        eventTypeToPropertyMap = new HashMap();
395        eventTypeToPropertyMap.put(ScriptEventType.AUDIO_EVENT, Properties.Audio);
396        eventTypeToPropertyMap.put(ScriptEventType.CAD_EVENT, Properties.CADLog);
397        eventTypeToPropertyMap.put(ScriptEventType.CCTV_EVENT, Properties.CCTV);
398        eventTypeToPropertyMap.put(ScriptEventType.CHP_RADIO_EVENT, Properties.CHPRadio);
399        eventTypeToPropertyMap.put(ScriptEventType.PARAMICS_EVENT, Properties.Paramics);
400        eventTypeToPropertyMap.put(ScriptEventType.TOW_EVENT, Properties.Tow);
401        eventTypeToPropertyMap.put(ScriptEventType.UNIT_EVENT, Properties.Unit);
402        eventTypeToPropertyMap.put(ScriptEventType.WITNESS_EVENT, Properties.Witness);
403        eventTypeToPropertyMap.put(ScriptEventType.MAINTENANCE_RADIO_EVENT, Properties.MaintenanceRadio);
404        eventTypeToPropertyMap.put(ScriptEventType.TMT_RADIO_EVENT, Properties.TMTRadio);
405        eventTypeToPropertyMap.put(ScriptEventType.TELEPHONE_EVENT, Properties.Telephone);
406        eventTypeToPropertyMap.put(ScriptEventType.ATMS_EVAL_EVENT, Properties.ATMS);
407        eventTypeToPropertyMap.put(ScriptEventType.ACTIVITY_LOG_EVAL_EVENT, Properties.ActivityLog);
408        eventTypeToPropertyMap.put(ScriptEventType.CAD_EVAL_EVENT, Properties.CAD);
409        eventTypeToPropertyMap.put(ScriptEventType.CMS_EVAL_EVENT, Properties.CMS);
410        eventTypeToPropertyMap.put(ScriptEventType.FACILITATOR_EVAL_EVENT, Properties.Facilitator);
411        eventTypeToPropertyMap.put(ScriptEventType.RADIO_EVAL_EVENT, Properties.Radio);
412
413        // Add the mouse listener
414        IncidentTimelineMouseListener mouseListener
415                = new IncidentTimelineMouseListener();
416        addMouseMotionListener(mouseListener);
417        addMouseListener(mouseListener);
418    }
419
420    /**
421     * Update the panel if it's changed collapsed status. Redraw it with the
422     * correct dimensions for its status.
423     *
424     * @param incident the incident this panel represents
425     */
426    public void timelinePanelUpdate(ScriptIncident incident)
427    {
428        this.incident = incident;
429        this.visible = (incident != null);
430
431        Dimension newSize;
432        if (visible)
433        {
434
435            if (getTopLevelAncestor() instanceof IncidentEditorFrame)
436            {
437
438                newSize = new Dimension(((incident.length + incident.offset + requestedEditorFillerTime)
439                        / ScriptBuilderGuiConstants.HORIZONTAL_TICK_RESOLUTION
440                        * ScriptBuilderGuiConstants.PIXEL_WIDTH_PER_HORIZONTAL_TICK)
441                        + ScriptBuilderGuiConstants.EVENT_ICON_WIDTH,
442                        ScriptBuilderGuiConstants.TIMELINE_COLLAPSED_HEIGHT
443                        + ScriptBuilderGuiConstants.SCRIPT_EVENT_ICON_STEP * 2);
444            }
445            else
446            {
447                newSize = new Dimension(((incident.length + incident.offset + requestedScriptBuilderFillerTime)
448                        / ScriptBuilderGuiConstants.HORIZONTAL_TICK_RESOLUTION
449                        * ScriptBuilderGuiConstants.PIXEL_WIDTH_PER_HORIZONTAL_TICK)
450                        + ScriptBuilderGuiConstants.EVENT_ICON_WIDTH,
451                        ScriptBuilderGuiConstants.TIMELINE_COLLAPSED_HEIGHT
452                        + ScriptBuilderGuiConstants.SCRIPT_EVENT_ICON_STEP * 2);
453            }
454
455        }
456        else
457        {
458            newSize = new Dimension(0, 0);
459        }
460        this.setSize(newSize);
461        this.setPreferredSize(newSize);
462
463        invalidate();
464    }
465
466    /**
467     * Redraw this panel and all the icons inside it. If user is holding an
468     * event, draw that icon under the mouse.
469     *
470     * @param g the graphics component
471     */
472    @Override
473    public void paint(Graphics g)
474    {
475        super.paint(g);
476
477        if (!visible)
478        {
479            return;
480        }
481
482        Graphics2D g2d = (Graphics2D) g;
483//        jdalbey removed this decision and replaced it with ELSE clause
484//                so it will work with any alternate ancestor.
485//        if (getTopLevelAncestor() instanceof ScriptBuilderFrame)
486//        {
487//            IncidentTimelineDrawer.DrawScriptBuilderTimeline(g2d, incident);
488//        }
489        if (getTopLevelAncestor() instanceof IncidentEditorFrame)
490        {
491            IncidentTimelineDrawer.DrawIncidentTimeline(g2d, incident, false);
492        }
493        else
494        {
495            IncidentTimelineDrawer.DrawScriptBuilderTimeline(g2d, incident);
496        }
497
498        if (focused)
499        {
500            CursorDrawer.DrawCursor(g2d, cursorTime, false);
501            if (this.getTopLevelAncestor() instanceof ScriptBuilderFrame)
502            {
503                if (((ScriptBuilderFrame) this.getTopLevelAncestor()).currentEventType != null)
504                {
505                    EventIconDrawer.DrawEventIcon(g2d,
506                            ((ScriptBuilderFrame) this.getTopLevelAncestor()).currentEventType,
507                            x + 5, y + 10);
508                }
509            }
510            if (this.getTopLevelAncestor() instanceof IncidentEditorFrame)
511            {
512                if (((IncidentEditorFrame) this.getTopLevelAncestor()).currentEventType != null)
513                {
514                    EventIconDrawer.DrawEventIcon(g2d,
515                            ((IncidentEditorFrame) this.getTopLevelAncestor()).currentEventType,
516                            x + 5, y + 10);
517                }
518            }
519        }
520    }
521
522    /**
523     * Local main for viewing this panel only.
524     *
525     * @author jdalbey
526     * @param args not used
527     */
528    public static void main(String[] args)
529    {
530        JFrame frame = new JFrame("ScriptBuilderTimelinePanel Demo");
531        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
532
533        IncidentTimelinePanel pnl = new IncidentTimelinePanel();
534
535        // Create a script
536        File inFile = new File("test/scriptbuilder/structures/test_input_file.xml");
537        SimulationScript script = new SimulationScript();
538        script.loadScriptFromFile(inFile);
539        // retrieve a single incident from the script
540        ScriptIncident inci = script.incidents.get(2);
541        // update this panel with an incident
542        pnl.timelinePanelUpdate(inci);
543
544        frame.getContentPane().add(pnl, BorderLayout.CENTER);
545        frame.pack();
546
547        frame.setVisible(true);
548
549    }
550}
Note: See TracBrowser for help on using the repository browser.