コード例 #1
0
    def __init__(self):
        """
        initialize pitivi with the command line arguments
        """
        Loggable.__init__(self)

        # init logging as early as possible so we can log startup code
        enable_color = os.environ.get('PITIVI_DEBUG_NO_COLOR',
                                      '0') in ('', '0')
        log.init('PITIVI_DEBUG', enable_color)

        self.info('starting up')

        # store ourself in the instance global
        if instance.PiTiVi:
            raise RuntimeWarning(
                _("There is already a %s instance, please inform the developers by filing a bug at http://bugzilla.gnome.org/enter_bug.cgi?product=pitivi"
                  ) % APPNAME)
        instance.PiTiVi = self

        self.projects = []
        self.current = None

        # get settings
        self.settings = GlobalSettings()
        self.threads = ThreadMaster()
        #self.screencast = False

        self.plugin_manager = PluginManager(
            self.settings.get_local_plugin_path(),
            self.settings.get_plugin_settings_path())
        self.effects = Magician()
        self.deviceprobe = get_probe()

        self.projectManager = ProjectManager()
        self._connectToProjectManager(self.projectManager)

        self.action_log = UndoableActionLog()
        self.debug_action_log_observer = DebugActionLogObserver()
        self.debug_action_log_observer.startObserving(self.action_log)
        self.timelineLogObserver = TimelineLogObserver(self.action_log)
        self.sourcelist_log_observer = SourceListLogObserver(self.action_log)
コード例 #2
0
 def setUp(self):
     self.stream = new_stream()
     self.factory = new_source_factory()
     self.effect_factory = TestEffectFactory(self.stream)
     self.track1 = Track(self.stream)
     self.track2 = Track(self.stream)
     self.timeline = Timeline()
     self.timeline.addTrack(self.track1)
     self.timeline.addTrack(self.track2)
     self.track_object1 = SourceTrackObject(self.factory, self.stream)
     self.track_object2 = SourceTrackObject(self.factory, self.stream)
     self.track_effect1 = TrackEffect(self.effect_factory, self.stream)
     self.track_effect2 = TrackEffect(self.effect_factory, self.stream)
     self.track1.addTrackObject(self.track_object1)
     self.track2.addTrackObject(self.track_object2)
     self.timeline_object1 = TimelineObject(self.factory)
     self.timeline_object1.addTrackObject(self.track_object1)
     self.timeline_object1.addTrackObject(self.track_object2)
     self.action_log = UndoableActionLog()
     self.observer = TestTimelineLogObserver(self.action_log)
     self.observer.startObserving(self.timeline)
コード例 #3
0
 def setUp(self):
     self.stream = new_stream()
     self.factory = new_factory()
     self.track1 = Track(self.stream)
     self.track2 = Track(self.stream)
     self.timeline = Timeline()
     self.timeline.addTrack(self.track1)
     self.timeline.addTrack(self.track2)
     self.track_object1 = SourceTrackObject(self.factory, self.stream)
     self.track_object2 = SourceTrackObject(self.factory, self.stream)
     self.track1.addTrackObject(self.track_object1)
     self.track2.addTrackObject(self.track_object2)
     self.timeline_object1 = TimelineObject(self.factory)
     self.timeline_object1.addTrackObject(self.track_object1)
     self.timeline_object1.addTrackObject(self.track_object2)
     self.action_log = UndoableActionLog()
     self.observer = TestTimelineLogObserver(self.action_log)
     self.observer.startObserving(self.timeline)
コード例 #4
0
ファイル: application.py プロジェクト: ironss/pitivi-tweaking
    def __init__(self):
        """
        initialize pitivi with the command line arguments
        """
        Loggable.__init__(self)

        # init logging as early as possible so we can log startup code
        enable_color = os.environ.get('PITIVI_DEBUG_NO_COLOR', '0') in ('', '0')
        log.init('PITIVI_DEBUG', enable_color)

        self.info('starting up')

        # store ourself in the instance global
        if instance.PiTiVi:
            raise RuntimeWarning(
                _("There is already a %s instance, please inform the developers by filing a bug at http://bugzilla.gnome.org/enter_bug.cgi?product=pitivi")
                % APPNAME)
        instance.PiTiVi = self

        self.projects = []
        self.current = None

        # get settings
        self.settings = GlobalSettings()
        self.threads = ThreadMaster()
        #self.screencast = False

        self.plugin_manager = PluginManager(
            self.settings.get_local_plugin_path(),
            self.settings.get_plugin_settings_path())
        self.effects = Magician()
        self.deviceprobe = get_probe()

        self.projectManager = ProjectManager()
        self._connectToProjectManager(self.projectManager)

        self.action_log = UndoableActionLog()
        self.debug_action_log_observer = DebugActionLogObserver()
        self.debug_action_log_observer.startObserving(self.action_log)
        self.timelineLogObserver = TimelineLogObserver(self.action_log)
        self.projectLogObserver = ProjectLogObserver(self.action_log)
        self.sourcelist_log_observer = SourceListLogObserver(self.action_log)
