[pitivi] undo: Fix undo ops on obsolete video transitions
- From: Alexandru Băluț <alexbalut src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [pitivi] undo: Fix undo ops on obsolete video transitions
- Date: Thu, 23 Jun 2016 06:55:03 +0000 (UTC)
commit 6f558f1bd7fa011128562d087c2822bd65cf1eeb
Author: Alexandru Băluț <alexandru balut gmail com>
Date: Mon Jun 20 00:14:51 2016 +0200
undo: Fix undo ops on obsolete video transitions
If the user changes a transition and then later removes the clip and
then even later starts undoing and gets back to the
PropertyChangedAction corresponding to the transition change, the
action was keeping the old transition clip object and working on it
instead of the replacement.
The new UndoableAutomaticObjectAction superclass of
PropertyChangedAction keeps track of the latest object and the mapping
from old to new objects. It's notified when a replacement is found in
the TransitionClipRemoved.undo method, for now. This allows
PropertyChangedAction to work on the latest object.
PropertyChangedAction is used also for other types of objects, not only
GES.VideoTransition, but the overhead is only a dictionarly lookup when
undoing or redoing.
Differential Revision: https://phabricator.freedesktop.org/D1096
pitivi/undo/timeline.py | 4 ++-
pitivi/undo/undo.py | 44 ++++++++++++++++++++++++++++++++++++++----
tests/test_undo_timeline.py | 31 +++++++++++++++++++++++------
3 files changed, 66 insertions(+), 13 deletions(-)
---
diff --git a/pitivi/undo/timeline.py b/pitivi/undo/timeline.py
index 4cdbf79..50a5c02 100644
--- a/pitivi/undo/timeline.py
+++ b/pitivi/undo/timeline.py
@@ -27,6 +27,7 @@ from pitivi.undo.undo import GObjectObserver
from pitivi.undo.undo import MetaContainerObserver
from pitivi.undo.undo import SimpleUndoableAction
from pitivi.undo.undo import UndoableAction
+from pitivi.undo.undo import UndoableAutomaticObjectAction
from pitivi.utils.loggable import Loggable
@@ -318,7 +319,7 @@ class TransitionClipRemovedAction(UndoableAction):
self.properties = []
for property_name in TRANSITION_PROPS:
field_name = property_name.replace("-", "_")
- value = track_element.get_property(field_name)
+ value = self.track_element.get_property(field_name)
self.properties.append((property_name, value))
@classmethod
@@ -352,6 +353,7 @@ class TransitionClipRemovedAction(UndoableAction):
# Probably the audio transition clip.
continue
# Double lucky!
+ UndoableAutomaticObjectAction.update_object(self.track_element, track_element)
for prop_name, value in self.properties:
track_element.set_property(prop_name, value)
break
diff --git a/pitivi/undo/undo.py b/pitivi/undo/undo.py
index 99b2810..5c3d30e 100644
--- a/pitivi/undo/undo.py
+++ b/pitivi/undo/undo.py
@@ -55,6 +55,41 @@ class UndoableAction(GObject.Object, Loggable):
raise NotImplementedError()
+class UndoableAutomaticObjectAction(UndoableAction):
+ """An action on an automatically created object.
+
+ Attributes:
+ auto_object (object): The object which has been automatically created
+ and might become obsolete later.
+ """
+
+ __updates = {}
+
+ def __init__(self, auto_object):
+ UndoableAction.__init__(self)
+ self.__auto_object = auto_object
+
+ @property
+ def auto_object(self):
+ """The latest object which identifies the same thing as the original."""
+ return self.__updates.get(self.__auto_object, self.__auto_object)
+
+ @classmethod
+ def update_object(cls, auto_object, new_auto_object):
+ """Provides a replacement for an object.
+
+ Args:
+ auto_object (object): The object being replaced.
+ new_auto_object (object): The replacement.
+ """
+ cls.__updates[auto_object] = new_auto_object
+ others = [key
+ for key, value in cls.__updates.items()
+ if value == auto_object]
+ for other in others:
+ cls.__updates[other] = new_auto_object
+
+
class ExpandableUndoableAction(GObject.Object, Loggable):
"""An action which can include immediately following actions."""
@@ -345,20 +380,19 @@ class MetaContainerObserver(GObject.Object):
self.meta_container = None
-class PropertyChangedAction(UndoableAction):
+class PropertyChangedAction(UndoableAutomaticObjectAction):
def __init__(self, gobject, field_name, old_value, new_value):
- UndoableAction.__init__(self)
- self.gobject = gobject
+ UndoableAutomaticObjectAction.__init__(self, gobject)
self.field_name = field_name
self.old_value = old_value
self.new_value = new_value
def do(self):
- self.gobject.set_property(self.field_name, self.new_value)
+ self.auto_object.set_property(self.field_name, self.new_value)
def undo(self):
- self.gobject.set_property(self.field_name, self.old_value)
+ self.auto_object.set_property(self.field_name, self.old_value)
class GObjectObserver(GObject.Object):
diff --git a/tests/test_undo_timeline.py b/tests/test_undo_timeline.py
index fad9218..efe180f 100644
--- a/tests/test_undo_timeline.py
+++ b/tests/test_undo_timeline.py
@@ -383,13 +383,30 @@ class TestLayerObserver(BaseTestUndoTimeline):
self.assertEqual(transition_element.get_transition_type(),
GES.VideoStandardTransitionType.BAR_WIPE_LR)
- # Remove the clip and add it back. This recreates the transition clip.
- with self.action_log.started("remove clip"):
- self.layer.remove_clip(clip2)
- self.action_log.undo()
- transition_element = get_transition_element(self.layer)
- self.assertEqual(transition_element.get_transition_type(),
- GES.VideoStandardTransitionType.BAR_WIPE_LR)
+ for unused_repeat in range(4):
+ # Remove the clip and add it back.
+ # This recreates the transition clip.
+ with self.action_log.started("remove clip"):
+ self.layer.remove_clip(clip2)
+ self.action_log.undo()
+ transition_element = get_transition_element(self.layer)
+ self.assertEqual(transition_element.get_transition_type(),
+ GES.VideoStandardTransitionType.BAR_WIPE_LR)
+
+ # Undo a transition change operation done on a now obsolete
+ # transition clip.
+ self.action_log.undo()
+ transition_element = get_transition_element(self.layer)
+ self.assertEqual(transition_element.get_transition_type(),
+ GES.VideoStandardTransitionType.CROSSFADE)
+
+ self.action_log.redo()
+ transition_element = get_transition_element(self.layer)
+ self.assertEqual(transition_element.get_transition_type(),
+ GES.VideoStandardTransitionType.BAR_WIPE_LR,
+ "The auto objects map in "
+ "UndoableAutomaticObjectAction is not updated when "
+ "undoing clip remove.")
class TestControlSourceObserver(BaseTestUndoTimeline):
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]