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

Revision 167, 15.8 KB checked in by sdanthin, 6 years ago (diff)

TimeSlice?.java modified remove/getcorrespondingAudioEvent to work with ID system. CHPRadioEvent.java modified to implement setID and ids in the I_AudioEvent.java. ScriptIncident? "adding event" modified to account for ID system. AudioEvent? has ids added. Preliminary tests show working.

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