Warning: Can't use blame annotator:
svn blame failed on trunk/src/scriptbuilder/structures/ScriptIncident.java: ("Can't find a temporary directory: Internal error", 20014)

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

Revision 203, 16.8 KB checked in by jdalbey, 6 years ago (diff)

XMLWriter.java name changed to XMLBuilder. Add pretty printing methods (ticket #237).

RevLine 
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     * Adds an event to the correct timeslice when imported from an XML file.
266     * @param ev Event to be added to the timeslice.
267     * @param start Time when event needs to be added.
268     */
269    public void addNewEventFromXML(I_ScriptEvent ev, int start)
270    {
271        TimeSlice t = slices.get(start);
272        if(t==null)
273        {
274            t = new TimeSlice(start,this);
275            slices.put(start,t); 
276        }
277        t.addEvent(ev);
278        eventCount++;
279
280        //If this is the latest start time in the incident, update that number
281        if (start > latestStart)
282        {
283            latestStart = start;
284        }
285        //If this event is earlier than all previous events, or if there are
286        //no other events, the offset is equal to this event's start time
287        if (start < offset || eventCount == 1)
288        {
289            offset = start;
290            //System.out.println("Offset: " + offset);
291        }
292        updateLength();
293       
294    }
295    /**
296     * Add a new script event to this incident.
297     *
298     * @param ev The new event
299     * @param start Start time of this event, in seconds, from the beginning of
300     * the simulation
301     */
302    public void addNewEvent(I_ScriptEvent ev, int start)
303    {
304       
305       
306        //Check to see if there's already a timeslice here
307        TimeSlice t = slices.get(start);
308        //logic to check if the added event needs to also have an associated audio event.
309       
310        //If not, make one; then, add the event to it
311        if (t == null)
312        {
313            t = new TimeSlice(start, this);
314            slices.put(start, t);
315        }
316       
317        //checks if event to add is an I_AudioEvent and if the I_AudioEvent already has an AudioEvent to connect with it
318        if(ev instanceof I_AudioEvent){
319           
320           
321            //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.
322            if(!((I_AudioEvent) ev).getFileName().equals(""))
323            {
324                ((I_AudioEvent) ev).setID(((I_AudioEvent) ev).getFileName().replaceAll(".mp3",""));
325            }
326            // checks to see if the I_AudioEvent already has an ID or not, if not, set one based on the audioEventCount.
327            if(((I_AudioEvent) ev).getID().equals(""))
328            {
329                audioEventCount++;
330                //ternary expression here just prepends an extra 0 to the ID of the audioEvent if its eventcount is less than 10
331                ((I_AudioEvent) ev).setID(number+((audioEventCount<10)? "0"+Integer.toString(audioEventCount):Integer.toString(audioEventCount)));
332               
333            }
334            if(t.getCorrespondingAudioEvent((I_AudioEvent)ev)==null)
335            {
336                AudioEvent audio = (AudioEvent) ScriptEvent.factoryByType(ScriptEventType.AUDIO_EVENT);
337
338                //sets AudioEvent id to id of I_AudioEvent
339                audio.id = ((I_AudioEvent) ev).getID();
340                //sets I_AudioEvent filename to the AudioEvent id
341                ((I_AudioEvent) ev).setFileName(audio.id+ ".mp3");
342                //sets the file path of the AudioEvent based on its internal id
343                audio.setAudioFilePathRelative();
344                //adds AudioEvent to the timeslice
345                t.addEvent(audio);
346            }
347           
348           
349        }
350        t.addEvent(ev);
351        eventCount++;
352
353        //If this is the latest start time in the incident, update that number
354        if (start > latestStart)
355        {
356            latestStart = start;
357        }
358        //If this event is earlier than all previous events, or if there are
359        //no other events, the offset is equal to this event's start time
360        if (start < offset || eventCount == 1)
361        {
362            offset = start;
363            //System.out.println("Offset: " + offset);
364        }
365        updateLength();
366    }
367
368    /**
369     * Get an array of all valid timeSlices.
370     *
371     * @return List of timeSlices which are not null
372     */
373    public ArrayList<TimeSlice> getSlices()
374    {
375        ArrayList<TimeSlice> arr = new ArrayList<TimeSlice>();
376        for (int i = 0; i <= latestStart; i++)
377        {
378            TimeSlice ts = slices.get(i);
379            if (ts != null)
380            {
381                arr.add(ts);
382            }
383        }
384        return arr;
385    }
386
387    /**
388     * Write this incident, in proper XML form, to the file in question.
389     *
390     * @param f the destination savefile
391     */
392    public void saveIncidentToFile(File f)
393    {
394        try
395        {
396            f.createNewFile();
397
398            BufferedWriter bw = new BufferedWriter(new FileWriter(f));
399            bw.write(this.toXML());
400            bw.flush();
401            bw.close();
402
403        }
404        catch (Exception ex)
405        {
406            System.out.println("ERROR SAVING SCRIPT");
407            ex.printStackTrace();
408        }
409    }
410
411    @Override
412    public String toXML()
413    {
414        String output = "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n";
415        output += XMLBuilder.externalDTD();
416        output += XMLBuilder.openTag(ELEMENT.TMC_SCRIPT.tag + " title=\"" + this.script.title + "\"");
417
418        for (TimeSlice slice : slices.values())
419        {
420            output += slice.toXML();
421        }
422        output += XMLBuilder.closeTag(ELEMENT.TMC_SCRIPT.tag);
423        return output;
424    }
425
426    public void insertCadData(long currentEventTime, CadData cad)
427    {
428        int time = (int) currentEventTime;
429
430        TimeSlice slice;
431
432        if (slices.get(time) == null)
433        {
434            slices.put(time, new TimeSlice(time, this));
435        }
436        slice = slices.get(time);
437        slice.cadData = cad;
438    }
439   
440    public CadData getCadData(long currentEventTime)
441    {
442        int time = (int) currentEventTime;
443        TimeSlice slice;
444       
445        slice = slices.get(time);
446        return slice.cadData;
447    }
448
449    /**
450     * Update the offset and apparent length of this incident. The offset is the
451     * start time of the earliest event in the incident. The length is the time
452     * that the latest, longest-lasting event ends, minus the offset.
453     */
454    public void updateLength()
455    {
456        int lengthSoFar = 0;
457        for (int i = 0; i <= latestStart; i++)
458        {
459            TimeSlice ts = slices.get(i);
460            if (ts != null)
461            {
462                int reach = ts.getTime() + ts.getEffectiveDuration() - offset;
463                if (reach > lengthSoFar)
464                {
465                    lengthSoFar = reach;
466                }
467            }
468        }
469        length = lengthSoFar;
470    }
471
472    /**
473     * An event which is fired if the focused slice changes.
474     */
475    public static class SliceChangedEvent
476    {
477
478        /**
479         * The slice which has received focus in this event.
480         */
481        public TimeSlice slice;
482
483        SliceChangedEvent(TimeSlice slice)
484        {
485            this.slice = slice;
486        }
487    }
488
489    /**
490     * Update and cause the system to focus on the given timeslice.
491     *
492     * @param i Index of the slice to focus on
493     */
494    public void setSliceActive(int i)
495    {
496        if (this.slices.get(i) != null)
497        {
498            script.broadcastEvent(new SliceChangedEvent(this.slices.get(i)));
499        }
500    }
501
502    /**
503     * An event which is fired if the focused incident changes.
504     */
505    public static class IncidentFocusedEvent
506    {
507
508        /**
509         * The incident which has received focus in this event.
510         */
511        public ScriptIncident incident;
512
513        IncidentFocusedEvent(ScriptIncident i)
514        {
515            incident = i;
516        }
517    }
518
519    /**
520     * Update and cause the system to focus on this incident.
521     */
522    public void setIncidentActive()
523    {
524        script.broadcastEvent(new IncidentFocusedEvent(this));
525    }
526
527    /**
528     * String representation of this incident.
529     *
530     * @return String of the form "[Incident number] - [Incident name]"
531     */
532    @Override
533    public String toString()
534    {
535        return this.number + " - " + this.name;
536    }
537
538    /**
539     * Remove the timeslice at the given position.
540     *
541     * @param seconds absolute start time of the timeslice to remove.
542     */
543    public void removeTimeSlice(int seconds)
544    {
545        //remove the timeslice
546        this.slices.remove(seconds);
547
548        //offset is equivalent to start time of earliest slice
549        if (seconds == offset)
550        {
551            if (slices.size() > 0)
552            {
553                offset = slices.firstKey();
554            }
555            else
556            {
557                offset = 0;
558            }
559        }
560        this.updateLength();
561        script.update();
562    }
563
564    /**
565     * Shifts the start time of a given event in this incident. The first event
566     * in the incident cannot be shifted.
567     *
568     * @param evt the event to be relocated
569     * @param oldTime the current start time of the event
570     * @param newTime the destination start time of the event
571     * @return true if the event is shifted over properly
572     * @pre the event in question exists
573     * @pre oldTime != newTime
574     */
575    public boolean changeEventStart(I_ScriptEvent evt, int oldTime, int newTime)
576    {
577        if (!(oldTime == 0 && newTime > oldTime))
578        {
579            if(evt instanceof I_AudioEvent)
580            {
581                //todo: need to figure out how to remove the audioEvent tha corresponds with the
582                this.slices.get(oldTime).removeCorrespondingAudioEvent((I_AudioEvent)evt);
583                //this.addNewEvent(evt,newTime)
584            }
585            this.slices.get(oldTime).events.remove(evt);
586            this.addNewEvent(evt, newTime);
587            return true;
588        }
589        return false;
590    }
591}
Note: See TracBrowser for help on using the repository browser.