コード例 #5
0
ファイル: application.py プロジェクト: bemasc/pitivi
class Pitivi(Loggable, Signallable):
    """
    Pitivi's main application class.

    Signals:
     - C{new-project} : A new C{Project} is loaded and ready to use.

     - C{new-project-loading} : Pitivi is attempting to load a new project.
     - C{new-project-loaded} : A new L{Project} has been loaded, and the UI should refresh it's view.
     - C{new-project-failed} : A new L{Project} failed to load.
     - C{closing-project} :  pitivi would like to close a project. handlers should return false
     if they do not want this project to close. by default, assumes
     true. This signal should only be used by classes that might want to abort
     the closing of a project.
     - C{project-closed} : The project is closed, it will be freed when the callback returns.
     Classes should connect to this instance when they want to know that
     data related to that project is no longer going to be used.
     - C{shutdown} : Used internally, do not use this signal.`

    @ivar settings: Application-wide settings.
    @type settings: L{GlobalSettings}.
    @ivar projects: List of used projects
    @type projects: List of L{Project}.
    @ivar current: Currently used project.
    @type current: L{Project}.
    """

    __signals__ = {
        "new-project": ["project"],
        "new-project-loading": ["uri"],
        "new-project-created": ["project"],
        "new-project-loaded": ["project"],
        "new-project-failed": ["uri", "exception"],
        "closing-project": ["project"],
        "project-closed": ["project"],
        "missing-uri": ["formatter", "uri"],
        "shutdown": None}

    def __init__(self):
        """
        initialize pitivi with the command line arguments
        """
        Loggable.__init__(self)

        # init logging as early as possible so we can log startup code
        enable_color = os.environ.get('PITIVI_DEBUG_NO_COLOR', '0') in ('', '0')
        log.init('PITIVI_DEBUG', enable_color)

        self.info('starting up')

        # store ourself in the instance global
        if instance.PiTiVi:
            raise RuntimeWarning(
                _("There is already a %s instance, please inform the developers by filing a bug at http://bugzilla.gnome.org/enter_bug.cgi?product=pitivi")
                % APPNAME)
        instance.PiTiVi = self

        self.projects = []
        self.current = None

        # get settings
        self.settings = GlobalSettings()
        self.threads = ThreadMaster()
        #self.screencast = False

        self.plugin_manager = PluginManager(
            self.settings.get_local_plugin_path(),
            self.settings.get_plugin_settings_path())
        self.effects = EffectsHandler()

        self.projectManager = ProjectManager(self.effects)
        self._connectToProjectManager(self.projectManager)

        self.action_log = UndoableActionLog()
        self.debug_action_log_observer = DebugActionLogObserver()
        self.debug_action_log_observer.startObserving(self.action_log)
        self.timelineLogObserver = TimelineLogObserver(self.action_log)
        self.projectLogObserver = ProjectLogObserver(self.action_log)
        self.sourcelist_log_observer = SourceListLogObserver(self.action_log)

    def shutdown(self):
        """
        Close PiTiVi.

        @return: C{True} if PiTiVi was successfully closed, else C{False}.
        @rtype: C{bool}
        """
        self.debug("shutting down")
        # we refuse to close if we're running a user interface and the user
        # doesn't want us to close the current project.
        if self.current and not self.projectManager.closeRunningProject():
            self.warning("Not closing since running project doesn't want to close")
            return False
        self.threads.stopAllThreads()
        self.settings.storeSettings()
        self.current = None
        instance.PiTiVi = None
        self.emit("shutdown")
        return True

    def _connectToProjectManager(self, projectManager):
        projectManager.connect("new-project-loading",
                self._projectManagerNewProjectLoading)
        projectManager.connect("new-project-created",
                self._projectManagerNewProjectCreated)
        projectManager.connect("new-project-loaded",
                self._projectManagerNewProjectLoaded)
        projectManager.connect("new-project-failed",
                self._projectManagerNewProjectFailed)
        projectManager.connect("closing-project",
                self._projectManagerClosingProject)
        projectManager.connect("project-closed",
                self._projectManagerProjectClosed)

    def _projectManagerNewProjectLoading(self, projectManager, uri):
        self.emit("new-project-loading", uri)

    def _projectManagerNewProjectCreated(self, projectManager, project):
        self.current = project
        self.emit("new-project-created", project)

    def _newProjectLoaded(self, project):
        pass

    def _projectManagerNewProjectLoaded(self, projectManager, project):
        self.current = project
        self.action_log.clean()
        self.timelineLogObserver.startObserving(project.timeline)
        self.projectLogObserver.startObserving(project)
        self.sourcelist_log_observer.startObserving(project.sources)
        self._newProjectLoaded(project)
        self.emit("new-project-loaded", project)

    def _projectManagerNewProjectFailed(self, projectManager, uri, exception):
        self.emit("new-project-failed", uri, exception)

    def _projectManagerClosingProject(self, projectManager, project):
        return self.emit("closing-project", project)

    def _projectManagerProjectClosed(self, projectManager, project):
        self.timelineLogObserver.stopObserving(project.timeline)
        self.projectLogObserver.stopObserving(project)
        self.current = None
        self.emit("project-closed", project)
