[pitivi] Make MoveContext avoid clip overlaps.



commit f92e1f61e044380f22ab8dba4da4ad5197d8664b
Author: Alessandro Decina <alessandro d gmail com>
Date:   Sun Jul 19 20:47:39 2009 +0200

    Make MoveContext avoid clip overlaps.

 pitivi/timeline/timeline.py |  139 +++++++++++++------
 tests/test_timeline.py      |  314 ++++++++++++++++++++++++++++++++++++-------
 2 files changed, 358 insertions(+), 95 deletions(-)
---
diff --git a/pitivi/timeline/timeline.py b/pitivi/timeline/timeline.py
index dedbb70..09a5696 100644
--- a/pitivi/timeline/timeline.py
+++ b/pitivi/timeline/timeline.py
@@ -29,6 +29,7 @@ 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
+from pitivi.timeline.gap import Gap, SmallestGapsFinder, invalid_gap
 
 # Selection modes
 SELECT = 0
@@ -933,8 +934,8 @@ class EditingContext(object):
         self.timeline = timeline
         self._snap = True
         self._mode = self.DEFAULT
-        self._last_position = None
-        self._last_priority = None
+        self._last_position = focus.start
+        self._last_priority = focus.priority
 
         self.timeline.disableUpdates()
 
@@ -1004,7 +1005,7 @@ class EditingContext(object):
         pass
 
     def _rollTo(self, position, priority):
-        pass
+        return position, priority
 
     def _finishRipple(self):
         pass
@@ -1016,7 +1017,7 @@ class EditingContext(object):
         pass
 
     def _defaultTo(self, position, priority):
-        pass
+        return position, priority
 
     def snap(self, snap):
         """Set whether edge snapping is currently enabled"""
@@ -1025,14 +1026,16 @@ class EditingContext(object):
         self._snap = snap
 
     def editTo(self, position, priority):
-        self._last_position = position
-        self._last_priority = priority
         if self._mode == self.DEFAULT:
-            self._defaultTo(position, priority)
+            position, priority = self._defaultTo(position, priority)
         if self._mode == self.ROLL:
-            self._rollTo(position, priority)
+            position, priority = self._rollTo(position, priority)
         elif self._mode == self.RIPPLE:
-            self._rippleTo(position, priority)
+            position, priority = self._rippleTo(position, priority)
+        self._last_position = position
+        self._last_priority = priority
+
+        return position, priority
 
 class MoveContext(EditingContext):
 
@@ -1042,53 +1045,61 @@ class MoveContext(EditingContext):
     def __init__(self, timeline, focus, other):
         EditingContext.__init__(self, timeline, focus, other)
 
-        # calculate minimum start time and priority
-        self.earliest = focus.start
-        self.min_priority = focus.priority
-        self.latest = focus.start + focus.duration
-        
-        timeline_objects = []
-        self.default_originals = {}
-        for track_object in other:
-            timeline_object = track_object.timeline_object
-            timeline_objects.append(timeline_object)
-
-            if timeline_object.start < self.earliest:
-                self.earliest = timeline_object.start
+        self.timeline_objects = set(track_object.timeline_object
+                for track_object in other)
+        self.timeline_objects.add(focus.timeline_object)
 
-            self.latest = max(self.latest, timeline_object.start +
-                timeline_object.duration)
-
-            if timeline_object.priority < self.min_priority:
-                self.min_priority = timeline_object.min_priority
+        min_priority = infinity
+        earliest = infinity
+        latest = 0
+        self.default_originals = {}
+        for timeline_object in self.timeline_objects:
+            self.default_originals[timeline_object] = \
+                    self._getTimelineObjectValues(timeline_object)
 
-        self.default_originals = self._saveValues(timeline_objects)
+            earliest = min(earliest, timeline_object.start)
+            latest = max(latest,
+                    timeline_object.start + timeline_object.duration)
+            min_priority = min(min_priority, timeline_object.priority)
 
         self.offsets = self._getOffsets(self.focus.start, self.focus.priority,
-                timeline_objects)
+                self.timeline_objects)
 
