[pitivi] pitivi: Rely on timeline widgets' focus to set actions/shortcuts sensitivity



commit 13621422fc5e2d4317f299bce06205987477e466
Author: Jean-François Fortin Tam <nekohayo gmail com>
Date:   Tue Sep 10 22:25:00 2013 -0400

    pitivi: Rely on timeline widgets' focus to set actions/shortcuts sensitivity
    
    This greatly simplifies the code (present and future) and makes the whole app
    incredibly more reliable when it comes to preventing "dangerous" timeline
    shortcuts (such as Delete/Spacebar) from interfering with other GTK+ widgets.
    
    Fixes bug #707828

 data/ui/effectslibrary.ui   |    2 --
 data/ui/medialibrary.ui     |    2 --
 data/ui/titleeditor.ui      |    2 --
 pitivi/clipproperties.py    |   10 ----------
 pitivi/effects.py           |    6 ------
 pitivi/mainwindow.py        |   22 ----------------------
 pitivi/medialibrary.py      |   20 --------------------
 pitivi/timeline/layer.py    |    5 -----
 pitivi/timeline/ruler.py    |   15 +++++++++++++++
 pitivi/timeline/timeline.py |   36 ++++++++++++++++++++++++++++++------
 pitivi/titleeditor.py       |    6 ------
 pitivi/transitions.py       |    8 --------
 pitivi/viewer.py            |    8 --------
 13 files changed, 45 insertions(+), 97 deletions(-)
---
diff --git a/data/ui/effectslibrary.ui b/data/ui/effectslibrary.ui
index 3f35a44..98ea9a3 100644
--- a/data/ui/effectslibrary.ui
+++ b/data/ui/effectslibrary.ui
@@ -91,8 +91,6 @@
               </object>
             </child>
             <signal name="changed" handler="_searchEntryChangedCb" swapped="no"/>
-            <signal name="focus-in-event" handler="_searchEntryFocusedCb" swapped="no"/>
-            <signal name="focus-out-event" handler="_searchEntryDefocusedCb" swapped="no"/>
             <signal name="icon-release" handler="_searchEntryIconClickedCb" swapped="no"/>
           </object>
         </child>
diff --git a/data/ui/medialibrary.ui b/data/ui/medialibrary.ui
index 0c7ff43..e49d7a5 100644
--- a/data/ui/medialibrary.ui
+++ b/data/ui/medialibrary.ui
@@ -144,8 +144,6 @@
               </object>
             </child>
             <signal name="changed" handler="_searchEntryChangedCb" swapped="no"/>
-            <signal name="focus-in-event" handler="_disableKeyboardShortcutsCb" swapped="no"/>
-            <signal name="focus-out-event" handler="_enableKeyboardShortcutsCb" swapped="no"/>
             <signal name="icon-release" handler="_searchEntryIconClickedCb" swapped="no"/>
           </object>
         </child>
diff --git a/data/ui/titleeditor.ui b/data/ui/titleeditor.ui
index 35a4c86..e0f2b32 100644
--- a/data/ui/titleeditor.ui
+++ b/data/ui/titleeditor.ui
@@ -230,8 +230,6 @@
             <property name="margin_top">12</property>
             <property name="margin_bottom">12</property>
             <property name="wrap_mode">word</property>
-            <signal name="focus-in-event" handler="_textviewFocusedCb" swapped="no"/>
-            <signal name="focus-out-event" handler="_textviewUnfocusedCb" swapped="no"/>
           </object>
           <packing>
             <property name="expand">True</property>
diff --git a/pitivi/clipproperties.py b/pitivi/clipproperties.py
index 2e5b817..86c855b 100644
--- a/pitivi/clipproperties.py
+++ b/pitivi/clipproperties.py
@@ -429,10 +429,8 @@ class EffectProperties(Gtk.Expander, Loggable):
 
     def _treeviewSelectionChangedCb(self, treeview):
         if self.selection.count_selected_rows() == 0 and self.clips:
-            self.app.gui.setActionsSensitive(True)
             self._toolbar.hide()
         else:
