source: tmcsimulator-scriptbuilder/trunk/src/scriptbuilder/gui/panels/ScriptBuilderTimelinePanel.java @ 54

Revision 54, 12.6 KB checked in by bmcguffin, 9 years ago (diff)

Duplicated main ScriptBuilder? window. The new window will become the Incident Editor window (see Storyboard 2a-B). The main ScriptBuilder? window will become the Incident Combiner window (see storyboard 1a-B).

Line 
1package scriptbuilder.gui.panels;
2
3import event.editor.Editor;
4import event.editor.Properties;
5import java.awt.Dimension;
6import java.awt.Graphics;
7import java.awt.Graphics2D;
8import java.awt.event.MouseEvent;
9import java.util.HashMap;
10import java.util.Map;
11import javax.swing.JPanel;
12import javax.swing.event.MouseInputAdapter;
13import scriptbuilder.gui.IncidentEditorFrame;
14import scriptbuilder.gui.ScriptBuilderFrame;
15import scriptbuilder.gui.ScriptBuilderGuiConstants;
16import scriptbuilder.gui.drawers.CursorDrawer;
17import scriptbuilder.gui.drawers.EventIconDrawer;
18import scriptbuilder.gui.drawers.IncidentTimelineDrawer;
19import scriptbuilder.structures.ScriptEvent;
20import scriptbuilder.structures.ScriptEvent.ScriptEventType;
21import scriptbuilder.structures.ScriptIncident;
22import scriptbuilder.structures.TimeSlice;
23import scriptbuilder.structures.events.I_ScriptEvent;
24
25/**
26 * Represents a single incident timeline in the GUI. Listens for mouse actions.
27 *
28 * @author Greg Eddington <geddingt@calpoly.edu>
29 * @author Bryan McGuffin
30 * @version 2017/06/30
31 */
32public class ScriptBuilderTimelinePanel extends JPanel
33{
34
35    /**
36     * The incident this panel represents.
37     */
38    ScriptIncident incident;
39    /**
40     * If true, this panel is in its minimized state.
41     */
42    //boolean collapsed;
43    /**
44     * If false, this panel won't be drawn.
45     */
46    boolean visible;
47    /**
48     * If true, this panel has focus.
49     */
50    boolean focused;
51
52    int cursorTime, lastSlice, x, y;
53
54    /**
55     * The map representing the properties of this incident's events. Keys:
56     * event types. Values: Properties objects for those events.
57     */
58    Map<ScriptEventType, Properties> eventTypeToPropertyMap;
59
60    /**
61     * Listener for the mouse. Receives notifications when the mouse enters,
62     * exits, moves through, or clicks inside the panel.
63     */
64    public class IncidentTimelineMouseListener extends MouseInputAdapter
65    {
66
67        /**
68         * Action to take when the mouse enters the panel. Here, the incident
69         * corresponding to this panel gains focus.
70         *
71         * @param e the mouse event
72         */
73        @Override
74        public void mouseEntered(MouseEvent e)
75        {
76            incident.setIncidentActive();
77            focused = true;
78        }
79
80        /**
81         * Action to take when the mouse leaves the panel. Here, the incident
82         * loses focus and the panel gets repainted.
83         *
84         * @param e the mouse event
85         */
86        @Override
87        public void mouseExited(MouseEvent e)
88        {
89            focused = false;
90            repaint();
91        }
92
93        /**
94         * Determine if the mouse click happened within a valid timeSlice on
95         * this incident; if so, activate the Editor window for that timeSlice.
96         *
97         * @param e the mouse event
98         */
99        @Override
100        public void mouseClicked(MouseEvent e)
101        {
102            Editor ed = new Editor();
103            ScriptBuilderFrame f = null;
104            IncidentEditorFrame g = null;
105            if (getTopLevelAncestor() instanceof ScriptBuilderFrame)
106            {
107                f = (ScriptBuilderFrame) getTopLevelAncestor();
108            }
109            else if (getTopLevelAncestor() instanceof IncidentEditorFrame)
110            {
111                g = (IncidentEditorFrame) getTopLevelAncestor();
112            }
113
114            x = cursorTime = e.getX();
115            y = e.getY();
116
117            if (e.getX() % ScriptBuilderGuiConstants.PIXEL_WIDTH_PER_HORIZONTAL_TICK
118                    > ScriptBuilderGuiConstants.PIXEL_WIDTH_PER_HORIZONTAL_TICK / 2)
119            {
120                cursorTime += ScriptBuilderGuiConstants.PIXEL_WIDTH_PER_HORIZONTAL_TICK
121                        - e.getX()
122                        % ScriptBuilderGuiConstants.PIXEL_WIDTH_PER_HORIZONTAL_TICK;
123            }
124            else
125            {
126                cursorTime -= e.getX()
127                        % ScriptBuilderGuiConstants.PIXEL_WIDTH_PER_HORIZONTAL_TICK;
128            }
129
130            int newSlice = (cursorTime / ScriptBuilderGuiConstants.PIXEL_WIDTH_PER_HORIZONTAL_TICK);
131            newSlice *= ScriptBuilderGuiConstants.HORIZONTAL_TICK_RESOLUTION;
132            /**
133             * Check if click is out of bounds *
134             */
135            if (newSlice < 0 || incident == null)
136            {
137                return;
138            }
139
140            if (incident.slices.get(newSlice) != null)
141
142            {
143                for (I_ScriptEvent se : incident.slices.get(newSlice).events)
144                {
145                    ed.addProperty(eventTypeToPropertyMap.get(se.getScriptEventType()), se);
146                }
147            }
148
149            /**
150             * Add a new icon if left mouse button was clicked *
151             */
152            if (e.getButton() == MouseEvent.BUTTON1)
153            {
154                if (getTopLevelAncestor() instanceof ScriptBuilderFrame)
155                {
156                    if (f.currentEventType != null)
157                    {
158                        I_ScriptEvent s = ScriptEvent.factoryByType(f.currentEventType);
159                        ed.addProperty(eventTypeToPropertyMap.get(f.currentEventType), s);
160                        if (incident.slices.get(newSlice) == null)
161                        {
162                            incident.addNewEvent(s, newSlice);
163                        }
164                        else
165                        {
166                            incident.slices.get(newSlice).addEvent(s);
167                        }
168                        f.update(f.getScript(), f.getScript());
169                    }
170                }
171                if (getTopLevelAncestor() instanceof IncidentEditorFrame)
172                {
173                    if (g.currentEventType != null)
174                    {
175                        I_ScriptEvent s = ScriptEvent.factoryByType(g.currentEventType);
176                        ed.addProperty(eventTypeToPropertyMap.get(g.currentEventType), s);
177                        if (incident.slices.get(newSlice) == null)
178                        {
179                            incident.addNewEvent(s, newSlice);
180                        }
181                        else
182                        {
183                            incident.slices.get(newSlice).addEvent(s);
184                        }
185                        g.update(null, g.getIncident());
186                    }
187                }
188            }
189
190            if (incident.slices.get(newSlice) != null)
191            {
192                ed.setVisible(true);
193            }
194        }
195
196        /**
197         * Determine if the mouse is now hovering over a valid timeslice; if so,
198         * alter tooltip text and info window text to reflect the new timeslice.
199         *
200         * @param e the mouse event
201         */
202        @Override
203        public void mouseMoved(MouseEvent e)
204        {
205            x = cursorTime = e.getX();
206            y = e.getY();
207
208            if (e.getX() % ScriptBuilderGuiConstants.PIXEL_WIDTH_PER_HORIZONTAL_TICK
209                    > ScriptBuilderGuiConstants.PIXEL_WIDTH_PER_HORIZONTAL_TICK / 2)
210            {
211                cursorTime += ScriptBuilderGuiConstants.PIXEL_WIDTH_PER_HORIZONTAL_TICK
212                        - e.getX()
213                        % ScriptBuilderGuiConstants.PIXEL_WIDTH_PER_HORIZONTAL_TICK;
214            }
215            else
216            {
217                cursorTime -= e.getX()
218                        % ScriptBuilderGuiConstants.PIXEL_WIDTH_PER_HORIZONTAL_TICK;
219            }
220
221            if (incident != null)
222            {
223                int newSlice = (cursorTime / ScriptBuilderGuiConstants.PIXEL_WIDTH_PER_HORIZONTAL_TICK);
224                newSlice *= ScriptBuilderGuiConstants.HORIZONTAL_TICK_RESOLUTION;
225                if (newSlice >= 0 && incident.slices.get(newSlice) != null)
226                {
227                    incident.setSliceActive(newSlice);
228                    lastSlice = newSlice;
229                    String newToolTip;
230
231                    newToolTip = incident.slices.get(newSlice).toString();
232
233                    setToolTipText((newToolTip == null || newToolTip.equals(""))
234                            ? null : newToolTip);
235                }
236            }
237
238            repaint();
239        }
240    }
241
242    /**
243     * Constructor. Generates a HashMap of all possible event types.
244     */
245    public ScriptBuilderTimelinePanel()
246    {
247        super();
248
249//        FACILITATOR_EVAL_EVENT, RADIO_EVAL_EVENT
250        eventTypeToPropertyMap = new HashMap();
251        eventTypeToPropertyMap.put(ScriptEventType.AUDIO_EVENT, Properties.Audio);
252        eventTypeToPropertyMap.put(ScriptEventType.CAD_EVENT, Properties.CADLog);
253        eventTypeToPropertyMap.put(ScriptEventType.CCTV_EVENT, Properties.CCTV);
254        eventTypeToPropertyMap.put(ScriptEventType.CHP_RADIO_EVENT, Properties.CHPRadio);
255        eventTypeToPropertyMap.put(ScriptEventType.PARAMICS_EVENT, Properties.Paramics);
256        eventTypeToPropertyMap.put(ScriptEventType.TOW_EVENT, Properties.Tow);
257        eventTypeToPropertyMap.put(ScriptEventType.UNIT_EVENT, Properties.Unit);
258        eventTypeToPropertyMap.put(ScriptEventType.WITNESS_EVENT, Properties.Witness);
259        eventTypeToPropertyMap.put(ScriptEventType.MAINTENANCE_RADIO_EVENT, Properties.MaintenanceRadio);
260        eventTypeToPropertyMap.put(ScriptEventType.TMT_RADIO_EVENT, Properties.TMTRadio);
261        eventTypeToPropertyMap.put(ScriptEventType.TELEPHONE_EVENT, Properties.Telephone);
262        eventTypeToPropertyMap.put(ScriptEventType.ATMS_EVAL_EVENT, Properties.ATMS);
263        eventTypeToPropertyMap.put(ScriptEventType.ACTIVITY_LOG_EVAL_EVENT, Properties.ActivityLog);
264        eventTypeToPropertyMap.put(ScriptEventType.CAD_EVAL_EVENT, Properties.CAD);
265        eventTypeToPropertyMap.put(ScriptEventType.CMS_EVAL_EVENT, Properties.CMS);
266        eventTypeToPropertyMap.put(ScriptEventType.FACILITATOR_EVAL_EVENT, Properties.Facilitator);
267        eventTypeToPropertyMap.put(ScriptEventType.RADIO_EVAL_EVENT, Properties.Radio);
268
269        // Add the mouse listener
270        IncidentTimelineMouseListener mouseListener
271                = new IncidentTimelineMouseListener();
272        addMouseMotionListener(mouseListener);
273        addMouseListener(mouseListener);
274    }
275
276    /**
277     * Update the panel if it's changed collapsed status. Redraw it with the
278     * correct dimensions for its status.
279     *
280     * @param incident the incident this panel represents
281     */
282    public void timelinePanelUpdate(ScriptIncident incident)
283    {
284        this.incident = incident;
285        this.visible = incident != null;
286
287        Dimension newSize;
288        if (visible)
289        {
290
291            newSize = new Dimension(((incident.length + incident.offset)
292                    / ScriptBuilderGuiConstants.HORIZONTAL_TICK_RESOLUTION
293                    * ScriptBuilderGuiConstants.PIXEL_WIDTH_PER_HORIZONTAL_TICK)
294                    + ScriptBuilderGuiConstants.EVENT_ICON_WIDTH,
295                    ScriptBuilderGuiConstants.TIMELINE_COLLAPSED_HEIGHT
296                    + ScriptBuilderGuiConstants.SCRIPT_EVENT_ICON_STEP * 2);
297
298        }
299        else
300        {
301            newSize = new Dimension(0, 0);
302        }
303        this.setSize(newSize);
304        this.setPreferredSize(newSize);
305
306        invalidate();
307    }
308
309    /**
310     * Redraw this panel and all the icons inside it. If user is holding an
311     * event, draw that icon under the mouse.
312     *
313     * @param g the graphics component
314     */
315    @Override
316    public void paint(Graphics g)
317    {
318        super.paint(g);
319
320        if (!visible)
321        {
322            return;
323        }
324
325        Graphics2D g2d = (Graphics2D) g;
326        if (getTopLevelAncestor() instanceof ScriptBuilderFrame)
327        {
328            IncidentTimelineDrawer.DrawScriptBuilderTimeline(g2d, incident);
329        }
330        if (getTopLevelAncestor() instanceof IncidentEditorFrame)
331        {
332            IncidentTimelineDrawer.DrawIncidentTimeline(g2d, incident, false);
333        }
334
335        if (focused)
336        {
337            CursorDrawer.DrawCursor(g2d, cursorTime, false);
338            if (this.getTopLevelAncestor() instanceof ScriptBuilderFrame)
339            {
340                if (((ScriptBuilderFrame) this.getTopLevelAncestor()).currentEventType != null)
341                {
342                    EventIconDrawer.DrawEventIcon(g2d,
343                            ((ScriptBuilderFrame) this.getTopLevelAncestor()).currentEventType,
344                            x + 5, y + 10);
345                }
346            }
347            if (this.getTopLevelAncestor() instanceof IncidentEditorFrame)
348            {
349                if (((IncidentEditorFrame) this.getTopLevelAncestor()).currentEventType != null)
350                {
351                    EventIconDrawer.DrawEventIcon(g2d,
352                            ((IncidentEditorFrame) this.getTopLevelAncestor()).currentEventType,
353                            x + 5, y + 10);
354                }
355            }
356        }
357    }
358}
Note: See TracBrowser for help on using the repository browser.