コード例 #6
0
ファイル: test_timeline_undo.py プロジェクト: kyotobay/pitivi
class  TestTimelineUndo(TestCase):
    def setUp(self):
        self.stream = new_stream()
        self.factory = new_source_factory()
        self.effect_factory = TestEffectFactory(self.stream)
        self.track1 = Track(self.stream)
        self.track2 = Track(self.stream)
        self.timeline = Timeline()
        self.timeline.addTrack(self.track1)
        self.timeline.addTrack(self.track2)
        self.track_object1 = SourceTrackObject(self.factory, self.stream)
        self.track_object2 = SourceTrackObject(self.factory, self.stream)
        self.track_effect1 = TrackEffect(self.effect_factory, self.stream)
        self.track_effect2 = TrackEffect(self.effect_factory, self.stream)
        self.track1.addTrackObject(self.track_object1)
        self.track2.addTrackObject(self.track_object2)
        self.timeline_object1 = TimelineObject(self.factory)
        self.timeline_object1.addTrackObject(self.track_object1)
        self.timeline_object1.addTrackObject(self.track_object2)
        self.action_log = UndoableActionLog()
        self.observer = TestTimelineLogObserver(self.action_log)
        self.observer.startObserving(self.timeline)

    def testAddTimelineObject(self):
        stacks = []

        def commitCb(action_log, stack, nested):
            stacks.append(stack)
        self.action_log.connect("commit", commitCb)

        self.action_log.begin("add clip")
        self.timeline.addTimelineObject(self.timeline_object1)
        self.action_log.commit()

        self.failUnlessEqual(len(stacks), 1)
        stack = stacks[0]
        self.failUnlessEqual(len(stack.done_actions), 1)
        action = stack.done_actions[0]
        self.failUnless(isinstance(action, TimelineObjectAdded))

        self.failUnless(self.timeline_object1 \
                in self.timeline.timeline_objects)
        self.action_log.undo()
        self.failIf(self.timeline_object1 \
                in self.timeline.timeline_objects)

        self.action_log.redo()
        self.failUnless(self.timeline_object1 \
                in self.timeline.timeline_objects)

    def testRemoveTimelineObject(self):
        stacks = []

        def commitCb(action_log, stack, nested):
            stacks.append(stack)
        self.action_log.connect("commit", commitCb)

        self.timeline.addTimelineObject(self.timeline_object1)
        self.action_log.begin("remove clip")
        self.timeline.removeTimelineObject(self.timeline_object1, deep=True)
        self.action_log.commit()

        self.failUnlessEqual(len(stacks), 1)
        stack = stacks[0]
        self.failUnlessEqual(len(stack.done_actions), 1)
        action = stack.done_actions[0]
        self.failUnless(isinstance(action, TimelineObjectRemoved))

        self.failIf(self.timeline_object1 \
                in self.timeline.timeline_objects)
        self.action_log.undo()
        self.failUnless(self.timeline_object1 \
                in self.timeline.timeline_objects)

        self.action_log.redo()
        self.failIf(self.timeline_object1 \
                in self.timeline.timeline_objects)

    def testAddEffectToTimelineObject(self):
        stacks = []
        pipeline = Pipeline()

        def commitCb(action_log, stack, nested):
            stacks.append(stack)
        self.action_log.connect("commit", commitCb)
        self.observer.pipeline = pipeline

        #FIXME Should I commit it and check there are 2 elements
        #in the stacks
        self.timeline.addTimelineObject(self.timeline_object1)
        self.track1.addTrackObject(self.track_effect1)

        self.action_log.begin("add effect")
        self.timeline_object1.addTrackObject(self.track_effect1)
        self.action_log.commit()

        self.failUnlessEqual(len(stacks), 1)
        stack = stacks[0]
        self.failUnlessEqual(len(stack.done_actions), 1)
        action = stack.done_actions[0]
        self.failUnless(isinstance(action, TrackEffectAdded))

        self.failUnless(self.track_effect1 \
                in self.timeline_object1.track_objects)
        self.failUnless(self.track_effect1 \
                in self.track1.track_objects)
        self.failUnless(len([effect for effect in \
                                self.timeline_object1.track_objects
                                if isinstance(effect, TrackEffect)]) == 1)
        self.failUnless(len([effect for effect in self.track1.track_objects
                             if isinstance(effect, TrackEffect)]) == 1)

        self.action_log.undo()
        self.failIf(self.track_effect1 \
                in self.timeline_object1.track_objects)
        self.failIf(self.track_effect1 \
                in self.track1.track_objects)

        self.action_log.redo()
        self.failUnless(len([effect for effect in
                                self.timeline_object1.track_objects
                                if isinstance(effect, TrackEffect)]) == 1)
        self.failUnless(len([effect for effect in self.track1.track_objects
                             if isinstance(effect, TrackEffect)]) == 1)

        self.timeline.removeTimelineObject(self.timeline_object1, deep=True)

    def testTimelineObjectPropertyChange(self):
        stacks = []

        def commitCb(action_log, stack, nested):
            stacks.append(stack)
        self.action_log.connect("commit", commitCb)

        self.timeline_object1.start = 5 * gst.SECOND
        self.timeline_object1.duration = 20 * gst.SECOND
        self.timeline.addTimelineObject(self.timeline_object1)
        self.action_log.begin("modify clip")
        self.timeline_object1.start = 10 * gst.SECOND
        self.action_log.commit()

        self.failUnlessEqual(len(stacks), 1)
        stack = stacks[0]
        self.failUnlessEqual(len(stack.done_actions), 1)
        action = stack.done_actions[0]
        self.failUnless(isinstance(action, TimelineObjectPropertyChanged))

        self.failUnlessEqual(self.timeline_object1.start, 10 * gst.SECOND)
        self.action_log.undo()
        self.failUnlessEqual(self.timeline_object1.start, 5 * gst.SECOND)
        self.action_log.redo()
        self.failUnlessEqual(self.timeline_object1.start, 10 * gst.SECOND)

        self.timeline_object1.priority = 10
        self.action_log.begin("priority change")
        self.timeline_object1.priority = 20
        self.action_log.commit()

        self.failUnlessEqual(self.timeline_object1.priority, 20)
        self.action_log.undo()
        self.failUnlessEqual(self.timeline_object1.priority, 10)
        self.action_log.redo()
        self.failUnlessEqual(self.timeline_object1.priority, 20)

    def testUngroup(self):
        self.timeline_object1.start = 5 * gst.SECOND
        self.timeline_object1.duration = 20 * gst.SECOND

        self.timeline.addTimelineObject(self.timeline_object1)
        self.timeline.setSelectionToObj(self.track_object1, SELECT_ADD)

        self.failUnlessEqual(len(self.timeline.timeline_objects), 1)
        self.failUnlessEqual(self.timeline.timeline_objects[0].start,
                5 * gst.SECOND)
        self.failUnlessEqual(self.timeline.timeline_objects[0].duration,
                20 * gst.SECOND)

        self.action_log.begin("ungroup")
        self.timeline.ungroupSelection()
        self.action_log.commit()

        self.failUnlessEqual(len(self.timeline.timeline_objects), 2)
        self.failUnlessEqual(self.timeline.timeline_objects[0].start,
                5 * gst.SECOND)
        self.failUnlessEqual(self.timeline.timeline_objects[0].duration,
                20 * gst.SECOND)
        self.failUnlessEqual(self.timeline.timeline_objects[1].start,
                5 * gst.SECOND)
        self.failUnlessEqual(self.timeline.timeline_objects[1].duration,
                20 * gst.SECOND)

        self.action_log.undo()

        self.failUnlessEqual(len(self.timeline.timeline_objects), 1)
        self.failUnlessEqual(self.timeline.timeline_objects[0].start,
                5 * gst.SECOND)
        self.failUnlessEqual(self.timeline.timeline_objects[0].duration,
                20 * gst.SECOND)
