[pitivi] Fix ungrouping and add grouping unit tests



commit 850446a7d622f76880295907a1fefdac1376180e
Author: Thibault Saunier <tsaunier gnome org>
Date:   Wed Jan 6 14:10:28 2016 +0100

    Fix ungrouping and add grouping unit tests
    
    Ungrouping selected clips now deselects all clips so that
    user can notice clips are actually not selected
    
    After grouping, add the new group to timeline.current_group
    as it keeps being selected.
    
    In the case were we group/ungroup right away,
    make sure ungrouping does not recurse and ungroups
    more than supposed to.
    
    Reviewed-by: Alex Băluț <alexandru balut gmail com>
    Differential Revision: https://phabricator.freedesktop.org/D624

 pitivi/timeline/timeline.py     |   13 +++--
 tests/common.py                 |   21 ++++++-
 tests/test_timeline_timeline.py |  129 +++++++++++++++++++++++++++++++++------
 3 files changed, 138 insertions(+), 25 deletions(-)
---
diff --git a/pitivi/timeline/timeline.py b/pitivi/timeline/timeline.py
index 359eedc..830fe2f 100644
--- a/pitivi/timeline/timeline.py
+++ b/pitivi/timeline/timeline.py
@@ -1562,21 +1562,21 @@ class TimelineContainer(Gtk.Grid, Zoomable, Loggable):
             if toplevel == self.timeline.current_group:
                 for child in toplevel.get_children(False):
                     child.ungroup(False)
-            else:
-                toplevel.ungroup(False)
 
         self.timeline.resetSelectionGroup()
+        self.timeline.selection.setSelection([], SELECT)
 
         self.app.action_log.commit()
         self._project.pipeline.commit_timeline()
 
     def _groupSelected(self, unused_action, unused_parameter):
         if not self.bTimeline:
-            self.error("No timeline set yet?")
+            self.info("No timeline set yet?")
             return
 
         self.app.action_log.begin("group")
-        containers = set({})
+        containers = set()
+        new_group = None
         for obj in self.timeline.selection:
             toplevel = obj.get_toplevel_parent()
             if toplevel == self.timeline.current_group:
@@ -1587,10 +1587,13 @@ class TimelineContainer(Gtk.Grid, Zoomable, Loggable):
                 containers.add(toplevel)
 
         if containers:
-            GES.Container.group(list(containers))
+            new_group = GES.Container.group(list(containers))
 
         self.timeline.resetSelectionGroup()
 
+        if new_group:
+            self.timeline.current_group.add(new_group)
+
         self._project.pipeline.commit_timeline()
         self.app.action_log.commit()
 
diff --git a/tests/common.py b/tests/common.py
index 9cfdedd..5e03ab4 100644
--- a/tests/common.py
+++ b/tests/common.py
@@ -7,14 +7,17 @@ import gc
 import unittest
 import tempfile
 
+from gi.repository import Gdk
 from gi.repository import Gst
+from gi.repository import Gtk
 
 from unittest import mock
 from pitivi import check
 
 from pitivi.application import Pitivi
-from pitivi.utils.timeline import Selected
 from pitivi.utils.loggable import Loggable
+from pitivi.utils.timeline import Selected
+from pitivi.utils.validate import Event
 
 detect_leaks = os.environ.get("PITIVI_TEST_DETECT_LEAKS", "0") not in ("0", "")
 os.environ["PITIVI_USER_CACHE_DIR"] = tempfile.mkdtemp("pitiviTestsuite")
@@ -107,6 +110,22 @@ class TestCase(unittest.TestCase, Loggable):
         self._result = result
         unittest.TestCase.run(self, result)
 
+    def toggleClipSelection(self, bClip):
+        '''
+        Toggle selection state of @bClip.
+        '''
+        selected = bool(bClip.ui.get_state_flags() & Gtk.StateFlags.SELECTED)
+        self.assertEqual(bClip.selected.selected, selected)
+
+        bClip.ui.sendFakeEvent(
+            Event(Gdk.EventType.BUTTON_PRESS, button=1), bClip.ui)
+        bClip.ui.sendFakeEvent(
+            Event(Gdk.EventType.BUTTON_RELEASE, button=1), bClip.ui)
+
+        self.assertEqual(bool(bClip.ui.get_state_flags() & Gtk.StateFlags.SELECTED),
+                         not selected)
+        self.assertEqual(bClip.selected.selected, not selected)
+
 
 def getSampleUri(sample):
     assets_dir = os.path.dirname(os.path.abspath(__file__))
diff --git a/tests/test_timeline_timeline.py b/tests/test_timeline_timeline.py
index 883add8..5954b82 100644
--- a/tests/test_timeline_timeline.py
+++ b/tests/test_timeline_timeline.py
@@ -17,12 +17,17 @@
 # Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
 # Boston, MA 02110-1301, USA.
 
-from unittest import TestCase, mock
-from tests.common import getPitiviMock
+from unittest import mock
+
 from gi.repository import Gdk
+from gi.repository import GES
+from gi.repository import Gtk
+
+from tests import common
 
-from pitivi.project import Project, ProjectManager
-from pitivi.timeline.timeline import Timeline
+from pitivi.project import ProjectManager
+from pitivi.timeline.timeline import TimelineContainer
+from pitivi.utils.validate import Event
 from pitivi.utils import ui
 
 
@@ -31,26 +36,23 @@ THIN = ui.LAYER_HEIGHT / 2
 THICK = ui.LAYER_HEIGHT
 
 
