[pitivi] Keep TimelineObjects sorted by start time in the Timeline.



commit ca085490494b2927d4457bc2f277c181ac5483ed
Author: Alessandro Decina <alessandro d gmail com>
Date:   Sun Jul 19 20:41:53 2009 +0200

    Keep TimelineObjects sorted by start time in the Timeline.
    
    Do the same as for Track, so that we can implement fast enough
    Timeline.getPreviousTimelineObject and Timeline.getNextTimelineObject.

 pitivi/timeline/timeline.py |   41 +++++++++++++++-
 tests/test_timeline.py      |  110 ++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 148 insertions(+), 3 deletions(-)
---
diff --git a/pitivi/timeline/timeline.py b/pitivi/timeline/timeline.py
index 4724e39..dedbb70 100644
--- a/pitivi/timeline/timeline.py
+++ b/pitivi/timeline/timeline.py
@@ -27,6 +27,8 @@ from pitivi.log.loggable import Loggable
 from pitivi.utils import UNKNOWN_DURATION, closest_item, PropertyChangeTracker
 from pitivi.timeline.track import SourceTrackObject, TrackError
 from pitivi.stream import match_stream_groups_map
+from pitivi.utils import start_insort_right, infinity, getPreviousObject, \
+        getNextObject
 
 # Selection modes
 SELECT = 0
@@ -414,7 +416,7 @@ class TimelineObject(Signallable, Loggable):
 
         # FIXME: cycle
         obj.timeline_object = self
-        self.track_objects.append(obj)
+        start_insort_right(self.track_objects, obj)
 
         self.emit("track-object-added", obj)
 
@@ -1279,7 +1281,9 @@ class Timeline(Signallable, Loggable):
         if not obj.track_objects:
             raise TimelineError()
 
-        self.timeline_objects.append(obj)
+        self._connectToTimelineObject(obj)
+
+        start_insort_right(self.timeline_objects, obj)
         obj.timeline = self
 
         self.edges.addTimelineObject(obj)
@@ -1304,6 +1308,8 @@ class Timeline(Signallable, Loggable):
         if obj.link is not None:
             obj.link.removeTimelineObject(obj)
 
+        self._disconnectFromTimelineObject(obj)
+
         obj.timeline = None
 
         self.edges.removeTimelineObject(obj)
@@ -1324,6 +1330,23 @@ class Timeline(Signallable, Loggable):
         for obj in objs:
             self.removeTimelineObject(obj, deep=True)
 
+    def _timelineObjectStartChangedCb(self, timeline_object, start):
+        self.timeline_objects.remove(timeline_object)
+        start_insort_right(self.timeline_objects, timeline_object)
+
+    def _timelineObjectDurationChangedCb(self, timeline_object, duration):
+        pass
+
+    def _connectToTimelineObject(self, timeline_object):
+        timeline_object.connect('start-changed',
+                self._timelineObjectStartChangedCb)
+        timeline_object.connect('duration-changed',
+                self._timelineObjectDurationChangedCb)
+
+    def _disconnectFromTimelineObject(self, timeline_object):
+        timeline_object.disconnect_by_function(self._timelineObjectStartChangedCb)
+        timeline_object.disconnect_by_function(self._timelineObjectDurationChangedCb)
+
     # FIXME : shouldn't this be made more generic (i.e. not specific to source factories) ?
     # FIXME : Maybe it should be up to the ObjectFactory to create the TimelineObject since
     #    it would know the exact type of TimelineObject to create with what properties (essential
@@ -1386,6 +1409,20 @@ class Timeline(Signallable, Loggable):
 
         return output_stream_to_track_map
 
