source: tmcsimulator-scriptbuilder/trunk/src/scriptbuilder/structures/ScriptIncident.java @ 150

Revision 150, 13.9 KB checked in by sdanthin, 6 years ago (diff)

IncidentTimelinePanel?.java added right-click menu popup functionality to add time
ScriptIncident?.java Added moveAllFollowingEvents function
ScriptIncidentTest?.java Added test to test moveAllFollowingEvents - may need better edge cases

Line 
1package scriptbuilder.structures;
2
3import java.awt.Color;
4import java.io.BufferedWriter;
5import java.io.File;
6import java.io.FileWriter;
7import java.util.ArrayList;
8import java.util.TreeMap;
9import scriptbuilder.structures.events.I_ScriptEvent;
10
11/**
12 * A script incident. It has an ID number, a name, and a description. It may
13 * contain several script events. It also has a color in the GUI window, and is
14 * collapsible. Incidents may start as soon as the script begins to run, or they
15 * can be offset from the start of the script.
16 *
17 * @author Greg Eddington <geddingt@calpoly.edu>
18 * @author Bryan McGuffin
19 * @version 2017/06/29
20 */
21public class ScriptIncident implements I_XML_Writable
22{
23
24    /**
25     * The moments in time which have associated events.
26     */
27    public TreeMap<Integer, TimeSlice> slices;
28
29    /**
30     * GUI display color of this slice.
31     */
32    public Color color;
33
34    /**
35     * ID number for this incident.
36     */
37    public int number;
38
39    /**
40     * Name of the incident.
41     */
42    public String name;
43
44    /**
45     * Description of the incident.
46     */
47    public String description;
48   
49    /**
50     * Length, in seconds, of the incident.
51     */
52    public int length = 0;
53
54    /**
55     * If true, incident appears minimized.
56     */
57    public boolean collapsed = false;
58
59    /**
60     * Number of seconds between start of simulation and start of this incident.
61     */
62    public int offset = 0;
63
64    /**
65     * Start position of the latest timeslice.
66     */
67    private int latestStart = 0;
68
69    /**
70     * Number of events in this incident.
71     */
72    public int eventCount = 0;
73
74    public SimulationScript script;
75
76    /**
77     * Basic constructor.
78     *
79     * @param number The incident ID number
80     * @param name The name of the incident
81     * @param description The description of the incident
82     * @param script The script object holding this incident
83     */
84    public ScriptIncident(int number, String name, String description,
85            SimulationScript script)
86    {
87        color = Color.BLACK;
88        this.number = number;
89        this.name = name;
90        this.description = description;
91        this.script = script;
92        slices = new TreeMap<Integer, TimeSlice>();
93    }
94
95    /**
96     * Constructor with color parameter.
97     *
98     * @param color The color to use in the GUI for this event
99     * @param number The incident ID number
100     * @param name The name of the incident
101     * @param description The description of the incident
102     * @param script The script object holding this incident
103     */
104    public ScriptIncident(Color color, int number, String name,
105            String description, SimulationScript script)
106    {
107        this.color = color;
108        this.number = number;
109        this.name = name;
110        this.description = description;
111        this.script = script;
112        slices = new TreeMap<Integer, TimeSlice>();
113    }
114
115    /**
116     * Constructor with color and offset parameters.
117     *
118     * @param color The color to use in the GUI for this event
119     * @param number The incident ID number
120     * @param name The name of the incident
121     * @param description The description of the incident
122     * @param script The script object holding this incident
123     * @param offset Number of seconds after 00:00:00 that this incident begins
124     */
125    public ScriptIncident(Color color, int number, String name,
126            String description, SimulationScript script,
127            int offset)
128    {
129        this.color = color;
130        this.number = number;
131        this.name = name;
132        this.description = description;
133        this.script = script;
134        slices = new TreeMap<Integer, TimeSlice>();
135        this.setOffset(offset);
136    }
137   
138//    /**
139//     * Constructor with type and location parameters.
140//     * @param color
141//     * @param number
142//     * @param name
143//     * @param description
144//     * @param script
145//     * @param offset
146//     * @param type
147//     * @param location
148//     */
149//    public ScriptIncident(Color color, int number, String name,
150//            String description, SimulationScript script,
151//            int offset, String type, String location)
152//    {
153//        this.color = color;
154//        this.number = number;
155//        this.name = name;
156//        this.description = description;
157//        this.script = script;
158//        slices = new TreeMap<Integer, TimeSlice>();
159//        this.setOffset(offset);
160//        this.location = location;
161//        this.type = type;
162//        insertCadData(offset, new CadData(type,location));
163//    }
164
165    /**
166     * Set whether or not the incident is fully visible or in a compacted state.
167     *
168     * @param collapsed True if the event is compacted
169     */
170    public void setCollapsed(boolean collapsed)
171    {
172        this.collapsed = collapsed;
173        script.update();
174    }
175
176    /**
177     * Set the delay time between the start of the script and the start of this
178     * incident.
179     *
180     * @param offset Number of seconds after 00:00:00 that this incident begins
181     */
182    public void setOffset(int offset)
183    {
184        int old = this.offset;
185        this.offset = offset;
186        TreeMap<Integer, TimeSlice> newSlices = new TreeMap<Integer, TimeSlice>();
187
188        int latest = 0;
189
190        for (Integer k : slices.keySet())
191        {
192            newSlices.put(k + (offset - old), slices.get(k));
193            latest = k + (offset - old);
194        }
195
196        latestStart = latest;
197
198        for (TimeSlice ts : newSlices.values())
199        {
200            ts.shift(offset - old);
201        }
202
203        slices = newSlices;
204        updateLength();
205        script.update();
206    }
207    /**
208     * shifts all timeslices over by timeAdd amount starting at offset
209     * @param offset amount of time preceding where we want to move all of the following events.
210     * @param timeAdd amount of time added after offset
211     */
212    public void moveAllFollowingEvents(int offset, int timeAdd)
213    {
214        //int old = this.offset;
215        TreeMap<Integer, TimeSlice> newSlices = new TreeMap<Integer, TimeSlice>();
216
217       
218
219        for (Integer k : slices.keySet())
220        {
221            if(k<offset)
222            {
223                newSlices.put(k, slices.get(k));
224            }else
225            {
226                if(k+timeAdd >0)
227                {
228                    newSlices.put(k+timeAdd, slices.get(k));
229                }else
230                {
231                    newSlices.put(0, slices.get(k));
232                }
233               
234            }
235           
236           
237        }
238        for (TimeSlice ts : newSlices.values())
239        {
240            if(ts.getTime()>offset )
241            {
242                if( ts.getTime()+timeAdd>=0)
243                {
244                    ts.shift(timeAdd);
245                }
246                else
247                {
248                    ts.shift(-ts.getTime());
249                }
250               
251            }
252           
253        }
254        latestStart = (latestStart + timeAdd>0) ? latestStart + timeAdd: 0;
255        slices = newSlices;
256        updateLength();
257        script.update();
258    }
259    /**
260     * Add a new script event to this incident.
261     *
262     * @param ev The new event
263     * @param start Start time of this event, in seconds, from the beginning of
264     * the simulation
265     */
266    public void addNewEvent(I_ScriptEvent ev, int start)
267    {
268        /*
269        int leftoverSeconds = start % 60;
270       
271        //round start time to the nearest minute
272        if(leftoverSeconds != 0)
273        {
274            if(leftoverSeconds > 30)
275            {
276                start += (60 - leftoverSeconds);
277            }
278            else
279            {
280                start -= leftoverSeconds;
281            }
282        }
283        */
284       
285        //Check to see if there's already a timeslice here
286        TimeSlice t = slices.get(start);
287        //If not, make one; then, add the event to it
288        if (t == null)
289        {
290            t = new TimeSlice(start, this);
291            t.addEvent(ev);
292            slices.put(start, t);
293        }
294        else
295        {
296            t.addEvent(ev);
297        }
298        eventCount++;
299
300        //If this is the latest start time in the incident, update that number
301        if (start > latestStart)
302        {
303            latestStart = start;
304        }
305        //If this event is earlier than all previous events, or if there are
306        //no other events, the offset is equal to this event's start time
307        if (start < offset || eventCount == 1)
308        {
309            offset = start;
310            //System.out.println("Offset: " + offset);
311        }
312        updateLength();
313    }
314
315    /**
316     * Get an array of all valid timeSlices.
317     *
318     * @return List of timeSlices which are not null
319     */
320    public ArrayList<TimeSlice> getSlices()
321    {
322        ArrayList<TimeSlice> arr = new ArrayList<TimeSlice>();
323        for (int i = 0; i <= latestStart; i++)
324        {
325            TimeSlice ts = slices.get(i);
326            if (ts != null)
327            {
328                arr.add(ts);
329            }
330        }
331        return arr;
332    }
333
334    /**
335     * Write this incident, in proper XML form, to the file in question.
336     *
337     * @param f the destination savefile
338     */
339    public void saveIncidentToFile(File f)
340    {
341        try
342        {
343            f.createNewFile();
344
345            BufferedWriter bw = new BufferedWriter(new FileWriter(f));
346            bw.write(this.toXML());
347            bw.flush();
348            bw.close();
349
350        }
351        catch (Exception ex)
352        {
353            System.out.println("ERROR SAVING SCRIPT");
354            ex.printStackTrace();
355        }
356    }
357
358    @Override
359    public String toXML()
360    {
361        String output = "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n";
362        output += XMLWriter.internalDTD();
363        output += XMLWriter.openTag(ELEMENT.TMC_SCRIPT.tag + " title=\"" + this.script.title + "\"");
364
365        for (TimeSlice slice : slices.values())
366        {
367            output += slice.toXML();
368        }
369        output += XMLWriter.closeTag(ELEMENT.TMC_SCRIPT.tag);
370        return output;
371    }
372
373    public void insertCadData(long currentEventTime, CadData cad)
374    {
375        int time = (int) currentEventTime;
376
377        TimeSlice slice;
378
379        if (slices.get(time) == null)
380        {
381            slices.put(time, new TimeSlice(time, this));
382        }
383        slice = slices.get(time);
384        slice.cadData = cad;
385    }
386   
387    public CadData getCadData(long currentEventTime)
388    {
389        int time = (int) currentEventTime;
390        TimeSlice slice;
391       
392        slice = slices.get(time);
393        return slice.cadData;
394    }
395
396    /**
397     * Update the offset and apparent length of this incident. The offset is the
398     * start time of the earliest event in the incident. The length is the time
399     * that the latest, longest-lasting event ends, minus the offset.
400     */
401    public void updateLength()
402    {
403        int lengthSoFar = 0;
404        for (int i = 0; i <= latestStart; i++)
405        {
406            TimeSlice ts = slices.get(i);
407            if (ts != null)
408            {
409                int reach = ts.getTime() + ts.getEffectiveDuration() - offset;
410                if (reach > lengthSoFar)
411                {
412                    lengthSoFar = reach;
413                }
414            }
415        }
416        length = lengthSoFar;
417    }
418
419    /**
420     * An event which is fired if the focused slice changes.
421     */
422    public static class SliceChangedEvent
423    {
424
425        /**
426         * The slice which has received focus in this event.
427         */
428        public TimeSlice slice;
429
430        SliceChangedEvent(TimeSlice slice)
431        {
432            this.slice = slice;
433        }
434    }
435
436    /**
437     * Update and cause the system to focus on the given timeslice.
438     *
439     * @param i Index of the slice to focus on
440     */
441    public void setSliceActive(int i)
442    {
443        if (this.slices.get(i) != null)
444        {
445            script.broadcastEvent(new SliceChangedEvent(this.slices.get(i)));
446        }
447    }
448
449    /**
450     * An event which is fired if the focused incident changes.
451     */
452    public static class IncidentFocusedEvent
453    {
454
455        /**
456         * The incident which has received focus in this event.
457         */
458        public ScriptIncident incident;
459
460        IncidentFocusedEvent(ScriptIncident i)
461        {
462            incident = i;
463        }
464    }
465
466    /**
467     * Update and cause the system to focus on this incident.
468     */
469    public void setIncidentActive()
470    {
471        script.broadcastEvent(new IncidentFocusedEvent(this));
472    }
473
474    /**
475     * String representation of this incident.
476     *
477     * @return String of the form "[Incident number] - [Incident name]"
478     */
479    @Override
480    public String toString()
481    {
482        return this.number + " - " + this.name;
483    }
484
485    /**
486     * Remove the timeslice at the given position.
487     *
488     * @param seconds absolute start time of the timeslice to remove.
489     */
490    public void removeTimeSlice(int seconds)
491    {
492        //remove the timeslice
493        this.slices.remove(seconds);
494
495        //offset is equivalent to start time of earliest slice
496        if (seconds == offset)
497        {
498            if (slices.size() > 0)
499            {
500                offset = slices.firstKey();
501            }
502            else
503            {
504                offset = 0;
505            }
506        }
507        this.updateLength();
508        script.update();
509    }
510
511    /**
512     * Shifts the start time of a given event in this incident. The first event
513     * in the incident cannot be shifted.
514     *
515     * @param evt the event to be relocated
516     * @param oldTime the current start time of the event
517     * @param newTime the destination start time of the event
518     * @return true if the event is shifted over properly
519     * @pre the event in question exists
520     * @pre oldTime != newTime
521     */
522    public boolean changeEventStart(I_ScriptEvent evt, int oldTime, int newTime)
523    {
524        if (!(oldTime == 0 && newTime > oldTime))
525        {
526            this.slices.get(oldTime).events.remove(evt);
527            this.addNewEvent(evt, newTime);
528            return true;
529        }
530        return false;
531    }
532}
Note: See TracBrowser for help on using the repository browser.