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

Revision 89, 15.7 KB checked in by bmcguffin, 9 years ago (diff)

Added dropdown menu item to ScriptBuilderFrame?: "Delete Incident". When clicked, user may select an existing incident to delete. Program will prompt user to confirm the deletion, then remove the incident from the script and refresh the display.

Added button to individual event editor window: "Remove this event". When clicked, the currently displayed event will be removed from the timeslice it is in. The display will be refreshed accordingly. NOTE: This still has some bugs, namely that the last remaining event in a timeslice fails to be deleted.

Restructured Interface ScriptEventEditorPanel? to include a removeAssociatedEvent method, which calls a new method in I_ScriptEvent called removeThis, which causes the event to be removed from its timeslice.

Editor.Java previously contained several classes and enums, none of which were set to private scope. Moved these extra classes to their own files to decrease clutter in Editor.java and increase readability of all files.

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