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

Revision 96, 15.8 KB checked in by bmcguffin, 9 years ago (diff)

Removed "Delete" option from popup context menu. Incidents can still be deleted from the "Delete Incident" dropdown menu item; this change forces the user to be more deliberate in their decision to delete an incident.

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