コード例 #7
0
class Pitivi(Loggable, Signallable):
    """
    Pitivi's main application class.

    Signals:
     - C{new-project} : A new C{Project} is loaded and ready to use.

     - C{new-project-loading} : Pitivi is attempting to load a new project.
     - C{new-project-loaded} : A new L{Project} has been loaded, and the UI should refresh it's view.
     - C{new-project-failed} : A new L{Project} failed to load.
     - C{closing-project} :  pitivi would like to close a project. handlers should return false
     if they do not want this project to close. by default, assumes
     true. This signal should only be used by classes that might want to abort
     the closing of a project.
     - C{project-closed} : The project is closed, it will be freed when the callback returns.
     Classes should connect to this instance when they want to know that
     data related to that project is no longer going to be used.
     - C{shutdown} : Used internally, do not use this signal.`

    @ivar settings: Application-wide settings.
    @type settings: L{GlobalSettings}.
    @ivar projects: List of used projects
    @type projects: List of L{Project}.
    @ivar current: Currently used project.
    @type current: L{Project}.
    """

    __signals__ = {
        "new-project": ["project"],
        "new-project-loading": ["uri"],
        "new-project-created": ["project"],
        "new-project-loaded": ["project"],
        "new-project-failed": ["uri", "exception"],
        "closing-project": ["project"],
        "project-closed": ["project"],
        "missing-uri": ["formatter", "uri"],
        "shutdown": None
    }

    def __init__(self):
        """
        initialize pitivi with the command line arguments
        """
        Loggable.__init__(self)

        # init logging as early as possible so we can log startup code
        enable_color = os.environ.get('PITIVI_DEBUG_NO_COLOR',
                                      '0') in ('', '0')
        log.init('PITIVI_DEBUG', enable_color)

        self.info('starting up')

        # store ourself in the instance global
        if instance.PiTiVi:
            raise RuntimeWarning(
                _("There is already a %s instance, please inform the developers by filing a bug at http://bugzilla.gnome.org/enter_bug.cgi?product=pitivi"
                  ) % APPNAME)
        instance.PiTiVi = self

        self.projects = []
        self.current = None

        # get settings
        self.settings = GlobalSettings()
        self.threads = ThreadMaster()
        #self.screencast = False

        self.plugin_manager = PluginManager(
            self.settings.get_local_plugin_path(),
            self.settings.get_plugin_settings_path())
        self.effects = Magician()
        self.deviceprobe = get_probe()

        self.projectManager = ProjectManager()
        self._connectToProjectManager(self.projectManager)

        self.action_log = UndoableActionLog()
        self.debug_action_log_observer = DebugActionLogObserver()
        self.debug_action_log_observer.startObserving(self.action_log)
        self.timelineLogObserver = TimelineLogObserver(self.action_log)
        self.sourcelist_log_observer = SourceListLogObserver(self.action_log)

    #{ Shutdown methods

    def shutdown(self):
        """
        Close PiTiVi.

        @return: C{True} if PiTiVi was successfully closed, else C{False}.
        @rtype: C{bool}
        """
        self.debug("shutting down")
        # we refuse to close if we're running a user interface and the user
        # doesn't want us to close the current project.
        if self.projectManager.current and not self.projectManager.closeRunningProject(
        ):
            self.warning(
                "Not closing since running project doesn't want to close")
            return False
        self.threads.stopAllThreads()
        self.settings.storeSettings()
        self.deviceprobe.release()
        self.deviceprobe = None
        self.current = None
        instance.PiTiVi = None
        self.emit("shutdown")
        return True

    #}

    def _connectToProjectManager(self, projectManager):
        projectManager.connect("new-project-loading",
                               self._projectManagerNewProjectLoading)
        projectManager.connect("new-project-created",
                               self._projectManagerNewProjectCreated)
        projectManager.connect("new-project-loaded",
                               self._projectManagerNewProjectLoaded)
        projectManager.connect("new-project-failed",
                               self._projectManagerNewProjectFailed)
        projectManager.connect("closing-project",
                               self._projectManagerClosingProject)
        projectManager.connect("project-closed",
                               self._projectManagerProjectClosed)

    def _projectManagerNewProjectLoading(self, projectManager, uri):
        self.emit("new-project-loading", uri)

    def _projectManagerNewProjectCreated(self, projectManager, project):
        self.current = project
        self.emit("new-project-created", project)

    def _projectManagerNewProjectLoaded(self, projectManager, project):
        self.current = project
        self.action_log.clean()
        self.timelineLogObserver.startObserving(project.timeline)
        self.sourcelist_log_observer.startObserving(project.sources)
        self.emit("new-project-loaded", project)

    def _projectManagerNewProjectFailed(self, projectManager, uri, exception):
        self.emit("new-project-failed", uri, exception)

    def _projectManagerClosingProject(self, projectManager, project):
        return self.emit("closing-project", project)

    def _projectManagerProjectClosed(self, projectManager, project):
        self.timelineLogObserver.stopObserving(project.timeline)
        self.current = None
        self.emit("project-closed", project)
コード例 #8
0
 def setUp(self):
     self.log = UndoableActionLog()
     self._connectToUndoableActionLog(self.log)
     self.signals = []
