[pitivi] utils: Cleanup the Selection class



commit c45d467a2a062797c25c08cfd5f3a90576d63e89
Author: Alexandru Băluț <alexandru balut gmail com>
Date:   Tue Jan 25 22:34:05 2022 +0100

    utils: Cleanup the Selection class
    
    Clarify what type of objects it holds, `GES.Clip`.
    
    Made the `Selection.selected` protected since the `Selection` object is
    already iterable.

 pitivi/clipproperties.py        | 10 +++----
 pitivi/timeline/timeline.py     |  7 +++--
 pitivi/utils/timeline.py        | 59 +++++++++++++++++++----------------------
 pitivi/viewer/overlay.py        | 11 ++++----
 tests/test_timeline_timeline.py |  2 +-
 5 files changed, 41 insertions(+), 48 deletions(-)
---
diff --git a/pitivi/clipproperties.py b/pitivi/clipproperties.py
index 75ad59600..39431fd9a 100644
--- a/pitivi/clipproperties.py
+++ b/pitivi/clipproperties.py
@@ -214,17 +214,13 @@ class ClipProperties(Gtk.ScrolledWindow, Loggable):
         self._project = project
 
     def _selection_changed_cb(self, selection):
-        selected_clips = selection.selected
-        single_clip_selected = len(selected_clips) == 1
-        self.helper_box.set_visible(not single_clip_selected)
+        ges_clip = selection.get_single_clip()
+        self.helper_box.set_visible(not ges_clip)
 
         video_source = None
         title_source = None
         color_clip_source = None
-        ges_clip = None
-        if single_clip_selected:
-            ges_clip = list(selected_clips)[0]
-
+        if ges_clip:
             for child in ges_clip.get_children(False):
                 if isinstance(child, GES.VideoSource):
                     video_source = child
diff --git a/pitivi/timeline/timeline.py b/pitivi/timeline/timeline.py
index f43709d86..8d7123cc5 100644
--- a/pitivi/timeline/timeline.py
+++ b/pitivi/timeline/timeline.py
@@ -2185,7 +2185,7 @@ class TimelineContainer(Gtk.Grid, Zoomable, Loggable):
         """
         with self.app.action_log.started("split clip", toplevel=True,
                                          
finalizing_action=CommitTimelineFinalizingAction(self._project.pipeline)):
-            self._split_elements(self.timeline.selection.selected)
+            self._split_elements(list(self.timeline.selection))
 
     def _split_elements(self, clips=None):
         splitting_selection = clips is not None
@@ -2197,7 +2197,6 @@ class TimelineContainer(Gtk.Grid, Zoomable, Loggable):
         position = self._project.pipeline.get_position()
         position = self.ges_timeline.get_frame_time(self.ges_timeline.get_frame_at(position))
         splitted = False
-
         with self._project.pipeline.commit_timeline_after():
             for clip in clips:
                 start = clip.get_start()
@@ -2287,7 +2286,7 @@ class TimelineContainer(Gtk.Grid, Zoomable, Loggable):
         previous_snapping_distance = self.ges_timeline.get_snapping_distance()
         self.ges_timeline.set_snapping_distance(0)
         try:
-            clips = list(self.timeline.selection.selected)
+            clips = list(self.timeline.selection)
             clips.sort(key=lambda candidate_clip: candidate_clip.start, reverse=delta_frames > 0)
             # We must use delta * frame_time because getting negative frame time is not possible.
             clip_delta = delta_frames * self.ges_timeline.get_frame_time(1)
@@ -2309,7 +2308,7 @@ class TimelineContainer(Gtk.Grid, Zoomable, Loggable):
 
     def snap_clips(self, forward: bool):
         """Snap clips to next or previous clip."""
-        clips = list(self.timeline.selection.selected)
+        clips = list(self.timeline.selection)
         clips.sort(key=lambda clip: clip.start, reverse=forward)
         with self.app.action_log.started("Snaps to closest clip",
                                          
finalizing_action=CommitTimelineFinalizingAction(self._project.pipeline),
diff --git a/pitivi/utils/timeline.py b/pitivi/utils/timeline.py
index 64eb8cd9d..976e9a9f4 100644
--- a/pitivi/utils/timeline.py
+++ b/pitivi/utils/timeline.py
@@ -15,6 +15,9 @@
 #
 # You should have received a copy of the GNU Lesser General Public
 # License along with this program; if not, see <http://www.gnu.org/licenses/>.
+from typing import List
+from typing import Set
+
 from gi.repository import GES
 from gi.repository import GObject
 from gi.repository import Gst
@@ -70,9 +73,6 @@ class Selected(GObject.Object):
 class Selection(GObject.Object, Loggable):
     """Manages a set of clips representing a selection.
 