-            self.app.gui.setActionsSensitive(False)
             self._toolbar.show()
 
         self._updateEffectConfigUi()
@@ -561,8 +559,6 @@ class TransformationProperties(Gtk.Expander):
         """
         spinbtn = self.builder.get_object(widget_name)
         spinbtn.connect("output", self._onValueChangedCb, property_name)
-        spinbtn.connect("focus-in-event", self._disableTimelineActionsCb)
-        spinbtn.connect("focus-out-event", self._enableTimelineActionsCb)
         self.spin_buttons[property_name] = spinbtn
         self.default_values[property_name] = spinbtn.get_value()
 
@@ -584,12 +580,6 @@ class TransformationProperties(Gtk.Expander):
         if box and box.clicked_point == 0:
             box.update_from_effect(self.effect)
 
-    def _disableTimelineActionsCb(self, unused_widget, unused_event):
-        self.app.gui.setActionsSensitive(False)
-
-    def _enableTimelineActionsCb(self, unused_widget, unused_event):
-        self.app.gui.setActionsSensitive(True)
-
     def _flushPipeLineCb(self, widget):
         self.app.current_project.pipeline.flushSeek()
 
diff --git a/pitivi/effects.py b/pitivi/effects.py
index b42a7a2..7a05835 100644
--- a/pitivi/effects.py
+++ b/pitivi/effects.py
@@ -586,12 +586,6 @@ class EffectListWidget(Gtk.VBox, Loggable):
     def _searchEntryIconClickedCb(self, entry, unused, unused1):
         entry.set_text("")
 
-    def _searchEntryFocusedCb(self, entry, event):
-        self.app.gui.setActionsSensitive(False)
-
-    def _searchEntryDefocusedCb(self, entry, event):
-        self.app.gui.setActionsSensitive(True)
-
     def _setRowVisible(self, model, iter, data):
         if self._effectType == model.get_value(iter, COL_EFFECT_TYPE):
             if model.get_value(iter, COL_EFFECT_CATEGORIES) is None:
diff --git a/pitivi/mainwindow.py b/pitivi/mainwindow.py
index 11e309d..fa9ebf8 100644
--- a/pitivi/mainwindow.py
+++ b/pitivi/mainwindow.py
@@ -579,28 +579,6 @@ class PitiviMainWindow(Gtk.Window, Loggable):
         self._fullscreenToolbarDirection = None
         return False
 
-    def setActionsSensitive(self, sensitive):
-        """
-        Grab (or release) keyboard letter keys focus/sensitivity
-        for operations such as typing text in an entry.
-
-        This toggles the sensitivity of all actiongroups that might interfere.
-        This means mostly the timeline's actions.
-
-        This method does not need to be called when creating a separate window.
-        """
-        self.log("Setting actions sensitivity to %s" % sensitive)
-        # The mainwindow's actions don't prevent typing into entry widgets;
-        # Only timeline actions (ex: deleting and play/pause) are dangerous.
-        if self.timeline_ui:
-            # Don't loop in self.timeline_ui.ui_manager.get_action_groups()
-            # otherwise you'll get all the action groups of the application.
-            self.timeline_ui.playhead_actions.set_sensitive(sensitive)
-            selected = self.timeline_ui.timeline.selection.getSelectedTrackElements()
-            if not sensitive or (sensitive and selected):
-                self.log("Setting timeline selection actions sensitivity to %s" % sensitive)
-                self.timeline_ui.selection_actions.set_sensitive(sensitive)
-
 ## Missing Plugin Support
 
     def _installPlugins(self, details, missingPluginsCallback):
diff --git a/pitivi/medialibrary.py b/pitivi/medialibrary.py
index 86f8602..8fb360f 100644
--- a/pitivi/medialibrary.py
+++ b/pitivi/medialibrary.py
@@ -183,8 +183,6 @@ class MediaLibraryWidget(Gtk.VBox, Loggable):
         self.treeview_scrollwin.add(self.treeview)
         self.treeview.connect("button-press-event", self._treeViewButtonPressEventCb)
         self.treeview.connect("button-release-event", self._treeViewButtonReleaseEventCb)
-        self.treeview.connect("focus-in-event", self._disableKeyboardShortcutsCb)
-        self.treeview.connect("focus-out-event", self._enableKeyboardShortcutsCb)
         self.treeview.connect("row-activated", self._itemOrRowActivatedCb)
         self.treeview.set_property("rules_hint", True)
         self.treeview.set_headers_visible(False)
@@ -226,8 +224,6 @@ class MediaLibraryWidget(Gtk.VBox, Loggable):
         self.iconview_scrollwin.add(self.iconview)
         self.iconview.connect("button-press-event", self._iconViewButtonPressEventCb)
         self.iconview.connect("button-release-event", self._iconViewButtonReleaseEventCb)
-        self.iconview.connect("focus-in-event", self._disableKeyboardShortcutsCb)
-        self.iconview.connect("focus-out-event", self._enableKeyboardShortcutsCb)
         self.iconview.connect("item-activated", self._itemOrRowActivatedCb)
         self.iconview.connect("selection-changed", self._viewSelectionChangedCb)
         self.iconview.set_item_orientation(Gtk.Orientation.VERTICAL)
@@ -333,22 +329,6 @@ class MediaLibraryWidget(Gtk.VBox, Loggable):
     def _insertEndCb(self, unused_action):
         self.app.gui.timeline_ui.insertEnd(self.getSelectedAssets())
 
-    def _disableKeyboardShortcutsCb(self, *unused_args):
-        """
-        Disable the Delete keyboard shortcut and playback shortcuts
-        to prevent accidents or being unable to type various characters.
-
-        This is used when focusing the search entry, icon on tree view widgets.
-        """
-        self.app.gui.setActionsSensitive(False)
-
-    def _enableKeyboardShortcutsCb(self, *unused_args):
-        """
-        When focusing out of media library widgets,
-        re-enable the timeline keyboard shortcuts.
-        """
-        self.app.gui.setActionsSensitive(True)
-
     def _trackElementAddedCb(self, source, unused_track_element):
         """ After an object has been added to the first track, position it
         correctly and request the next source to be processed. """
diff --git a/pitivi/timeline/layer.py b/pitivi/timeline/layer.py
index 6726193..7065a0a 100644
--- a/pitivi/timeline/layer.py
+++ b/pitivi/timeline/layer.py
@@ -84,8 +84,6 @@ class BaseLayerControl(Gtk.VBox, Loggable):
         self.name_entry = Gtk.Entry()
         self.name_entry.set_tooltip_text(_("Set a personalized name for this layer"))
         self.name_entry.set_property("primary-icon-name", icon_mapping[layer_type])
-        self.name_entry.connect("focus-in-event", self._focusChangeCb, False)
-        self.name_entry.connect("focus-out-event", self._focusChangeCb, True)
         self.name_entry.connect("button_press_event", self._buttonPressCb)
 #        self.name_entry.drag_dest_unset()
         self.name_entry.set_sensitive(False)
@@ -180,9 +178,6 @@ class BaseLayerControl(Gtk.VBox, Loggable):
         else:
             button.set_tooltip_text(_("Make layer visible"))
 
-    def _focusChangeCb(self, widget, direction, sensitive_actions):
-        self._app.gui.setActionsSensitive(sensitive_actions)
-
     def _soloToggledCb(self, button):
         """
         Send TimelineControls the new solo-ed layer