コード例 #9
0
class TestUndoableActionLog(TestCase):
    def setUp(self):
        self.log = UndoableActionLog()
        self._connectToUndoableActionLog(self.log)
        self.signals = []

    def tearDown(self):
        self._disconnectFromUndoableActionLog(self.log)

    def _undoActionLogSignalCb(self, log, *args):
        args = list(args)
        signalName = args.pop(-1)
        self.signals.append((signalName, args))

    def _connectToUndoableActionLog(self, log):
        for signalName in ("begin", "push", "rollback", "commit", "undo",
                           "redo"):
            log.connect(signalName, self._undoActionLogSignalCb, signalName)

    def _disconnectFromUndoableActionLog(self, log):
        self.log.disconnect_by_func(self._undoActionLogSignalCb)

    def testRollbackWrongState(self):
        self.failUnlessRaises(UndoWrongStateError, self.log.rollback)

    def testCommitWrongState(self):
        self.failUnlessRaises(UndoWrongStateError, self.log.commit)

    def testPushWrongState(self):
        # no error in this case
        self.log.push(None)

    def testUndoWrongState(self):
        self.failUnlessRaises(UndoWrongStateError, self.log.undo)

    def testRedoWrongState(self):
        self.failUnlessRaises(UndoWrongStateError, self.log.redo)

    def testCheckpoint(self):
        self.log.begin("meh")
        self.log.push(DummyUndoableAction())
        self.failUnlessRaises(UndoWrongStateError, self.log.checkpoint)
        self.log.rollback()
        self.log.checkpoint()
        self.failIfEqual(self.log._checkpoint, None)

    def testDirty(self):
        self.failIf(self.log.dirty())
        self.log.begin("meh")
        self.log.push(DummyUndoableAction())
        self.log.commit()
        self.failUnless(self.log.dirty())
        self.log.checkpoint()
        self.failIf(self.log.dirty())
        self.log.undo()
        self.failUnless(self.log.dirty())
        self.log.redo()
        self.failIf(self.log.dirty())

    def testCommit(self):
        """
        Commit a stack.
        """
        self.failUnlessEqual(len(self.log.undo_stacks), 0)
        self.failUnlessEqual(len(self.log.redo_stacks), 0)
        self.log.begin("meh")
        self.failUnlessEqual(len(self.signals), 1)
        name, (stack, nested) = self.signals[0]
        self.failUnlessEqual(name, "begin")
        self.failIf(nested)

        self.failUnlessEqual(self.log.undo_stacks, [])
        self.log.commit()
        self.failUnlessEqual(len(self.signals), 2)
        name, (stack, nested) = self.signals[1]
        self.failUnlessEqual(name, "commit")
        self.failIf(nested)
        self.failUnlessEqual(len(self.log.undo_stacks), 1)
        self.failUnlessEqual(len(self.log.redo_stacks), 0)

    def testNestedCommit(self):
        """
        Do two nested commits.
        """
        self.failUnlessEqual(len(self.log.undo_stacks), 0)
        self.failUnlessEqual(len(self.log.redo_stacks), 0)
        self.log.begin("meh")
        self.failUnlessEqual(len(self.signals), 1)
        name, (stack, nested) = self.signals[0]
        self.failUnlessEqual(name, "begin")
        self.failIf(nested)

        self.failUnlessEqual(len(self.log.undo_stacks), 0)
        self.failUnlessEqual(len(self.log.redo_stacks), 0)
        self.log.begin("nested")
        self.failUnlessEqual(len(self.signals), 2)
        name, (stack, nested) = self.signals[1]
        self.failUnlessEqual(name, "begin")
        self.failUnless(nested)

        self.failUnlessEqual(self.log.undo_stacks, [])
        self.log.commit()
        self.failUnlessEqual(len(self.signals), 3)
        name, (stack, nested) = self.signals[2]
        self.failUnlessEqual(name, "commit")
        self.failUnless(nested)
        self.failUnlessEqual(len(self.log.undo_stacks), 0)
        self.failUnlessEqual(len(self.log.redo_stacks), 0)

        self.failUnlessEqual(self.log.undo_stacks, [])
        self.log.commit()
        self.failUnlessEqual(len(self.signals), 4)
        name, (stack, nested) = self.signals[3]
        self.failUnlessEqual(name, "commit")
        self.failIf(nested)
        self.failUnlessEqual(len(self.log.undo_stacks), 1)
        self.failUnlessEqual(len(self.log.redo_stacks), 0)

    def testRollback(self):
        """
        Test a rollback.
        """
        self.failUnlessEqual(len(self.log.undo_stacks), 0)
        self.failUnlessEqual(len(self.log.redo_stacks), 0)
        self.log.begin("meh")
        self.failUnlessEqual(len(self.signals), 1)
        name, (stack, nested) = self.signals[0]
        self.failUnlessEqual(name, "begin")
        self.failIf(nested)

        self.log.rollback()
        self.failUnlessEqual(len(self.signals), 2)
        name, (stack, nested) = self.signals[1]
        self.failUnlessEqual(name, "rollback")
        self.failIf(nested)
        self.failUnlessEqual(len(self.log.undo_stacks), 0)
        self.failUnlessEqual(len(self.log.redo_stacks), 0)

    def testNestedRollback(self):
        """
        Test two nested rollbacks.
        """
        self.failUnlessEqual(len(self.log.undo_stacks), 0)
        self.failUnlessEqual(len(self.log.redo_stacks), 0)
        self.log.begin("meh")
        self.failUnlessEqual(len(self.signals), 1)
        name, (stack, nested) = self.signals[0]
        self.failUnlessEqual(name, "begin")
        self.failIf(nested)

        self.failUnlessEqual(len(self.log.undo_stacks), 0)
        self.failUnlessEqual(len(self.log.redo_stacks), 0)
        self.log.begin("nested")
        self.failUnlessEqual(len(self.signals), 2)
        name, (stack, nested) = self.signals[1]
        self.failUnlessEqual(name, "begin")
        self.failUnless(nested)

        self.log.rollback()
        self.failUnlessEqual(len(self.signals), 3)
        name, (stack, nested) = self.signals[2]
        self.failUnlessEqual(name, "rollback")
        self.failUnless(nested)
        self.failUnlessEqual(len(self.log.undo_stacks), 0)
        self.failUnlessEqual(len(self.log.redo_stacks), 0)

        self.log.rollback()
        self.failUnlessEqual(len(self.signals), 4)
        name, (stack, nested) = self.signals[3]
        self.failUnlessEqual(name, "rollback")
        self.failIf(nested)
        self.failUnlessEqual(len(self.log.undo_stacks), 0)
        self.failUnlessEqual(len(self.log.redo_stacks), 0)

    def testUndoRedo(self):
        """
        Try an undo() redo() sequence.
        """
        # begin
        self.log.begin("meh")
        self.failUnlessEqual(len(self.signals), 1)
        name, (stack, nested) = self.signals[0]
        self.failUnlessEqual(name, "begin")
        self.failIf(nested)

        # push two actions
        action1 = DummyUndoableAction()
        self.log.push(action1)
        self.failUnlessEqual(len(self.signals), 2)
        name, (stack, signalAction) = self.signals[1]
        self.failUnlessEqual(name, "push")
        self.failUnless(action1 is signalAction)

        action2 = DummyUndoableAction()
        self.log.push(action2)
        self.failUnlessEqual(len(self.signals), 3)
        name, (stack, signalAction) = self.signals[2]
        self.failUnlessEqual(name, "push")
        self.failUnless(action2 is signalAction)

        # commit
        self.failUnlessEqual(len(self.log.undo_stacks), 0)
        self.failUnlessEqual(len(self.log.redo_stacks), 0)
        self.log.commit()
        self.failUnlessEqual(len(self.signals), 4)
        name, (stack, nested) = self.signals[3]
        self.failUnlessEqual(name, "commit")
        self.failIf(nested)
        self.failUnlessEqual(len(self.log.undo_stacks), 1)
        self.failUnlessEqual(len(self.log.redo_stacks), 0)

        self.failUnless(action1.done_)
        self.failUnless(action2.done_)

        # undo what we just committed
        self.log.undo()
        self.failUnlessEqual(len(self.signals), 5)
        name, stack = self.signals[4]
        self.failUnlessEqual(name, "undo")
        self.failUnlessEqual(len(self.log.undo_stacks), 0)
        self.failUnlessEqual(len(self.log.redo_stacks), 1)

        self.failIf(action1.done_)
        self.failIf(action2.done_)

        # redo
        self.log.redo()
        self.failUnlessEqual(len(self.signals), 6)
        name, stack = self.signals[5]
        self.failUnlessEqual(name, "redo")
        self.failUnlessEqual(len(self.log.undo_stacks), 1)
        self.failUnlessEqual(len(self.log.redo_stacks), 0)

        self.failUnless(action1.done_)
        self.failUnless(action2.done_)

    def testOrder(self):
        """
        Test that actions are undone and redone in the correct order.
        """
        call_sequence = []

        class Action(UndoableAction):
            def __init__(self, n):
                self.n = n

            def do(self):
                call_sequence.append("do%s" % self.n)
                self._done()

            def undo(self):
                call_sequence.append("undo%s" % self.n)
                self._undone()

        action1 = Action(1)
        action2 = Action(2)
        action3 = Action(3)

        self.log.begin("meh")
        self.log.push(action1)
        self.log.begin("nested")
        self.log.push(action2)
        self.log.commit()
        self.log.push(action3)
        self.log.commit()

        self.log.undo()
        self.failUnlessEqual(call_sequence, ["undo3", "undo2", "undo1"])

        call_sequence[:] = []
        self.log.redo()
        self.failUnlessEqual(call_sequence, ["do1", "do2", "do3"])

        call_sequence[:] = []
        self.log.undo()
        self.failUnlessEqual(call_sequence, ["undo3", "undo2", "undo1"])