-        self.focal_offset = (focus.start - self.earliest,
-                focus.priority - self.min_priority)
+        self.min_priority = focus.priority - min_priority
 
         # get the span over all clips for edge snapping
-        self.default_span = self.latest - self.earliest
+        self.default_span = latest - earliest
 
-        ripple = timeline.getObjsAfterTime(self.latest)
+        ripple = timeline.getObjsAfterTime(latest)
         self.ripple_offsets = self._getOffsets(self.focus.start,
             self.focus.priority, ripple)
 
         # get the span over all clips for ripple editing
-
-        latest = self.latest
         for timeline_object in ripple:
             latest = max(latest, timeline_object.start +
                 timeline_object.duration)
-        self.ripple_span = latest - self.earliest
+        self.ripple_span = latest - earliest
 
         # save default values
-        self.default_originals = self._saveValues(other)
         self.ripple_originals = self._saveValues(ripple)
 
+        self.timeline_objects_plus_ripple = set(self.timeline_objects)
+        self.timeline_objects_plus_ripple.update(ripple)
+
+    def _getGapsAtPriority(self, priority):
+        if self._mode == self.RIPPLE:
+            timeline_objects = self.timeline_objects_plus_ripple
+        else:
+            timeline_objects = self.timeline_objects
+        gaps = SmallestGapsFinder(timeline_objects)
+        prio_diff = priority - self.focus.priority
+
+        for timeline_object in timeline_objects:
+            gaps.update(*Gap.findAroundObject(timeline_object,
+                    timeline_object.priority + prio_diff))
+
+        return gaps.left_gap, gaps.right_gap
+
     def setMode(self, mode):
         if mode == self.ROLL:
             raise Exception("invalid mode ROLL")
@@ -1098,27 +1109,61 @@ class MoveContext(EditingContext):
         self._restoreValues(self.default_originals)
 
     def _defaultTo(self, position, priority):
-        position = max(0, position, self.focal_offset[0])
-        priority = max(0, priority, self.focal_offset[1])
         if self._snap:
-            position = self.timeline.snapToEdge(position, 
+            position = self.timeline.snapToEdge(position,
                 position + self.default_span)
-        self.focus.setStart(position)
+
+        priority = max(self.min_priority, priority)
+        left_gap, right_gap = self._getGapsAtPriority(priority)
+
+        if left_gap is invalid_gap or right_gap is invalid_gap:
+            if priority == self._last_priority:
+                # abort move
+                return self._last_position, self._last_priority
+
+            # try to do the same time move, using the current priority
+            return self._defaultTo(position, self._last_priority)
+
+        delta = position - self.focus.start
+        if delta > 0 and right_gap.duration < delta:
+            position = self.focus.start + right_gap.duration
+        elif delta < 0 and left_gap.duration < abs(delta):
+            position = self.focus.start - left_gap.duration
+
         self.focus.priority = priority
+        self.focus.setStart(position, snap = self._snap)
 
         for obj, (s_offset, p_offset) in self.offsets.iteritems():
             obj.setStart(position + s_offset)
             obj.priority = priority + p_offset
 
+        return position, priority
+
     def _finishRipple(self):
         self._restoreValues(self.ripple_originals)
 
     def _rippleTo(self, position, priority):
-        position = max(0, position, self.focal_offset[0])
-        priority = max(0, priority, self.focal_offset[1])
         if self._snap:
-            position = self.timeline.snapToEdge(position, 
+            position = self.timeline.snapToEdge(position,
                 position + self.ripple_span)
+
+        priority = max(self.min_priority, priority)
+        left_gap, right_gap = self._getGapsAtPriority(priority)
+
+        if left_gap is invalid_gap or right_gap is invalid_gap:
+            if priority == self._last_priority:
+                # abort move
+                return self._last_position, self._last_priority
+
+            # try to do the same time move, using the current priority
+            return self._defaultTo(position, self._last_priority)
+
+        delta = position - self.focus.start
+        if delta > 0 and right_gap.duration < delta:
+            position = self.focus.start + right_gap.duration
+        elif delta < 0 and left_gap.duration < abs(delta):
+            position = self.focus.start - left_gap.duration
+
         self.focus.setStart(position)
         self.focus.priority = priority
         for obj, (s_offset, p_offset) in self.offsets.iteritems():
@@ -1128,6 +1173,8 @@ class MoveContext(EditingContext):
             obj.setStart(position + s_offset)
             obj.priority = priority + p_offset
 
+        return position, priority
+
 class TrimStartContext(EditingContext):
 
     def __init__(self, timeline, focus, other):
@@ -1149,6 +1196,8 @@ class TrimStartContext(EditingContext):
         earliest = self.focus.start - self.focus.in_point
         self.focus.trimStart(max(position, earliest), snap=self.snap)
 
+        return position, priority
+
 class TrimEndContext(EditingContext):
 
     def __init__(self, timeline, focus, other):
@@ -1171,6 +1220,8 @@ class TrimEndContext(EditingContext):
         duration = max(0, position - self.focus.start)
         self.focus.setDuration(duration, snap=self.snap)
 
+        return position, priority
+
 class Timeline(Signallable, Loggable):
     """
     Top-level container for L{TimelineObject}s.
diff --git a/tests/test_timeline.py b/tests/test_timeline.py
index 186f1d8..f28f6b4 100644
--- a/tests/test_timeline.py
+++ b/tests/test_timeline.py
@@ -847,24 +847,23 @@ class TestContexts(TestCase):
         self.timeline.addTimelineObject(self.timeline_object1)
         self.timeline.addTimelineObject(self.timeline_object2)
         self.timeline.addTimelineObject(self.timeline_object3)
-        self.focus = self.track_object1
         self.other = set([self.track_object2, self.track_object3])
 
     def testMoveContext(self):
         # set up the initial state of the timeline and create the track object
         # [focus]     [t2   ]     [t3     ]
-        self.focus.start = 0
-        self.focus.duration = gst.SECOND * 5
+        self.track_object1.start = 0
+        self.track_object1.duration = gst.SECOND * 5
         self.track_object2.start = 15 * gst.SECOND
         self.track_object3.start = 25 * gst.SECOND
-        context = MoveContext(self.timeline, self.focus, set())
+        context = MoveContext(self.timeline, self.track_object1, set())
 
         # make an edit, check that the edit worked as expected
         #    [focus]  [t2   ]     [t3     ]
         context.editTo(gst.SECOND * 10, 0)
-        self.failUnlessEqual(self.focus.start, gst.SECOND * 10)
-        self.failUnlessEqual(self.focus.duration,  gst.SECOND * 5)
-        self.failUnlessEqual(self.focus.in_point, 0)
+        self.failUnlessEqual(self.track_object1.start, gst.SECOND * 10)
+        self.failUnlessEqual(self.track_object1.duration,  gst.SECOND * 5)
+        self.failUnlessEqual(self.track_object1.in_point, 0)
         self.failUnlessEqual(self.track_object2.start, gst.SECOND * 15)
         self.failUnlessEqual(self.track_object3.start, gst.SECOND * 25)
 
@@ -872,9 +871,9 @@ class TestContexts(TestCase):
         #            [focus]  [t2   ]     [t3     ]
         context.setMode(context.RIPPLE)
         context.editTo(gst.SECOND * 20, 0)
-        self.failUnlessEqual(self.focus.start, gst.SECOND * 20)
-        self.failUnlessEqual(self.focus.duration,  gst.SECOND * 5)
-        self.failUnlessEqual(self.focus.in_point, 0)
+        self.failUnlessEqual(self.track_object1.start, gst.SECOND * 20)
+        self.failUnlessEqual(self.track_object1.duration,  gst.SECOND * 5)
+        self.failUnlessEqual(self.track_object1.in_point, 0)
         self.failUnlessEqual(self.track_object2.start, gst.SECOND * 35)
         self.failUnlessEqual(self.track_object3.start, gst.SECOND * 45)
 
@@ -882,41 +881,38 @@ class TestContexts(TestCase):
         #             [t2   ]     [t3     ]
         #            [focus]
         context.setMode(context.DEFAULT)
-        self.failUnlessEqual(self.focus.start, gst.SECOND * 20)
-        self.failUnlessEqual(self.focus.duration,  gst.SECOND * 5)
-        self.failUnlessEqual(self.focus.in_point, 0)
+        self.failUnlessEqual(self.track_object1.start, gst.SECOND * 20)
+        self.failUnlessEqual(self.track_object1.duration,  gst.SECOND * 5)
+        self.failUnlessEqual(self.track_object1.in_point, 0)
         self.failUnlessEqual(self.track_object2.start, gst.SECOND * 15)
         self.failUnlessEqual(self.track_object3.start, gst.SECOND * 25)
 
         context.finish()
 
-        self.failUnlessEqual(self.focus.start, 20 * gst.SECOND)
-        self.failUnlessEqual(self.track_object2.start, 15 * gst.SECOND)
-        self.failUnlessEqual(self.track_object3.start, 25 * gst.SECOND)
-
     def testMoveContextFocusNotEarliest(self):
         #     [t2  ][focus]  [t3     ]
-        self.focus.start = 10 * gst.SECOND
-        self.focus.duration = 5 * gst.SECOND
+        self.track_object1.start = 10 * gst.SECOND
+        self.track_object1.duration = 5 * gst.SECOND
         self.track_object2.start = 1 * gst.SECOND
         self.track_object2.duration = 9 * gst.SECOND
         self.track_object3.start = 15 * gst.SECOND
         self.track_object3.duration = 10 * gst.SECOND
+        self.track_object3.priority = 1
         other = set([self.track_object2])
 
-        context = MoveContext(self.timeline, self.focus, other)
+        context = MoveContext(self.timeline, self.track_object1, other)
         context.editTo(20 * gst.SECOND, 0)
 
         #                           [t2  ][focus] 
         #                    [t3     ]
-        self.failUnlessEqual(self.focus.start, 20 * gst.SECOND)
+        self.failUnlessEqual(self.track_object1.start, 20 * gst.SECOND)
         self.failUnlessEqual(self.track_object2.start, 11 * gst.SECOND)
         self.failUnlessEqual(self.track_object3.start, 15 * gst.SECOND)
 
         context.setMode(context.RIPPLE)
 
         #                            [t2  ][focus]  [t3     ]
-        self.failUnlessEqual(self.focus.start, 20 * gst.SECOND)
+        self.failUnlessEqual(self.track_object1.start, 20 * gst.SECOND)
         self.failUnlessEqual(self.track_object2.start, 11 * gst.SECOND)
         self.failUnlessEqual(self.track_object3.start, 25 * gst.SECOND)
 
@@ -924,35 +920,234 @@ class TestContexts(TestCase):
 
         #                           [t2  ][focus] 
         #                    [t3     ]
-        self.failUnlessEqual(self.focus.start, 20 * gst.SECOND)
+        self.failUnlessEqual(self.track_object1.start, 20 * gst.SECOND)
         self.failUnlessEqual(self.track_object2.start, 11 * gst.SECOND)
         self.failUnlessEqual(self.track_object3.start, 15 * gst.SECOND)
 
         context.finish()
 
-    def testNothingToRipple(self):
-        self.focus.start = 20 * gst.SECOND
-        self.focus.duration = 5 * gst.SECOND
+    def testMoveContextMargins(self):
+        self.other = set([self.track_object3])
+
+        self.track_object1.start = 16 * gst.SECOND
+        self.track_object1.duration = 10 * gst.SECOND
+
         self.track_object2.start = 10 * gst.SECOND
-        self.track_object2.duration = 1 * gst.SECOND
-        self.track_object3.start = 11 * gst.SECOND
-        self.track_object3.duration = 1 * gst.SECOND
+        self.track_object2.duration = 5 * gst.SECOND
 
-        context = MoveContext(self.timeline, self.focus, set())
-        context.setMode(context.RIPPLE)
+        self.track_object3.start = 3 * gst.SECOND
+        self.track_object3.duration = 7 * gst.SECOND
+
+        # move before left margin, should clamp
+        context = MoveContext(self.timeline, self.track_object1, self.other)
+        context.editTo(8 * gst.SECOND, 0)
+        context.finish()
+
+        self.failUnlessEqual(self.track_object1.start, 15 * gst.SECOND)
+        self.failUnlessEqual(self.track_object2.start, 10 * gst.SECOND)
+        self.failUnlessEqual(self.track_object3.start, 2 * gst.SECOND)
+
+        # move back, no clamp
+        context = MoveContext(self.timeline, self.track_object1, self.other)
+        context.editTo(16 * gst.SECOND, 0)
+        context.finish()
+
+        self.failUnlessEqual(self.track_object1.start, 16 * gst.SECOND)
+        self.failUnlessEqual(self.track_object2.start, 10 * gst.SECOND)
+        self.failUnlessEqual(self.track_object3.start, 3 * gst.SECOND)
+
+        # move past right margin, should clamp
+        context = MoveContext(self.timeline, self.track_object2, self.other)
+        context.editTo(20 * gst.SECOND, 0)
+
+        self.failUnlessEqual(self.track_object1.start, 16 * gst.SECOND)
+        self.failUnlessEqual(self.track_object2.start, 11 * gst.SECOND)
+        self.failUnlessEqual(self.track_object3.start, 4 * gst.SECOND)
+
+    def testMoveContextMarginsPriorityChange(self):
+        self.other = set([self.track_object3])
+
+        self.track_object1.start = 5 * gst.SECOND
+        self.track_object1.duration = 10 * gst.SECOND
+        self.track_object1.priority = 0
+
+        self.track_object2.start = 5 * gst.SECOND
+        self.track_object2.duration = 10 * gst.SECOND
+        self.track_object2.priority = 1
+
+        self.track_object3.start = 15 * gst.SECOND
+        self.track_object3.duration = 10 * gst.SECOND
+        self.track_object3.priority = 1
+
+        # same start, priority bump
+        context = MoveContext(self.timeline, self.track_object2, self.other)
+        context.editTo(5 * gst.SECOND, 0)
+        context.finish()
+
+        self.failUnlessEqual(self.track_object1.start, 5 * gst.SECOND)
+        self.failUnlessEqual(self.track_object1.priority, 0)
+        self.failUnlessEqual(self.track_object2.start, 5 * gst.SECOND)
+        self.failUnlessEqual(self.track_object2.priority, 1)
+        self.failUnlessEqual(self.track_object3.start, 15 * gst.SECOND)
+        self.failUnlessEqual(self.track_object3.priority, 1)
+
+        # collapse left
+        self.track_object2.start = 4 * gst.SECOND
+        self.track_object2.duration = 10 * gst.SECOND
+        self.track_object2.priority = 1
+
+        context = MoveContext(self.timeline, self.track_object2, self.other)
+        context.editTo(4 * gst.SECOND, 0)
+        context.finish()
+
+        self.failUnlessEqual(self.track_object1.start, 5 * gst.SECOND)
+        self.failUnlessEqual(self.track_object1.priority, 0)
+        self.failUnlessEqual(self.track_object2.start, 4 * gst.SECOND)
+        self.failUnlessEqual(self.track_object2.priority, 1)
+        self.failUnlessEqual(self.track_object3.start, 15 * gst.SECOND)
+        self.failUnlessEqual(self.track_object3.priority, 1)
+        
+        # collapse right
+        self.track_object2.start = 6 * gst.SECOND
+        self.track_object2.duration = 10 * gst.SECOND
+        self.track_object2.priority = 1
+
+        context = MoveContext(self.timeline, self.track_object2, self.other)
+        context.editTo(6 * gst.SECOND, 0)
+        context.finish()
+
+        self.failUnlessEqual(self.track_object1.start, 5 * gst.SECOND)
+        self.failUnlessEqual(self.track_object1.priority, 0)
+        self.failUnlessEqual(self.track_object2.start, 6 * gst.SECOND)
+        self.failUnlessEqual(self.track_object2.priority, 1)
+        self.failUnlessEqual(self.track_object3.start, 15 * gst.SECOND)
+        self.failUnlessEqual(self.track_object3.priority, 1)
+
+    def testMoveContextMarginsPriorityChangeMore(self):
+        self.other = set([self.track_object3])
+
+        self.track_object1.start = 20 * gst.SECOND
+        self.track_object1.duration = 10 * gst.SECOND
+        self.track_object1.priority = 0
+
+        self.track_object2.start = 10 * gst.SECOND
+        self.track_object2.duration = 10 * gst.SECOND
+        self.track_object2.priority = 1
+
+        self.track_object3.start = 20 * gst.SECOND
+        self.track_object3.duration = 10 * gst.SECOND
+        self.track_object3.priority = 1
+
+        # same start, priority bump
+        context = MoveContext(self.timeline, self.track_object2, self.other)
         context.editTo(10 * gst.SECOND, 0)
+        context.finish()
 
-        self.failUnlessEqual(self.focus.start, 10 * gst.SECOND)
+        self.failUnlessEqual(self.track_object1.start, 20 * gst.SECOND)
+        self.failUnlessEqual(self.track_object1.priority, 0)
         self.failUnlessEqual(self.track_object2.start, 10 * gst.SECOND)
-        self.failUnlessEqual(self.track_object3.start, 11 * gst.SECOND)
+        self.failUnlessEqual(self.track_object2.priority, 1)
+        self.failUnlessEqual(self.track_object3.start, 20 * gst.SECOND)
+        self.failUnlessEqual(self.track_object3.priority, 1)
+
+        # collapse left
+        self.track_object2.start = 9 * gst.SECOND
+        self.track_object2.duration = 10 * gst.SECOND
+        self.track_object2.priority = 1
+
+        self.track_object3.start = 19 * gst.SECOND
+        self.track_object3.duration = 10 * gst.SECOND
+        self.track_object3.priority = 1
+
+        context = MoveContext(self.timeline, self.track_object2, self.other)
+        context.editTo(9 * gst.SECOND, 0)
+        context.finish()
 
+        self.failUnlessEqual(self.track_object1.start, 20 * gst.SECOND)
+        self.failUnlessEqual(self.track_object1.priority, 0)
+        self.failUnlessEqual(self.track_object2.start, 9 * gst.SECOND)
+        self.failUnlessEqual(self.track_object2.priority, 1)
+        self.failUnlessEqual(self.track_object3.start, 19 * gst.SECOND)
+        self.failUnlessEqual(self.track_object3.priority, 1)
+        
+        # collapse right
+        self.track_object2.start = 21 * gst.SECOND
+        self.track_object2.duration = 10 * gst.SECOND
+        self.track_object2.priority = 1
+
+        self.track_object3.start = 31 * gst.SECOND
+        self.track_object3.duration = 10 * gst.SECOND
+        self.track_object3.priority = 1
+
+        context = MoveContext(self.timeline,
+                self.track_object3, set([self.track_object2]))
+        context.editTo(31 * gst.SECOND, 0)
+        context.finish()
+
+        self.failUnlessEqual(self.track_object1.start, 20 * gst.SECOND)
+        self.failUnlessEqual(self.track_object1.priority, 0)
+        self.failUnlessEqual(self.track_object2.start, 21 * gst.SECOND)
+        self.failUnlessEqual(self.track_object2.priority, 1)
+        self.failUnlessEqual(self.track_object3.start, 31 * gst.SECOND)
+        self.failUnlessEqual(self.track_object3.priority, 1)
+
+    def testMoveContextMarginsZigZag(self):
+        self.track_object4 = SourceTrackObject(self.factory, self.stream)
+        self.track1.addTrackObject(self.track_object4)
+        self.timeline_object4 = TimelineObject(self.factory)
+        self.timeline_object4.addTrackObject(self.track_object4)
+        self.timeline.addTimelineObject(self.timeline_object4)
+
+        self.track_object1.start = 0 * gst.SECOND
+        self.track_object1.duration = 10 * gst.SECOND
+        self.track_object1.priority = 0
+
+        self.track_object2.start = 15 * gst.SECOND
+        self.track_object2.duration = 10 * gst.SECOND
+        self.track_object2.priority = 0
+
+        self.track_object3.start = 10 * gst.SECOND
+        self.track_object3.duration = 10 * gst.SECOND
+        self.track_object3.priority = 1
 
-        #TODO: test trim context ripple modes when implemented
+        self.track_object4.start = 25 * gst.SECOND
+        self.track_object4.duration = 10 * gst.SECOND
+        self.track_object4.priority = 1
+
+        context = MoveContext(self.timeline, self.track_object2,
+                set([self.track_object3]))
+        context.editTo(9 * gst.SECOND, 0)
+        context.finish()
+
+        self.failUnlessEqual(self.track_object1.start, 0 * gst.SECOND)
+        self.failUnlessEqual(self.track_object1.priority, 0)
+        self.failUnlessEqual(self.track_object2.start, 10 * gst.SECOND)
+        self.failUnlessEqual(self.track_object2.priority, 0)
+        self.failUnlessEqual(self.track_object3.start, 5 * gst.SECOND)
+        self.failUnlessEqual(self.track_object3.priority, 1)
+        self.failUnlessEqual(self.track_object4.start, 25 * gst.SECOND)
+        self.failUnlessEqual(self.track_object4.priority, 1)
+
+        context = MoveContext(self.timeline, self.track_object2,
+                set([self.track_object3]))
+        context.editTo(25 * gst.SECOND, 0)
+        context.finish()
+
+        self.failUnlessEqual(self.track_object1.start, 0 * gst.SECOND)
+        self.failUnlessEqual(self.track_object1.priority, 0)
+        self.failUnlessEqual(self.track_object2.start, 20 * gst.SECOND)
+        self.failUnlessEqual(self.track_object2.priority, 0)
+        self.failUnlessEqual(self.track_object3.start, 15 * gst.SECOND)
+        self.failUnlessEqual(self.track_object3.priority, 1)
+        self.failUnlessEqual(self.track_object4.start, 25 * gst.SECOND)
+        self.failUnlessEqual(self.track_object4.priority, 1)
+
+        del self.timeline_object4
+        del self.track_object4
 
     def testTrimStartContext(self):
-        self.focus.start = 1 * gst.SECOND
-        self.focus.in_point = 3 * gst.SECOND
-        self.focus.duration = 20 * gst.SECOND
+        self.track_object1.start = 1 * gst.SECOND
+        self.track_object1.in_point = 3 * gst.SECOND
         self.track_object2.start = 1 * gst.SECOND
         self.track_object2.in_point = 10 * gst.SECOND
         self.track_object3.start = 15 * gst.SECOND
@@ -960,12 +1155,12 @@ class TestContexts(TestCase):
 
         # set up the initial state of the timeline and create the track object
         # [focus]     [t2   ]     [t3     ]
-        context = TrimStartContext(self.timeline, self.focus, self.other)
+        context = TrimStartContext(self.timeline, self.track_object1, self.other)
         context.editTo(gst.SECOND * 10, 0)
         context.finish()
 
-        self.failUnlessEqual(self.focus.start, 10 * gst.SECOND)
-        self.failUnlessEqual(self.focus.in_point, 12 * gst.SECOND)
+        self.failUnlessEqual(self.track_object1.start, 10 * gst.SECOND)
+        self.failUnlessEqual(self.track_object1.in_point, 12 * gst.SECOND)
         self.failUnlessEqual(self.track_object2.start, 1 * gst.SECOND)
         self.failUnlessEqual(self.track_object2.in_point, 10 * gst.SECOND)
         self.failUnlessEqual(self.track_object3.start, 15 * gst.SECOND)
@@ -973,9 +1168,9 @@ class TestContexts(TestCase):
 
 
     def testTrimEndContext(self):
-        self.focus.start = 1 * gst.SECOND
-        self.focus.in_point = 3 * gst.SECOND
-        self.focus.duration = 15 * gst.SECOND
+        self.track_object1.start = 1 * gst.SECOND
+        self.track_object1.in_point = 3 * gst.SECOND
+        self.track_object1.duration = 15 * gst.SECOND
         self.track_object2.start = 1 * gst.SECOND
         self.track_object2.in_point = 10 * gst.SECOND
         self.track_object2.duration = 16 * gst.SECOND
@@ -983,13 +1178,13 @@ class TestContexts(TestCase):
         self.track_object3.in_point = 19 * gst.SECOND
         self.track_object3.duration = 23 * gst.SECOND
 
-        context = TrimEndContext(self.timeline, self.focus, self.other)
+        context = TrimEndContext(self.timeline, self.track_object1, self.other)
         context.editTo(gst.SECOND * 10, 0)
         context.finish()
 
-        self.failUnlessEqual(self.focus.start, 1 * gst.SECOND)
-        self.failUnlessEqual(self.focus.in_point, 3 * gst.SECOND)
-        self.failUnlessEqual(self.focus.duration, 9 * gst.SECOND)
+        self.failUnlessEqual(self.track_object1.start, 1 * gst.SECOND)
+        self.failUnlessEqual(self.track_object1.in_point, 3 * gst.SECOND)
+        self.failUnlessEqual(self.track_object1.duration, 9 * gst.SECOND)
         self.failUnlessEqual(self.track_object2.start, 1 * gst.SECOND)
         self.failUnlessEqual(self.track_object2.in_point, 10 * gst.SECOND)
         self.failUnlessEqual(self.track_object2.duration, 16 * gst.SECOND)
@@ -998,13 +1193,31 @@ class TestContexts(TestCase):
         self.failUnlessEqual(self.track_object3.duration, 23 * gst.SECOND)
 
     def testEmptyOther(self):
-        context = MoveContext(self.timeline, self.focus, set())
+        context = MoveContext(self.timeline, self.track_object1, set())
         context.finish()
-        context = TrimStartContext(self.timeline, self.focus, set())
+        context = TrimStartContext(self.timeline, self.track_object1, set())
         context.finish()
-        context = TrimEndContext(self.timeline, self.focus, set())
+        context = TrimEndContext(self.timeline, self.track_object1, set())
         context.finish()
 
+    def testNothingToRipple(self):
+        self.track_object1.start = 20 * gst.SECOND
+        self.track_object1.duration = 5 * gst.SECOND
+        self.track_object2.start = 10 * gst.SECOND
+        self.track_object2.duration = 1 * gst.SECOND
+        self.track_object2.priority = 1
+        self.track_object3.start = 11 * gst.SECOND
+        self.track_object3.duration = 1 * gst.SECOND
+        self.track_object3.priority = 1
+
+        context = MoveContext(self.timeline, self.track_object1, set())
+        context.setMode(context.RIPPLE)
+        context.editTo(10 * gst.SECOND, 0)
+
+        self.failUnlessEqual(self.track_object1.start, 10 * gst.SECOND)
+        self.failUnlessEqual(self.track_object2.start, 10 * gst.SECOND)
+        self.failUnlessEqual(self.track_object3.start, 11 * gst.SECOND)
+
     def tearDown(self):
         del self.timeline_object1
         del self.timeline_object2
@@ -1017,6 +1230,5 @@ class TestContexts(TestCase):
         del self.factory
         del self.stream
         del self.timeline
-        del self.focus
         del self.other
         TestCase.tearDown(self)



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