-class TestLayers(TestCase):
-
-    def createTimeline(self, layers_heights):
-        app = getPitiviMock()
+class BaseTestTimeline(common.TestCase):
+    def createTimeline(self):
+        app = common.getPitiviMock()
         project_manager = ProjectManager(app)
         project_manager.newBlankProject()
         project = project_manager.current_project
-        timeline = Timeline(container=mock.MagicMock(), app=app)
+
+        timeline_container = TimelineContainer(app)
+        timeline_container.setProject(project)
+
+        timeline = timeline_container.timeline
         timeline.get_parent = mock.MagicMock()
-        timeline.setProject(project)
-        y = 0
-        for priority, height in enumerate(layers_heights):
-            bLayer = timeline.createLayer(priority=priority)
-            rect = Gdk.Rectangle()
-            rect.y = y
-            rect.height = height
-            bLayer.ui.set_allocation(rect)
-            y += height + SEPARATOR_HEIGHT
+
         return timeline
 
+
+class TestLayers(BaseTestTimeline):
     def testDraggingLayer(self):
         self.checkGetLayerAt([THIN, THIN, THIN], 1, True,
                              [0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2])
@@ -82,7 +84,17 @@ class TestLayers(TestCase):
                              [0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2])
 
     def checkGetLayerAt(self, heights, preferred, past_middle_when_adjacent, expectations):
-        timeline = self.createTimeline(heights)
+        timeline = self.createTimeline()
+
+        y = 0
+        for priority, height in enumerate(heights):
+            bLayer = timeline.createLayer(priority=priority)
+            rect = Gdk.Rectangle()
+            rect.y = y
+            rect.height = height
+            bLayer.ui.set_allocation(rect)
+            y += height + SEPARATOR_HEIGHT
+
         bLayers = [layer.bLayer for layer in timeline._layers]
         if preferred is None:
             preferred_bLayer = None
@@ -126,3 +138,82 @@ class TestLayers(TestCase):
         assertLayerAt(bLayers[expectations[13]], h[0] + s + h[1] + s + h[2] / 2 - 1)
         assertLayerAt(bLayers[expectations[14]], h[0] + s + h[1] + s + h[2] / 2)
         assertLayerAt(bLayers[expectations[15]], h[0] + s + h[1] + s + h[2] - 1)
+
+
+class TestGrouping(BaseTestTimeline):
+    def groupClips(self, num_clips):
+        timeline = self.createTimeline()
+        timeline.app.settings.leftClickAlsoSeeks = False
+        layer = timeline.bTimeline.append_layer()
+
+        asset = GES.UriClipAsset.request_sync(
+            common.getSampleUri("tears_of_steel.webm"))
+
+        clips = [layer.add_asset(asset, i * 10, 0, 10, GES.TrackType.UNKNOWN)
+                 for i in range(num_clips)]
+
+        # Press <ctrl> so selecting in ADD mode
+        timeline.sendFakeEvent(Event(event_type=Gdk.EventType.KEY_PRESS,
+                                     keyval=Gdk.KEY_Control_L))
+
+        # Select the 2 clips
+        for clip in clips:
+            self.toggleClipSelection(clip)
+
+        before_grouping_timeline_group = timeline.current_group
+
+        for clip in clips:
+            self.assertEqual(clip.get_parent(), timeline.current_group)
+
+        timeline.parent.group_action.emit("activate", None)
+
+        self.assertNotEqual(timeline.current_group, before_grouping_timeline_group)
+        for clip in clips:
+            # Check that we created a new group and that this group is not
+            # the timeline current_group
+            self.assertTrue(isinstance(clip.get_parent(), GES.Group))
+            self.assertNotEqual(clip.get_parent(), timeline.current_group)
+            # The newly created group has been selected
+            self.assertEqual(clip.get_toplevel_parent(), timeline.current_group)
+
+        for clip in clips:
+            self.assertEqual(clips[0].get_parent(), clip.get_parent())
+            self.assertTrue(bool(clip.ui.get_state_flags() & Gtk.StateFlags.SELECTED))
+            self.assertTrue(clip.selected.selected)
+
+        group = clips[0].get_parent()
+        self.assertEqual(len(group.get_children(False)), num_clips)
+
+        return timeline
+
+    def testGroup(self):
+        self.groupClips(2)
+
+    def testGroupSelection(self):
+        num_clips = 2
+        timeline = self.groupClips(num_clips)
+        layer = timeline.bTimeline.get_layers()[0]
+        clips = layer.get_clips()
+        self.assertEqual(len(clips), num_clips)
+
+        # Deselect one grouped clip clips
+        self.toggleClipSelection(clips[0])
+
+        # Make sure all the clips have been deselected
+        for clip in clips:
+            self.assertFalse(bool(clip.ui.get_state_flags() & Gtk.StateFlags.SELECTED))
+            self.assertFalse(clip.selected.selected)
+
+    def testGroupUngroup(self):
+        num_clips = 2
+        timeline = self.groupClips(num_clips)
+
+        self.assertEqual(len(timeline.selection.selected), num_clips)
+
+        timeline.parent.ungroup_action.emit("activate", None)
+        layer = timeline.bTimeline.get_layers()[0]
+        clips = layer.get_clips()
+        self.assertEqual(len(clips), num_clips)
+
+        for clip in clips:
+            self.assertIsNone(clip.get_parent())


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