diff --git a/pitivi/timeline/ruler.py b/pitivi/timeline/ruler.py
index 2023977..2d96743 100644
--- a/pitivi/timeline/ruler.py
+++ b/pitivi/timeline/ruler.py
@@ -72,6 +72,12 @@ class ScaleRuler(Gtk.DrawingArea, Zoomable, Loggable):
         Zoomable.__init__(self)
         Loggable.__init__(self)
         self.log("Creating new ScaleRuler")
+
+        # Allows stealing focus from other GTK widgets, prevent accidents:
+        self.props.can_focus = True
+        self.connect("focus-in-event", self._focusInCb)
+        self.connect("focus-out-event", self._focusOutCb)
+
         self.app = instance
         self._seeker = Seeker()
         self.hadj = hadj
@@ -99,6 +105,14 @@ class ScaleRuler(Gtk.DrawingArea, Zoomable, Loggable):
         self.callback_id = None
         self.callback_id_scroll = None
 
+    def _focusInCb(self, unused_widget, unused_arg):
+        self.log("Ruler has grabbed focus")
+        self.app.gui.timeline_ui.setActionsSensitivity(True)
+
+    def _focusOutCb(self, unused_widget, unused_arg):
+        self.log("Ruler has lost focus")
+        self.app.gui.timeline_ui.setActionsSensitivity(False)
+
     def _hadjValueChangedCb(self, hadj):
         self.pixbuf_offset = self.hadj.get_value()
         if self.callback_id_scroll is not None:
@@ -168,6 +182,7 @@ class ScaleRuler(Gtk.DrawingArea, Zoomable, Loggable):
 
     def do_button_release_event(self, event):
         self.debug("button released at x:%d", event.x)
+        self.grab_focus()  # Prevent other widgets from being confused
         self.pressed = False
         return False
 
diff --git a/pitivi/timeline/timeline.py b/pitivi/timeline/timeline.py
index 66f078e..b1778fd 100644
--- a/pitivi/timeline/timeline.py
+++ b/pitivi/timeline/timeline.py
@@ -694,6 +694,11 @@ class Timeline(Gtk.VBox, Zoomable, Loggable):
         Loggable.__init__(self)
         GObject.threads_init()
 
+        # Allows stealing focus from other GTK widgets, prevent accidents:
+        self.props.can_focus = True
+        self.connect("focus-in-event", self._focusInCb)
+        self.connect("focus-out-event", self._focusOutCb)
+
         self.gui = gui
         self.ui_manager = ui_manager
         self.app = instance
@@ -842,6 +847,22 @@ class Timeline(Gtk.VBox, Zoomable, Loggable):
             return GES.EditMode.EDIT_TRIM
         return GES.EditMode.EDIT_NORMAL
 
+    def setActionsSensitivity(self, sensitive):
+        """
+        The timeline's "actions" have global keyboard shortcuts that are
+        dangerous in any context other than the timeline. In a text entry widget
+        for example, you don't want the "Delete" key to remove clips currently
+        selected on the timeline, or "Spacebar" to toggle playback.
+
+        This sets the sensitivity of all actiongroups that might interfere.
+        """
+        self.playhead_actions.set_sensitive(sensitive)
+        self.debug("Playback shortcuts sensitivity set to %s" % sensitive)
+        selected = self.timeline.selection.getSelectedTrackElements()
+        if not sensitive or (sensitive and selected):
+            self.selection_actions.set_sensitive(sensitive)
+            self.debug("Editing shortcuts sensitivity set to %s" % sensitive)
+
     # Internal API
 
     def _createUi(self):
@@ -875,8 +896,6 @@ class Timeline(Gtk.VBox, Zoomable, Loggable):
             self.gui.connect("key-press-event", self._keyPressEventCb)
             self.gui.connect("key-release-event", self._keyReleaseEventCb)
 
-        self.embed.connect("enter-notify-event", self._enterNotifyEventCb)
-
         self.point = Clutter.Point()
         self.point.x = 0
         self.point.y = 0
@@ -1295,10 +1314,6 @@ class Timeline(Gtk.VBox, Zoomable, Loggable):
 
     # Callbacks
 
-    def _enterNotifyEventCb(self, widget, event):
-        if self.gui:
-            self.gui.setActionsSensitive(True)
-
     def _keyPressEventCb(self, widget, event):
         if event.keyval == Gdk.KEY_Shift_L:
             self.shiftMask = True
@@ -1311,8 +1326,17 @@ class Timeline(Gtk.VBox, Zoomable, Loggable):
         elif event.keyval == Gdk.KEY_Control_L:
             self.controlMask = False
 