コード例 #10
0
class  TestTimelineUndo(TestCase):
    def setUp(self):
        self.stream = new_stream()
        self.factory = new_source_factory()
        self.effect_factory = TestEffectFactory(self.stream)
        self.track1 = Track(self.stream)
        self.track2 = Track(self.stream)
        self.timeline = Timeline()
        self.timeline.addTrack(self.track1)
        self.timeline.addTrack(self.track2)
        self.track_object1 = SourceTrackObject(self.factory, self.stream)
        self.track_object2 = SourceTrackObject(self.factory, self.stream)
        self.track_effect1 = TrackEffect(self.effect_factory, self.stream)
        self.track_effect2 = TrackEffect(self.effect_factory, self.stream)
        self.track1.addTrackObject(self.track_object1)
        self.track2.addTrackObject(self.track_object2)
        self.timeline_object1 = TimelineObject(self.factory)
        self.timeline_object1.addTrackObject(self.track_object1)
        self.timeline_object1.addTrackObject(self.track_object2)
        self.action_log = UndoableActionLog()
        self.observer = TestTimelineLogObserver(self.action_log)
        self.observer.startObserving(self.timeline)

    def testAddTimelineObject(self):
        stacks = []
        def commitCb(action_log, stack, nested):
            stacks.append(stack)
        self.action_log.connect("commit", commitCb)

        self.action_log.begin("add clip")
        self.timeline.addTimelineObject(self.timeline_object1)
        self.action_log.commit()

        self.failUnlessEqual(len(stacks), 1)
        stack = stacks[0]
        self.failUnlessEqual(len(stack.done_actions), 1)
        action = stack.done_actions[0]
        self.failUnless(isinstance(action, TimelineObjectAdded))

        self.failUnless(self.timeline_object1 \
                in self.timeline.timeline_objects)
        self.action_log.undo()
        self.failIf(self.timeline_object1 \
                in self.timeline.timeline_objects)

        self.action_log.redo()
        self.failUnless(self.timeline_object1 \
                in self.timeline.timeline_objects)

    def testRemoveTimelineObject(self):
        stacks = []
        def commitCb(action_log, stack, nested):
            stacks.append(stack)
        self.action_log.connect("commit", commitCb)

        self.timeline.addTimelineObject(self.timeline_object1)
        self.action_log.begin("remove clip")
        self.timeline.removeTimelineObject(self.timeline_object1, deep=True)
        self.action_log.commit()

        self.failUnlessEqual(len(stacks), 1)
        stack = stacks[0]
        self.failUnlessEqual(len(stack.done_actions), 1)
        action = stack.done_actions[0]
        self.failUnless(isinstance(action, TimelineObjectRemoved))

        self.failIf(self.timeline_object1 \
                in self.timeline.timeline_objects)
        self.action_log.undo()
        self.failUnless(self.timeline_object1 \
                in self.timeline.timeline_objects)

        self.action_log.redo()
        self.failIf(self.timeline_object1 \
                in self.timeline.timeline_objects)

    def testAddEffectToTimelineObject(self):
        stacks = []
        pipeline = Pipeline()
        def commitCb(action_log, stack, nested):
            stacks.append(stack)
        self.action_log.connect("commit", commitCb)
        self.observer.pipeline = pipeline

        #FIXME Should I commit it and check there are 2 elements
        #in the stacks
        self.timeline.addTimelineObject(self.timeline_object1)
        self.track1.addTrackObject(self.track_effect1)

        self.action_log.begin("add effect")
        self.timeline_object1.addTrackObject(self.track_effect1)
        self.action_log.commit()

        self.failUnlessEqual(len(stacks), 1)
        stack = stacks[0]
        self.failUnlessEqual(len(stack.done_actions), 1)
        action = stack.done_actions[0]
        self.failUnless(isinstance(action, TrackEffectAdded))

        self.failUnless(self.track_effect1 \
                in self.timeline_object1.track_objects)
        self.failUnless(self.track_effect1 \
                in self.track1.track_objects)
        self.failUnless(len([effect for effect in \
                                self.timeline_object1.track_objects
                                if isinstance(effect, TrackEffect)]) == 1)
        self.failUnless(len([effect for effect in self.track1.track_objects
                             if isinstance(effect, TrackEffect)]) == 1)

        self.action_log.undo()
        self.failIf(self.track_effect1 \
                in self.timeline_object1.track_objects)
        self.failIf(self.track_effect1 \
                in self.track1.track_objects)

        self.action_log.redo()
        self.failUnless(len([effect for effect in
                                self.timeline_object1.track_objects
                                if isinstance(effect, TrackEffect)]) == 1)
        self.failUnless(len([effect for effect in self.track1.track_objects
                             if isinstance(effect, TrackEffect)]) == 1)

        self.timeline.removeTimelineObject(self.timeline_object1, deep=True)

    def testTimelineObjectPropertyChange(self):
        stacks = []
        def commitCb(action_log, stack, nested):
            stacks.append(stack)
        self.action_log.connect("commit", commitCb)

        self.timeline_object1.start = 5 * gst.SECOND
        self.timeline_object1.duration = 20 * gst.SECOND
        self.timeline.addTimelineObject(self.timeline_object1)
        self.action_log.begin("modify clip")
        self.timeline_object1.start = 10 * gst.SECOND
        self.action_log.commit()

        self.failUnlessEqual(len(stacks), 1)
        stack = stacks[0]
        self.failUnlessEqual(len(stack.done_actions), 1)
        action = stack.done_actions[0]
        self.failUnless(isinstance(action, TimelineObjectPropertyChanged))

        self.failUnlessEqual(self.timeline_object1.start, 10 * gst.SECOND)
        self.action_log.undo()
        self.failUnlessEqual(self.timeline_object1.start, 5 * gst.SECOND)
        self.action_log.redo()
        self.failUnlessEqual(self.timeline_object1.start, 10 * gst.SECOND)

        self.timeline_object1.priority = 10
        self.action_log.begin("priority change")
        self.timeline_object1.priority = 20
        self.action_log.commit()

        self.failUnlessEqual(self.timeline_object1.priority, 20)
        self.action_log.undo()
        self.failUnlessEqual(self.timeline_object1.priority, 10)
        self.action_log.redo()
        self.failUnlessEqual(self.timeline_object1.priority, 20)

    def testUngroup(self):
        self.timeline_object1.start = 5 * gst.SECOND
        self.timeline_object1.duration = 20 * gst.SECOND

        self.timeline.addTimelineObject(self.timeline_object1)
        self.timeline.setSelectionToObj(self.track_object1, SELECT_ADD)

        self.failUnlessEqual(len(self.timeline.timeline_objects), 1)
        self.failUnlessEqual(self.timeline.timeline_objects[0].start,
                5 * gst.SECOND)
        self.failUnlessEqual(self.timeline.timeline_objects[0].duration,
                20 * gst.SECOND)

        self.action_log.begin("ungroup")
        self.timeline.ungroupSelection()
        self.action_log.commit()

        self.failUnlessEqual(len(self.timeline.timeline_objects), 2)
        self.failUnlessEqual(self.timeline.timeline_objects[0].start,
                5 * gst.SECOND)
        self.failUnlessEqual(self.timeline.timeline_objects[0].duration,
                20 * gst.SECOND)
        self.failUnlessEqual(self.timeline.timeline_objects[1].start,
                5 * gst.SECOND)
        self.failUnlessEqual(self.timeline.timeline_objects[1].duration,
                20 * gst.SECOND)

        self.action_log.undo()

        self.failUnlessEqual(len(self.timeline.timeline_objects), 1)
        self.failUnlessEqual(self.timeline.timeline_objects[0].start,
                5 * gst.SECOND)
        self.failUnlessEqual(self.timeline.timeline_objects[0].duration,
                20 * gst.SECOND)