-    Attributes:
-        selected (List[GES.TrackElement]): Set of selected elements.
-
     Signals:
         selection-changed: The contents of the selection changed.
     """
@@ -84,52 +84,50 @@ class Selection(GObject.Object, Loggable):
     def __init__(self):
         GObject.Object.__init__(self)
         Loggable.__init__(self)
-        self.selected = set()
+        self._clips: Set[GES.Clip] = set()
         self.can_group = False
         self.can_ungroup = False
 
-    def set_selection(self, objs, mode):
+    def set_selection(self, clips: List[GES.Clip], mode: int):
         """Updates the current selection.
 
         Args:
-            objs (List[GES.TrackElement]): Timeline objects to update the
-                selection with.
+            clips (List[GES.Clip]): Timeline clips to update the selection with.
             mode (SELECT or UNSELECT or SELECT_ADD): The type of update to
                 apply. The selection will be:
                 - `SELECT` : set to the provided selection.
                 - `UNSELECT` : the same minus the provided selection.
                 - `SELECT_ADD` : extended with the provided selection.
         """
-        selection = set()
-        for obj in objs:
-            # FIXME GES break, handle the fact that we have unlinked objects in
-            # GES
-            if isinstance(obj, GES.TrackElement):
-                selection.add(obj.get_parent())
-            else:
-                selection.add(obj)
+        self.debug("Updating selection %s mode %s", clips, mode)
         if mode == SELECT_ADD:
-            selection = self.selected | selection
+            selection = self._clips | set(clips)
         elif mode == UNSELECT:
-            selection = self.selected - selection
+            selection = self._clips - set(clips)
+        else:
+            selection = set(clips)
 
-        old_selection = self.selected
-        if selection == old_selection:
+        if self._clips == selection:
             # Nothing changed. This can happen for example when the user clicks
             # the selected clip, then the clip remains selected.
             return
-        self.selected = selection
+
+        old_selection = self._clips
+        self._clips = selection
 
         for obj, selected in self.__get_selection_changes(old_selection):
             obj.selected.selected = selected
             if obj.ui:
                 from pitivi.utils.ui import set_state_flags_recurse
                 set_state_flags_recurse(obj.ui, Gtk.StateFlags.SELECTED, are_set=selected)
+
             for element in obj.get_children(False):
                 if isinstance(obj, (GES.BaseEffect, GES.TextOverlay)):
                     continue
                 element.selected.selected = selected
+
         self.set_can_group_ungroup()
+
         self.emit("selection-changed")
 
     def set_can_group_ungroup(self):
@@ -146,13 +144,13 @@ class Selection(GObject.Object, Loggable):
         self.can_ungroup = can_ungroup and not self.can_group
 
     def __get_selection_changes(self, old_selection):
-        for obj in old_selection - self.selected:
+        for obj in old_selection - self._clips:
             yield obj, False
 
         # Announce all selected objects that they are selected, even if
         # they were already selected. This allows them to update based on
         # the current selection.
-        for obj in self.selected:
+        for obj in self._clips:
             yield obj, True
 
     def select(self, objs):
@@ -168,7 +166,7 @@ class Selection(GObject.Object, Loggable):
             List[GES.TrackElement]
         """
         objects = []
-        for clip in self.selected:
+        for clip in self._clips:
             objects.extend(clip.get_children(False))
 
         return set(objects)