+    def getPreviousTimelineObject(self, obj, priority=-1):
+        prev = getPreviousObject(obj, self.timeline_objects, priority)
+        if prev is None:
+            raise TimelineError("no previous timeline object", obj)
+
+        return prev
+
+    def getNextTimelineObject(self, obj, priority=-1):
+        next = getNextObject(obj, self.timeline_objects, priority)
+        if next is None:
+            raise TimelineError("no next timeline object", obj)
+
+        return next
+
     def setSelectionToObj(self, obj, mode):
         """
         Update the timeline's selection with the given object and mode.
diff --git a/tests/test_timeline.py b/tests/test_timeline.py
index facc27c..186f1d8 100644
--- a/tests/test_timeline.py
+++ b/tests/test_timeline.py
@@ -2,7 +2,7 @@
 #
 #       tests/test_timeline.py
 #
-# Copyright (c) 2008, Alessandro Decina <alessandro decina collabora co uk>
+# Copyright (c) 2008,2009, Alessandro Decina <alessandro decina collabora co uk>
 #
 # This program is free software; you can redistribute it and/or
 # modify it under the terms of the GNU Lesser General Public
@@ -346,6 +346,114 @@ class TestTimelineAddRemoveTimelineObjects(TestCase):
         timeline.removeFactory(factory)
         self.failUnlessEqual(len(timeline.timeline_objects), 0)
 
+class TestTimeline(TestCase):
+    def setUp(self):
+        self.factory = StubFactory()
+        self.stream = AudioStream(gst.Caps('audio/x-raw-int'))
+        self.factory.addOutputStream(self.stream)
+        self.track1 = Track(self.stream)
+        self.timeline = Timeline()
+        TestCase.setUp(self)
+
+    def tearDown(self):
+        del self.factory
+        del self.stream
+        del self.track1
+        del self.timeline
+
+    def makeTimelineObject(self):
+        track_object = SourceTrackObject(self.factory, self.stream)
+        self.track1.addTrackObject(track_object)
+        timeline_object = TimelineObject(self.factory)
+        timeline_object.addTrackObject(track_object)
+        self.timeline.addTimelineObject(timeline_object)
+
+        return timeline_object
+
+    def testGetPreviousTimelineObject(self):
+        timeline_object1 = self.makeTimelineObject()
+        timeline_object2 = self.makeTimelineObject()
+        timeline_object3 = self.makeTimelineObject()
+        timeline_object4 = self.makeTimelineObject()
+
+        timeline_object1.start = 1 * gst.SECOND
+        timeline_object1.duration = 5 * gst.SECOND
+        timeline_object1.priority = 1
+
+        timeline_object2.start = 8 * gst.SECOND
+        timeline_object2.duration = 5 * gst.SECOND
+        timeline_object2.priority = 1
+
+        timeline_object3.start = 6 * gst.SECOND
+        timeline_object3.duration = 5 * gst.SECOND
+        timeline_object3.priority = 2
+
+        timeline_object4.start = 7 * gst.SECOND
+        timeline_object4.duration = 5 * gst.SECOND
+        timeline_object4.priority = 3
+
+        timeline = self.timeline
+
+        # no previous track_objectect
+        self.failUnlessRaises(TimelineError,
+                timeline.getPreviousTimelineObject, timeline_object4)
+
+        # same priority
+        prev = timeline.getPreviousTimelineObject(timeline_object2)
+        self.failUnlessEqual(prev, timeline_object1)
+
+        # given priority
+        prev = timeline.getPreviousTimelineObject(timeline_object2, priority=2)
+        self.failUnlessEqual(prev, timeline_object3)
+
+        # any priority
+        prev = timeline.getPreviousTimelineObject(timeline_object2, priority=None)
+        self.failUnlessEqual(prev, timeline_object4)
+
+        timeline_object3.start = 8 * gst.SECOND
+        # same start
+        prev = timeline.getPreviousTimelineObject(timeline_object2, priority=None)
+        self.failUnlessEqual(prev, timeline_object3)
+
+    def testGetNextTrackObject(self):
+        timeline_object1 = self.makeTimelineObject()
+        timeline_object2 = self.makeTimelineObject()
+        timeline_object3 = self.makeTimelineObject()
+        timeline_object4 = self.makeTimelineObject()
+
+        timeline_object1.start = 1 * gst.SECOND
+        timeline_object1.duration = 5 * gst.SECOND
+        timeline_object1.priority = 1
+
+        timeline_object2.start = 8 * gst.SECOND
+        timeline_object2.duration = 5 * gst.SECOND
+        timeline_object2.priority = 1
+
+        timeline_object3.start = 6 * gst.SECOND
+        timeline_object3.duration = 5 * gst.SECOND
+        timeline_object3.priority = 2
+
+        timeline_object4.start = 7 * gst.SECOND
+        timeline_object4.duration = 5 * gst.SECOND
+        timeline_object4.priority = 3
+
+        timeline = self.timeline
+
+        # no next timeline_objectect
+        self.failUnlessRaises(TimelineError, timeline.getNextTimelineObject, timeline_object2)
+
+        # same priority
+        prev = timeline.getNextTimelineObject(timeline_object1)
+        self.failUnlessEqual(prev, timeline_object2)
+
+        # given priority
+        prev = timeline.getNextTimelineObject(timeline_object1, priority=2)
+        self.failUnlessEqual(prev, timeline_object3)
+
+        # any priority
+        prev = timeline.getNextTimelineObject(timeline_object3, priority=None)
+        self.failUnlessEqual(prev, timeline_object4)
+
 class TestLink(TestCase):
 
     def test(self):



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]