コード例 #11
0
 def setUp(self):
     self.action_log = UndoableActionLog()
     self.observer = TestTimelineLogObserver(self.action_log)
コード例 #12
0
ファイル: test_undo.py プロジェクト: dparker18/Pitivi
 def setUp(self):
     self.log = UndoableActionLog()
     self._connectToUndoableActionLog(self.log)
     self.signals = []
コード例 #13
0
ファイル: test_undo.py プロジェクト: dparker18/Pitivi
class TestUndoableActionLog(TestCase):
    def setUp(self):
        self.log = UndoableActionLog()
        self._connectToUndoableActionLog(self.log)
        self.signals = []

    def tearDown(self):
        self._disconnectFromUndoableActionLog(self.log)

    def _undoActionLogSignalCb(self, log, *args):
        args = list(args)
        signalName = args.pop(-1)
        self.signals.append((signalName, args))

    def _connectToUndoableActionLog(self, log):
        for signalName in ("begin", "push", "rollback", "commit",
                    "undo", "redo"):
            log.connect(signalName, self._undoActionLogSignalCb, signalName)

    def _disconnectFromUndoableActionLog(self, log):
        self.log.disconnect_by_func(self._undoActionLogSignalCb)

    def testRollbackWrongState(self):
        self.failUnlessRaises(UndoWrongStateError, self.log.rollback)

    def testCommitWrongState(self):
        self.failUnlessRaises(UndoWrongStateError, self.log.commit)

    def testPushWrongState(self):
        # no error in this case
        self.log.push(None)

    def testUndoWrongState(self):
        self.failUnlessRaises(UndoWrongStateError, self.log.undo)

    def testRedoWrongState(self):
        self.failUnlessRaises(UndoWrongStateError, self.log.redo)

    def testCheckpoint(self):
        self.log.begin("meh")
        self.log.push(DummyUndoableAction())
        self.failUnlessRaises(UndoWrongStateError, self.log.checkpoint)
        self.log.rollback()
        self.log.checkpoint()
        self.failIfEqual(self.log._checkpoint, None)

    def testDirty(self):
        self.failIf(self.log.dirty())
        self.log.begin("meh")
        self.log.push(DummyUndoableAction())
        self.log.commit()
        self.failUnless(self.log.dirty())
        self.log.checkpoint()
        self.failIf(self.log.dirty())
        self.log.undo()
        self.failUnless(self.log.dirty())
        self.log.redo()
        self.failIf(self.log.dirty())

    def testCommit(self):
        """
        Commit a stack.
        """
        self.failUnlessEqual(len(self.log.undo_stacks), 0)
        self.failUnlessEqual(len(self.log.redo_stacks), 0)
        self.log.begin("meh")
        self.failUnlessEqual(len(self.signals), 1)
        name, (stack, nested) = self.signals[0]
        self.failUnlessEqual(name, "begin")
        self.failIf(nested)

        self.failUnlessEqual(self.log.undo_stacks, [])
        self.log.commit()
        self.failUnlessEqual(len(self.signals), 2)
        name, (stack, nested) = self.signals[1]
        self.failUnlessEqual(name, "commit")
        self.failIf(nested)
        self.failUnlessEqual(len(self.log.undo_stacks), 1)
        self.failUnlessEqual(len(self.log.redo_stacks), 0)

    def testNestedCommit(self):
        """
        Do two nested commits.
        """
        self.failUnlessEqual(len(self.log.undo_stacks), 0)
        self.failUnlessEqual(len(self.log.redo_stacks), 0)
        self.log.begin("meh")
        self.failUnlessEqual(len(self.signals), 1)
        name, (stack, nested) = self.signals[0]
        self.failUnlessEqual(name, "begin")
        self.failIf(nested)

        self.failUnlessEqual(len(self.log.undo_stacks), 0)
        self.failUnlessEqual(len(self.log.redo_stacks), 0)
        self.log.begin("nested")
        self.failUnlessEqual(len(self.signals), 2)
        name, (stack, nested) = self.signals[1]
        self.failUnlessEqual(name, "begin")
        self.failUnless(nested)

        self.failUnlessEqual(self.log.undo_stacks, [])
        self.log.commit()
        self.failUnlessEqual(len(self.signals), 3)
        name, (stack, nested) = self.signals[2]
        self.failUnlessEqual(name, "commit")
        self.failUnless(nested)
        self.failUnlessEqual(len(self.log.undo_stacks), 0)
        self.failUnlessEqual(len(self.log.redo_stacks), 0)

        self.failUnlessEqual(self.log.undo_stacks, [])
        self.log.commit()
        self.failUnlessEqual(len(self.signals), 4)
        name, (stack, nested) = self.signals[3]
        self.failUnlessEqual(name, "commit")
        self.failIf(nested)
        self.failUnlessEqual(len(self.log.undo_stacks), 1)
        self.failUnlessEqual(len(self.log.redo_stacks), 0)

    def testRollback(self):
        """
        Test a rollback.
        """
        self.failUnlessEqual(len(self.log.undo_stacks), 0)
        self.failUnlessEqual(len(self.log.redo_stacks), 0)
        self.log.begin("meh")
        self.failUnlessEqual(len(self.signals), 1)
        name, (stack, nested) = self.signals[0]
        self.failUnlessEqual(name, "begin")
        self.failIf(nested)

        self.log.rollback()
        self.failUnlessEqual(len(self.signals), 2)
        name, (stack, nested) = self.signals[1]
        self.failUnlessEqual(name, "rollback")
        self.failIf(nested)
        self.failUnlessEqual(len(self.log.undo_stacks), 0)
        self.failUnlessEqual(len(self.log.redo_stacks), 0)

    def testNestedRollback(self):
        """
        Test two nested rollbacks.
        """
        self.failUnlessEqual(len(self.log.undo_stacks), 0)
        self.failUnlessEqual(len(self.log.redo_stacks), 0)
        self.log.begin("meh")
        self.failUnlessEqual(len(self.signals), 1)
        name, (stack, nested) = self.signals[0]
        self.failUnlessEqual(name, "begin")
        self.failIf(nested)

        self.failUnlessEqual(len(self.log.undo_stacks), 0)
        self.failUnlessEqual(len(self.log.redo_stacks), 0)
        self.log.begin("nested")
        self.failUnlessEqual(len(self.signals), 2)
        name, (stack, nested) = self.signals[1]
        self.failUnlessEqual(name, "begin")
        self.failUnless(nested)

        self.log.rollback()
        self.failUnlessEqual(len(self.signals), 3)
        name, (stack, nested) = self.signals[2]
        self.failUnlessEqual(name, "rollback")
        self.failUnless(nested)
        self.failUnlessEqual(len(self.log.undo_stacks), 0)
        self.failUnlessEqual(len(self.log.redo_stacks), 0)

        self.log.rollback()
        self.failUnlessEqual(len(self.signals), 4)
        name, (stack, nested) = self.signals[3]
        self.failUnlessEqual(name, "rollback")
        self.failIf(nested)
        self.failUnlessEqual(len(self.log.undo_stacks), 0)
        self.failUnlessEqual(len(self.log.redo_stacks), 0)

    def testUndoRedo(self):
        """
        Try an undo() redo() sequence.
        """
        # begin
        self.log.begin("meh")
        self.failUnlessEqual(len(self.signals), 1)
        name, (stack, nested) = self.signals[0]
        self.failUnlessEqual(name, "begin")
        self.failIf(nested)

        # push two actions
        action1 = DummyUndoableAction()
        self.log.push(action1)
        self.failUnlessEqual(len(self.signals), 2)
        name, (stack, signalAction) = self.signals[1]
        self.failUnlessEqual(name, "push")
        self.failUnless(action1 is signalAction)

        action2 = DummyUndoableAction()
        self.log.push(action2)
        self.failUnlessEqual(len(self.signals), 3)
        name, (stack, signalAction) = self.signals[2]
        self.failUnlessEqual(name, "push")
        self.failUnless(action2 is signalAction)

        # commit
        self.failUnlessEqual(len(self.log.undo_stacks), 0)
        self.failUnlessEqual(len(self.log.redo_stacks), 0)
        self.log.commit()
        self.failUnlessEqual(len(self.signals), 4)
        name, (stack, nested) = self.signals[3]
        self.failUnlessEqual(name, "commit")
        self.failIf(nested)
        self.failUnlessEqual(len(self.log.undo_stacks), 1)
        self.failUnlessEqual(len(self.log.redo_stacks), 0)

        self.failUnless(action1.done_)
        self.failUnless(action2.done_)

        # undo what we just committed
        self.log.undo()
        self.failUnlessEqual(len(self.signals), 5)
        name, stack = self.signals[4]
        self.failUnlessEqual(name, "undo")
        self.failUnlessEqual(len(self.log.undo_stacks), 0)
        self.failUnlessEqual(len(self.log.redo_stacks), 1)

        self.failIf(action1.done_)
        self.failIf(action2.done_)

        # redo
        self.log.redo()
        self.failUnlessEqual(len(self.signals), 6)
        name, stack = self.signals[5]
        self.failUnlessEqual(name, "redo")
        self.failUnlessEqual(len(self.log.undo_stacks), 1)
        self.failUnlessEqual(len(self.log.redo_stacks), 0)

        self.failUnless(action1.done_)
        self.failUnless(action2.done_)

    def testOrder(self):
        """
        Test that actions are undone and redone in the correct order.
        """
        call_sequence = []

        class Action(UndoableAction):
            def __init__(self, n):
                self.n = n

            def do(self):
                call_sequence.append("do%s" % self.n)
                self._done()

            def undo(self):
                call_sequence.append("undo%s" % self.n)
                self._undone()

        action1 = Action(1)
        action2 = Action(2)
        action3 = Action(3)

        self.log.begin("meh")
        self.log.push(action1)
        self.log.begin("nested")
        self.log.push(action2)
        self.log.commit()
        self.log.push(action3)
        self.log.commit()

        self.log.undo()
        self.failUnlessEqual(call_sequence, ["undo3", "undo2", "undo1"])

        call_sequence[:] = []
        self.log.redo()
        self.failUnlessEqual(call_sequence, ["do1", "do2", "do3"])

        call_sequence[:] = []
        self.log.undo()
        self.failUnlessEqual(call_sequence, ["undo3", "undo2", "undo1"])