@@ -179,8 +177,8 @@ class Selection(GObject.Object, Loggable):
         Args:
             clip_type (type): The class the clip must be an instance of.
         """
-        if len(self.selected) == 1:
-            clip = tuple(self.selected)[0]
+        if len(self._clips) == 1:
+            clip = tuple(self._clips)[0]
             if isinstance(clip, clip_type):
                 return clip
         return None
@@ -189,7 +187,7 @@ class Selection(GObject.Object, Loggable):
     def toplevels(self):
         """Returns the toplevel elements of the selection."""
         toplevels = set()
-        for obj in self.selected:
+        for obj in self._clips:
             if not obj.timeline:
                 # The element has been removed from the timeline. Ignore it.
                 continue
@@ -215,7 +213,7 @@ class Selection(GObject.Object, Loggable):
             have only non-serializable ancestors.
         """
         toplevels = set()
-        for obj in self.selected:
+        for obj in self._clips:
             if not obj.timeline:
                 # The element has been removed from the timeline. Ignore it.
                 continue
@@ -229,10 +227,10 @@ class Selection(GObject.Object, Loggable):
         return group
 
     def __len__(self):
-        return len(self.selected)
+        return len(self._clips)
 
     def __iter__(self):
-        return iter(self.selected)
+        return iter(self._clips)
 
 
 class EditingContext(GObject.Object, Loggable):
@@ -269,7 +267,6 @@ class EditingContext(GObject.Object, Loggable):
         self.old_priority = self.focus.get_priority()
 
         self.new_position = None
-        self.new_priority = None
 
         self.timeline = timeline
         self.app = app
@@ -286,6 +283,7 @@ class EditingContext(GObject.Object, Loggable):
                                       toplevel=True)
 
     def finish(self):
+        self.debug("Finishing editing context")
         if self.__log_actions:
             self.app.action_log.commit("move-clip")
         self.timeline.get_asset().pipeline.commit_timeline()
@@ -314,7 +312,6 @@ class EditingContext(GObject.Object, Loggable):
             priority = max(0, priority)
 
         self.new_position = position
-        self.new_priority = priority
 
         if self.with_video:
             frame = self.timeline.get_frame_at(position)
diff --git a/pitivi/viewer/overlay.py b/pitivi/viewer/overlay.py
index 5d30f1a83..de3005290 100644
--- a/pitivi/viewer/overlay.py
+++ b/pitivi/viewer/overlay.py
@@ -53,13 +53,14 @@ class Overlay(Gtk.DrawingArea, Loggable):
 
     def _select(self):
         self.stack.selected_overlay = self
-        self.stack.app.gui.editor.timeline_ui.timeline.selection.set_selection([self._source], SELECT)
-        if isinstance(self._source, (GES.TitleSource, GES.VideoUriSource, GES.VideoTestSource)):
-            page = 0
-        else:
+        ges_clip = self._source.get_parent()
+        self.stack.app.gui.editor.timeline_ui.timeline.selection.set_selection([ges_clip], SELECT)
+
+        if not isinstance(self._source, (GES.TitleSource, GES.VideoUriSource, GES.VideoTestSource)):
             self.warning("Unknown clip type: %s", self._source)
             return
-        self.stack.app.gui.editor.context_tabs.set_current_page(page)
+
+        self.stack.app.gui.editor.context_tabs.set_current_page(0)
 
     def __source_selected_changed_cb(self, unused_source, selected):
         if not selected and self._is_selected():
diff --git a/tests/test_timeline_timeline.py b/tests/test_timeline_timeline.py
index 0cf86bdc9..dfcda10c4 100644
--- a/tests/test_timeline_timeline.py
+++ b/tests/test_timeline_timeline.py
@@ -326,7 +326,7 @@ class TestGrouping(common.TestCase):
         clips = self.add_clips_simple(timeline, num_clips)
         self.group_clips(timeline_container, clips)
 
-        self.assertEqual(len(timeline.selection.selected), num_clips)
+        self.assertEqual(len(timeline.selection), num_clips)
 
         timeline_container.ungroup_action.emit("activate", None)
         layer = timeline.ges_timeline.get_layers()[0]


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