+    def _focusInCb(self, unused_widget, unused_arg):
+        self.log("Timeline has grabbed focus")
+        self.setActionsSensitivity(True)
+
+    def _focusOutCb(self, unused_widget, unused_arg):
+        self.log("Timeline has lost focus")
+        self.setActionsSensitivity(False)
+
     def _timelineClickedCb(self, unused_timeline, event):
         self.pressed = True
+        self.grab_focus()  # Prevent other widgets from being confused
         position = self.pixelToNs(event.x - CONTROL_WIDTH + self.timeline._scroll_point.x)
         if self.app:
             self._seeker.seek(position)
diff --git a/pitivi/titleeditor.py b/pitivi/titleeditor.py
index 810e8fc..0cbb521 100644
--- a/pitivi/titleeditor.py
+++ b/pitivi/titleeditor.py
@@ -630,12 +630,6 @@ class TitleEditor(Loggable):
             self.settings["halignment"].append(en, n)
         self._deactivate()
 
-    def _textviewFocusedCb(self, unused_widget, unused_event):
-        self.app.gui.setActionsSensitive(False)
-
-    def _textviewUnfocusedCb(self, unused_widget, unused_event):
-        self.app.gui.setActionsSensitive(True)
-
     def _backgroundColorButtonCb(self, widget):
         self.textarea.modify_base(self.textarea.get_state(), widget.get_color())
         color = widget.get_rgba()
diff --git a/pitivi/transitions.py b/pitivi/transitions.py
index 978fbff..07d3802 100644
--- a/pitivi/transitions.py
+++ b/pitivi/transitions.py
@@ -118,8 +118,6 @@ class TransitionsListWidget(Signallable, Gtk.VBox, Loggable):
         self.iconview.set_property("has_tooltip", True)
 
         self.searchEntry.connect("changed", self._searchEntryChangedCb)
-        self.searchEntry.connect("focus-in-event", self._searchEntryActivateCb)
-        self.searchEntry.connect("focus-out-event", self._searchEntryDeactivateCb)
         self.searchEntry.connect("icon-press", self._searchEntryIconClickedCb)
         self.iconview.connect("selection-changed", self._transitionSelectedCb)
         self.iconview.connect("query-tooltip", self._queryTooltipCb)
@@ -201,12 +199,6 @@ class TransitionsListWidget(Signallable, Gtk.VBox, Loggable):
     def _searchEntryIconClickedCb(self, entry, unused, unsed1):
         entry.set_text("")
 
-    def _searchEntryDeactivateCb(self, entry, event):
-        self.app.gui.setActionsSensitive(True)
-
-    def _searchEntryActivateCb(self, entry, event):
-        self.app.gui.setActionsSensitive(False)
-
 # GES callbacks
 
     def _transitionTypeChangedCb(self, element, unused_prop):
diff --git a/pitivi/viewer.py b/pitivi/viewer.py
index c8d061c..321dfe6 100644
--- a/pitivi/viewer.py
+++ b/pitivi/viewer.py
@@ -244,7 +244,6 @@ class PitiviViewer(Gtk.VBox, Loggable):
         self.timecode_entry.setWidgetValue(0)
         self.timecode_entry.set_tooltip_text(_('Enter a timecode or frame number\nand press "Enter" to go to 
that position'))
         self.timecode_entry.connectActivateEvent(self._entryActivateCb)
-        self.timecode_entry.connectFocusEvents(self._entryFocusInCb, self._entryFocusOutCb)
         bbox.pack_start(self.timecode_entry, False, 10, 0)
         self._haveUI = True
 
@@ -289,13 +288,6 @@ class PitiviViewer(Gtk.VBox, Loggable):
     def _entryActivateCb(self, entry):
         self._seekFromTimecodeWidget()
 
-    def _entryFocusInCb(self, entry, event):
-        self.app.gui.setActionsSensitive(False)
-
-    def _entryFocusOutCb(self, entry, event):
-        self._seekFromTimecodeWidget()
-        self.app.gui.setActionsSensitive(True)
-
     def _seekFromTimecodeWidget(self):
         nanoseconds = self.timecode_entry.getWidgetValue()
         self.seeker.seek(nanoseconds)


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