[pitivi] Stop using UIManager because it's obsolete



commit 7139f4f789efe2b958596aa30901ac4c21d66ad4
Author: Alexandru Băluț <alexandru balut gmail com>
Date:   Sat Oct 31 23:17:23 2015 +0100

    Stop using UIManager because it's obsolete
    
    Refactored the management of the timeline actions. Now they are not
    disabled when the timeline loses focus, because they are made available
    only to the layers representation layout and the timeline toolbar. This
    guarantees that the accelerators will trigger only if the focus is
    the (PitiviTimeline's) layout widget. For details see
    TimelineContainer._createActions.
    
    A nice result is that the toolbar buttons don't flicker because the
    actions are enabled or disabled too many times.
    
    Fixes https://phabricator.freedesktop.org/T3416
    Fixes https://phabricator.freedesktop.org/T3477
    
    Reviewed-by: Thibault Saunier <tsaunier gnome org>
    Differential Revision: https://phabricator.freedesktop.org/D546

 data/ui/Makefile.am           |    2 +-
 data/ui/medialibrary.ui       |   24 +---
 data/ui/timelinecontainer.xml |   31 ----
 data/ui/timelinetoolbar.ui    |  133 ++++++++++++++++++
 pitivi/effects.py             |    2 +-
 pitivi/mainwindow.py          |   28 ++---
 pitivi/medialibrary.py        |  120 +++++++---------
 pitivi/preset.py              |    6 +-
 pitivi/timeline/layer.py      |   10 +-
 pitivi/timeline/ruler.py      |   15 +--
 pitivi/timeline/timeline.py   |  303 ++++++++++++++++++-----------------------
 11 files changed, 346 insertions(+), 328 deletions(-)
---
diff --git a/data/ui/Makefile.am b/data/ui/Makefile.am
index 87e2be8..053f108 100644
--- a/data/ui/Makefile.am
+++ b/data/ui/Makefile.am
@@ -14,7 +14,7 @@ ui_DATA = \
        renderingdialog.ui \
        renderingprogress.ui \
        startupwizard.ui \
-       timelinecontainer.xml \
+       timelinetoolbar.ui \
        titleeditor.ui \
        $(NULL)
 
diff --git a/data/ui/medialibrary.ui b/data/ui/medialibrary.ui
index f9960fb..88260c1 100644
--- a/data/ui/medialibrary.ui
+++ b/data/ui/medialibrary.ui
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<!-- Generated with glade 3.18.1 -->
+<!-- Generated with glade 3.19.0 -->
 <interface>
   <requires lib="gtk+" version="3.10"/>
   <object class="GtkToolbar" id="medialibrary_toolbar">
@@ -11,7 +11,6 @@
       <object class="GtkToolButton" id="media_import_button">
         <property name="visible">True</property>
         <property name="can_focus">False</property>
-        <property name="has_tooltip">True</property>
         <property name="tooltip_markup" translatable="yes">Add media files to your project</property>
         <property name="is_important">True</property>
         <property name="label" translatable="yes">Import</property>
@@ -32,15 +31,12 @@
     <child>
       <object class="GtkToolButton" id="media_remove_button">
         <property name="visible">True</property>
-        <property name="sensitive">False</property>
         <property name="can_focus">False</property>
-        <property name="has_tooltip">True</property>
-        <property name="tooltip_markup" translatable="yes">Remove selected clips from the project</property>
         <property name="tooltip_text" translatable="yes">Remove selected clips from the project</property>
+        <property name="action_name">medialibrary.remove_assets</property>
         <property name="label" translatable="yes">_Remove from Project</property>
         <property name="use_underline">True</property>
         <property name="icon_name">list-remove-symbolic</property>
-        <signal name="clicked" handler="_removeClickedCb" swapped="no"/>
         <child internal-child="accessible">
           <object class="AtkObject" id="media_remove_button-atkobject">
             <property name="AtkObject::accessible-name">media_remove_button</property>
@@ -55,11 +51,8 @@
     <child>
       <object class="GtkToolButton" id="media_props_button">
         <property name="visible">True</property>
-        <property name="sensitive">False</property>
         <property name="can_focus">False</property>
-        <property name="has_tooltip">True</property>
-        <property name="tooltip_markup" translatable="yes">Clip Properties...</property>
-        <property name="tooltip_text" translatable="yes">Clip Properties...</property>
+        <property name="tooltip_text" translatable="yes">Clip properties...</property>
         <property name="use_underline">True</property>
         <property name="icon_name">document-properties-symbolic</property>
         <signal name="clicked" handler="_clipPropertiesCb" swapped="no"/>
@@ -77,15 +70,12 @@
     <child>
       <object class="GtkToolButton" id="media_insert_button">
         <property name="visible">True</property>
-        <property name="sensitive">False</property>
         <property name="can_focus">False</property>
-        <property name="has_tooltip">True</property>
-        <property name="tooltip_markup" translatable="yes">Insert the selected clips at the end of the 
timeline</property>
         <property name="tooltip_text" translatable="yes">Insert the selected clips at the end of the 
timeline</property>
+        <property name="action_name">medialibrary.insert_assets_at_end</property>
         <property name="label" translatable="yes">Insert at _End of Timeline</property>
         <property name="use_underline">True</property>
         <property name="icon_name">insert-object-symbolic</property>
-        <signal name="clicked" handler="_insertEndCb" swapped="no"/>
         <child internal-child="accessible">
           <object class="AtkObject" id="media_insert_button-atkobject">
             <property name="AtkObject::accessible-name">media_insert_button</property>
@@ -125,7 +115,6 @@
           <object class="GtkEntry" id="media_search_entry">
             <property name="visible">True</property>
             <property name="can_focus">True</property>
-            <property name="has_tooltip">True</property>
             <property name="margin_start">3</property>
             <property name="invisible_char">•</property>
             <property name="primary_icon_name">starred-symbolic</property>
@@ -185,7 +174,6 @@
             <property name="visible">True</property>
             <property name="can_focus">True</property>
             <property name="receives_default">True</property>
-            <property name="has_tooltip">True</property>
             <property name="tooltip_text" translatable="yes">Close this message</property>
             <signal name="clicked" handler="_warningInfoBarDismissedCb" swapped="no"/>
           </object>
@@ -215,8 +203,8 @@
           <object class="GtkLabel" id="warning_label">
             <property name="visible">True</property>
             <property name="can_focus">False</property>
-            <property name="xalign">0</property>
             <property name="wrap">True</property>
+            <property name="xalign">0</property>
           </object>
           <packing>
             <property name="expand">False</property>
@@ -267,9 +255,9 @@
           <object class="GtkLabel" id="label1">
             <property name="visible">True</property>
             <property name="can_focus">False</property>
-            <property name="xalign">0</property>
             <property name="label" translatable="yes">Add media to your project by dragging files and 
folders here or by using the "Import" button.</property>
             <property name="wrap">True</property>
+            <property name="xalign">0</property>
           </object>
           <packing>
             <property name="expand">False</property>
diff --git a/data/ui/timelinetoolbar.ui b/data/ui/timelinetoolbar.ui
new file mode 100644
index 0000000..a610d82
--- /dev/null
+++ b/data/ui/timelinetoolbar.ui
@@ -0,0 +1,133 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.19.0 -->
+<interface>
+  <requires lib="gtk+" version="3.16"/>
+  <object class="GtkToolbar" id="timeline_toolbar">
+    <property name="visible">True</property>
+    <property name="can_focus">False</property>
+    <property name="valign">start</property>
+    <property name="orientation">vertical</property>
+    <property name="toolbar_style">icons</property>
+    <child>
+      <object class="GtkToolButton" id="toolbutton1">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="tooltip_text" translatable="yes">Split clips at playhead position</property>
+        <property name="action_name">timeline.split_clips</property>
+        <property name="label" translatable="yes">Split</property>
+        <property name="use_underline">True</property>
+        <property name="stock_id">pitivi-split</property>
+      </object>
+      <packing>
+        <property name="expand">False</property>
+        <property name="homogeneous">True</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkToolButton" id="toolbutton2">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="tooltip_text" translatable="yes">Delete clips</property>
+        <property name="action_name">timeline.delete_selected_clips</property>
+        <property name="label" translatable="yes">Delete</property>
+        <property name="use_underline">True</property>
+        <property name="stock_id">gtk-delete</property>
+      </object>
+      <packing>
+        <property name="expand">False</property>
+        <property name="homogeneous">True</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkToolButton" id="toolbutton3">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="tooltip_text" translatable="yes">Group clips</property>
+        <property name="action_name">timeline.group_selected_clips</property>
+        <property name="label" translatable="yes">Group</property>
+        <property name="use_underline">True</property>
+        <property name="stock_id">pitivi-group</property>
+      </object>
+      <packing>
+        <property name="expand">False</property>
+        <property name="homogeneous">True</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkToolButton" id="toolbutton4">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="tooltip_text" translatable="yes">Ungroup clips</property>
+        <property name="action_name">timeline.ungroup_selected_clips</property>
+        <property name="label" translatable="yes">Ungroup</property>
+        <property name="use_underline">True</property>
+        <property name="stock_id">pitivi-ungroup</property>
+      </object>
+      <packing>
+        <property name="expand">False</property>
+        <property name="homogeneous">True</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkToolButton" id="toolbutton5">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="tooltip_text" translatable="yes">Copy clips</property>
+        <property name="action_name">timeline.copy_selected_clips</property>
+        <property name="use_underline">True</property>
+        <property name="stock_id">gtk-copy</property>
+      </object>
+      <packing>
+        <property name="expand">False</property>
+        <property name="homogeneous">True</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkToolButton" id="toolbutton6">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="tooltip_text" translatable="yes">Paste clips</property>
+        <property name="action_name">timeline.paste_clips</property>
+        <property name="use_underline">True</property>
+        <property name="stock_id">gtk-paste</property>
+      </object>
+      <packing>
+        <property name="expand">False</property>
+        <property name="homogeneous">True</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkToolButton" id="toolbutton7">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="tooltip_text" translatable="yes">Align clips based on their soundtracks</property>
+        <property name="visible_horizontal">False</property>
+        <property name="visible_vertical">False</property>
+        <property name="action_name">timeline.align_selected_clips</property>
+        <property name="label" translatable="yes">Align</property>
+        <property name="use_underline">True</property>
+        <property name="stock_id">pitivi-align</property>
+      </object>
+      <packing>
+        <property name="expand">False</property>
+        <property name="homogeneous">True</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkToggleToolButton" id="gapless_button">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="tooltip_text" translatable="yes">Toggle gapless mode
+When enabled, adjacent clips automatically move to fill gaps.</property>
+        <property name="action_name">timeline.toggle_gapless_mode</property>
+        <property name="label" translatable="yes">Gapless mode</property>
+        <property name="use_underline">True</property>
+        <property name="stock_id">pitivi-gapless</property>
+      </object>
+      <packing>
+        <property name="expand">False</property>
+        <property name="homogeneous">True</property>
+      </packing>
+    </child>
+  </object>
+</interface>
diff --git a/pitivi/effects.py b/pitivi/effects.py
index c724508..8c777bd 100644
--- a/pitivi/effects.py
+++ b/pitivi/effects.py
@@ -287,7 +287,7 @@ class EffectListWidget(Gtk.Box, Loggable):
 
     """ Widget for listing effects """
 
-    def __init__(self, instance, unused_uiman):
+    def __init__(self, instance):
         Gtk.Box.__init__(self)
         Loggable.__init__(self)
 
diff --git a/pitivi/mainwindow.py b/pitivi/mainwindow.py
index 879765e..5cf2d27 100644
--- a/pitivi/mainwindow.py
+++ b/pitivi/mainwindow.py
@@ -136,11 +136,9 @@ class PitiviMainWindow(Gtk.ApplicationWindow, Loggable):
 
         self.connect("destroy", self._destroyedCb)
 
-        self.uimanager = Gtk.UIManager()
         self.setupCss()
         self.builder_handler_ids = []
         self.builder = Gtk.Builder()
-        self.add_accel_group(self.uimanager.get_accel_group())
 
         self._createUi()
         self.recent_manager = Gtk.RecentManager()
@@ -292,8 +290,8 @@ class PitiviMainWindow(Gtk.ApplicationWindow, Loggable):
 
         # First set of tabs
         self.main_tabs = BaseTabs(self.app)
-        self.medialibrary = MediaLibraryWidget(self.app, self.uimanager)
-        self.effectlist = EffectListWidget(self.app, self.uimanager)
+        self.medialibrary = MediaLibraryWidget(self.app)
+        self.effectlist = EffectListWidget(self.app)
         self.main_tabs.append_page(
             self.medialibrary, Gtk.Label(label=_("Media Library")))
         self.main_tabs.append_page(
@@ -330,7 +328,7 @@ class PitiviMainWindow(Gtk.ApplicationWindow, Loggable):
         self.mainhpaned.pack2(self.viewer, resize=True, shrink=False)
 
         # Now, the lower part: the timeline
-        self.timeline_ui = TimelineContainer(self, self.app, self.uimanager)
+        self.timeline_ui = TimelineContainer(self, self.app)
         self.timeline_ui.setProjectManager(self.app.project_manager)
         self.vpaned.pack2(self.timeline_ui, resize=True, shrink=False)
 
@@ -373,7 +371,7 @@ class PitiviMainWindow(Gtk.ApplicationWindow, Loggable):
         self.connect("configure-event", self._configureCb)
 
         # Focus the timeline by default!
-        self.timeline_ui.grab_focus()
+        self.focusTimeline()
         self.updateTitle()
 
     def _setDefaultPositions(self):
@@ -435,7 +433,10 @@ class PitiviMainWindow(Gtk.ApplicationWindow, Loggable):
         self.context_tabs.set_current_page(page)
 
     def focusTimeline(self):
-        self.timeline_ui.grab_focus()
+        layers_representation = self.timeline_ui.timeline.layout
+        # Check whether it has focus already, grab_focus always emits an event.
+        if not layers_representation.props.is_focus:
+            layers_representation.grab_focus()
 
     def _create_headerbar_buttons(self):
         undo_button = Gtk.Button.new_from_icon_name(
@@ -479,15 +480,6 @@ class PitiviMainWindow(Gtk.ApplicationWindow, Loggable):
         self._headerbar.pack_start(self.render_button)
 
     def _set_keyboard_shortcuts(self):
-        """
-        You can't rely on Glade/GTKBuilder to set accelerators properly
-        on menu items or buttons, it just doesn't work.
-        GAction and GActionGroup are overkill and a massive PITA.
-
-        This code keeps things *really* simple, and it actually works.
-        Bonus points: the accelerators disable themselves when buttons or
-        menu items are set_sensitive(False), which is exactly what we want.
-        """
         self.save_action = Gio.SimpleAction.new("save", None)
         self.save_action.connect("activate", self._saveProjectCb)
         self.add_action(self.save_action)
@@ -1323,11 +1315,11 @@ class PitiviMainWindow(Gtk.ApplicationWindow, Loggable):
 
     def __titleTypeCb(self, widget, event, project):
         if event.keyval == Gdk.KEY_Return:
-            self.timeline_ui.grab_focus()
+            self.focusTimeline()
             return True
         elif event.keyval == Gdk.KEY_Escape:
             widget.set_text(project.name)
-            self.timeline_ui.grab_focus()
+            self.focusTimeline()
             return True
         return False
 
diff --git a/pitivi/medialibrary.py b/pitivi/medialibrary.py
index a9f07a6..7b1d567 100644
--- a/pitivi/medialibrary.py
+++ b/pitivi/medialibrary.py
@@ -85,13 +85,6 @@ STORE_MODEL_STRUCTURE = (
  COL_LENGTH,
  COL_SEARCH_TEXT) = list(range(len(STORE_MODEL_STRUCTURE)))
 
-ui = '''
-<ui>
-    <accelerator action="RemoveSources" />
-    <accelerator action="InsertEnd" />
-</ui>
-'''
-
 # This whitelist is made from personal knowledge of file extensions in the wild,
 # from gst-inspect |grep demux,
 # http://en.wikipedia.org/wiki/Comparison_of_container_formats and
@@ -116,7 +109,7 @@ class MediaLibraryWidget(Gtk.Box, Loggable):
         'play': (GObject.SignalFlags.RUN_LAST, None,
                  (GObject.TYPE_PYOBJECT,))}
 
-    def __init__(self, app, uiman):
+    def __init__(self, app):
         Gtk.Box.__init__(self)
         Loggable.__init__(self)
 
@@ -129,6 +122,8 @@ class MediaLibraryWidget(Gtk.Box, Loggable):
         self._draggedPaths = None
         self.dragged = False
         self.clip_view = self.app.settings.lastClipView
+        if self.clip_view not in (SHOW_TREEVIEW, SHOW_ICONVIEW):
+            self.clip_view = SHOW_ICONVIEW
         self.import_start_time = time.time()
         self._last_imported_uris = []
 
@@ -150,9 +145,7 @@ class MediaLibraryWidget(Gtk.Box, Loggable):
         toolbar = builder.get_object("medialibrary_toolbar")
         toolbar.get_style_context().add_class(Gtk.STYLE_CLASS_INLINE_TOOLBAR)
         self._import_button = builder.get_object("media_import_button")
-        self._remove_button = builder.get_object("media_remove_button")
         self._clipprops_button = builder.get_object("media_props_button")
-        self._insert_button = builder.get_object("media_insert_button")
         self._listview_button = builder.get_object("media_listview_button")
         searchEntry = builder.get_object("media_search_entry")
 
@@ -289,19 +282,20 @@ class MediaLibraryWidget(Gtk.Box, Loggable):
         # Hack so that the views have the same method as self
         self.treeview.getSelectedItems = self.getSelectedItems
 
-        # Keyboard shortcuts for some items in the gtkbuilder file
-        selection_actions = (
-            ("RemoveSources", Gtk.STOCK_DELETE, _("_Remove from Project"),
-             "<Control>Delete", None, self._removeSourcesCb),
+        actions_group = Gio.SimpleActionGroup()
+        self.insert_action_group("medialibrary", actions_group)
+
+        self.remove_assets_action = Gio.SimpleAction.new("remove_assets", None)
+        self.remove_assets_action.connect("activate", self._removeAssetsCb)
+        actions_group.add_action(self.remove_assets_action)
+        self.app.add_accelerator("<Control>Delete", "medialibrary.remove_assets", None)
+
+        self.insert_at_end_action = Gio.SimpleAction.new("insert_assets_at_end", None)
+        self.insert_at_end_action.connect("activate", self._insertEndCb)
+        actions_group.add_action(self.insert_at_end_action)
+        self.app.add_accelerator("Insert", "medialibrary.insert_assets_at_end", None)
 
-            ("InsertEnd", Gtk.STOCK_COPY, _("Insert at _End of Timeline"),
-             "Insert", None, self._insertEndCb),
-        )
-        self.selection_actions = Gtk.ActionGroup(name="medialibraryselection")
-        self.selection_actions.add_actions(selection_actions)
-        self.selection_actions.set_sensitive(False)
-        uiman.insert_action_group(self.selection_actions, 0)
-        uiman.add_ui_from_string(ui)
+        self._updateActions()
 
         # Set the state of the view mode toggle button.
         self._listview_button.set_active(self.clip_view == SHOW_TREEVIEW)
@@ -350,10 +344,10 @@ class MediaLibraryWidget(Gtk.Box, Loggable):
             info = asset.get_info()
             asset_uri = info.get_uri()
             if asset_uri == uri:
-                self.debug("Found asset: %s for uri: %s" % (asset, uri))
+                self.debug("Found asset: %s for uri: %s", asset, uri)
                 return asset
 
-        self.warning("Did not find any asser for uri: %s" % (uri))
+        self.warning("Did not find any asset for uri: %s", uri)
 
     def _setupViewAsDragAndDropSource(self, view):
         view.drag_source_set(0, [], Gdk.DragAction.COPY)
@@ -367,10 +361,27 @@ class MediaLibraryWidget(Gtk.Box, Loggable):
     def _importSourcesCb(self, unused_action):
         self._showImportSourcesDialog()
 
-    def _removeSourcesCb(self, unused_action):
-        self._removeSources()
+    def _removeAssetsCb(self, unused_action, unused_parameter):
+        """
+        Determine which clips are selected in the icon or list view,
+        and ask MediaLibrary to remove them from the project.
+        """
+        model = self.treeview.get_model()
+        paths = self.getSelectedPaths()
+        if not paths:
+            return
+        # use row references so we don't have to care if a path has been
+        # removed
+        rows = [Gtk.TreeRowReference.new(model, path)
+                for path in paths]
 
-    def _insertEndCb(self, unused_action):
+        self.app.action_log.begin("remove asset from media library")
+        for row in rows:
+            asset = model[row.get_path()][COL_ASSET]
+            self.app.project_manager.current_project.remove_asset(asset)
+        self.app.action_log.commit()
+
+    def _insertEndCb(self, unused_action, unused_parameter):
         self.app.gui.timeline_ui.insertAssets(self.getSelectedAssets(), -1)
 
     def _searchEntryChangedCb(self, entry):
@@ -386,6 +397,11 @@ class MediaLibraryWidget(Gtk.Box, Loggable):
             entry.set_text("")
         elif icon_pos == Gtk.EntryIconPosition.PRIMARY:
             self._selectUnusedSources()
+            # Focus the container so the user can use Ctrl+Delete, for example.
+            if self.clip_view == SHOW_TREEVIEW:
+                self.treeview.grab_focus()
+            elif self.clip_view == SHOW_ICONVIEW:
+                self.iconview.grab_focus()
 
     def _setRowVisible(self, model, iter, data):
         """
@@ -792,28 +808,6 @@ class MediaLibraryWidget(Gtk.Box, Loggable):
             dialogbox.destroy()
             self._importDialog = None
 
-    def _removeSources(self):
-        """
-        Determine which clips are selected in the icon or list view,
-        and ask MediaLibrary to remove them from the project.
-        """
-        model = self.treeview.get_model()
-        paths = self.getSelectedPaths()
-        if not paths:
-            return
-        # use row references so we don't have to care if a path has been
-        # removed
-        rows = []
-        for path in paths:
-            row = Gtk.TreeRowReference.new(model, path)
-            rows.append(row)
-
-        self.app.action_log.begin("remove clip from source list")
-        for row in rows:
-            asset = model[row.get_path()][COL_ASSET]
-            self.app.project_manager.current_project.remove_asset(asset)
-        self.app.action_log.commit()
-
     def _sourceIsUsed(self, asset):
         """Check if a given URI is present in the timeline"""
         layers = self.app.project_manager.current_project.timeline.get_layers()
@@ -825,7 +819,7 @@ class MediaLibraryWidget(Gtk.Box, Loggable):
 
     def _selectUnusedSources(self):
         """
-        Select, in the media library, unused sources in the project.
+        Select the assets not used by any clip in the project's timeline.
         """
         project = self.app.project_manager.current_project
         unused_sources_uris = []
@@ -858,10 +852,6 @@ class MediaLibraryWidget(Gtk.Box, Loggable):
             self.app.gui.showProjectSettingsDialog()
         infobar.hide()
 
-    def _removeClickedCb(self, unused_widget=None):
-        """ Called when a user clicks on the remove button """
-        self._removeSources()
-
     def _clipPropertiesCb(self, unused_widget=None):
         """
         Show the clip properties (resolution, framerate, audio channels...)
@@ -1005,20 +995,14 @@ class MediaLibraryWidget(Gtk.Box, Loggable):
                 ts.select_path(path[0])
 
     def _viewSelectionChangedCb(self, unused):
-        selected_items = len(self.getSelectedPaths())
-        if selected_items:
-            self.selection_actions.set_sensitive(True)
-            self._remove_button.set_sensitive(True)
-            self._insert_button.set_sensitive(True)
-            # Some actions can only be done on a single item at a time:
-            self._clipprops_button.set_sensitive(False)
-            if selected_items == 1:
-                self._clipprops_button.set_sensitive(True)
-        else:
-            self.selection_actions.set_sensitive(False)
-            self._remove_button.set_sensitive(False)
-            self._insert_button.set_sensitive(False)
-            self._clipprops_button.set_sensitive(False)
+        self._updateActions()
+
+    def _updateActions(self):
+        selected_count = len(self.getSelectedPaths())
+        self.remove_assets_action.set_enabled(selected_count)
+        self.insert_at_end_action.set_enabled(selected_count)
+        # Some actions can only be done on a single item at a time:
+        self._clipprops_button.set_sensitive(selected_count == 1)
 
     def _itemOrRowActivatedCb(self, unused_view, path, *unused_column):
         """
diff --git a/pitivi/preset.py b/pitivi/preset.py
index 0a824cd..9c3193f 100644
--- a/pitivi/preset.py
+++ b/pitivi/preset.py
@@ -99,19 +99,19 @@ class PresetManager(GObject.Object, Loggable):
 
         action = Gio.SimpleAction.new("new", None)
         action.connect("activate", self._addPresetCb)
-        action_group.insert(action)
+        action_group.add_action(action)
         menu_model.append(_("New"), "preset.%s" % action.get_name())
         self.action_new = action
 
         action = Gio.SimpleAction.new("remove", None)
         action.connect("activate", self._removePresetCb)
-        action_group.insert(action)
+        action_group.add_action(action)
         menu_model.append(_("Remove"), "preset.%s" % action.get_name())
         self.action_remove = action
 
         action = Gio.SimpleAction.new("save", None)
         action.connect("activate", self._savePresetCb)
-        action_group.insert(action)
+        action_group.add_action(action)
         menu_model.append(_("Save"), "preset.%s" % action.get_name())
         self.action_save = action
 
diff --git a/pitivi/timeline/layer.py b/pitivi/timeline/layer.py
index e7c77e5..5b623ae 100644
--- a/pitivi/timeline/layer.py
+++ b/pitivi/timeline/layer.py
@@ -225,31 +225,31 @@ class LayerControls(Gtk.EventBox, Loggable):
         self.__move_layer_top_action = Gio.SimpleAction.new("move_layer_to_top", None)
         action = self.__move_layer_top_action
         action.connect("activate", self._moveLayerCb, -2)
-        action_group.insert(action)
+        action_group.add_action(action)
         menu_model.append(_("Move layer to top"), "layer.%s" % action.get_name().replace(" ", "."))
 
         self.__move_layer_up_action = Gio.SimpleAction.new("move_layer_up", None)
         action = self.__move_layer_up_action
         action.connect("activate", self._moveLayerCb, -1)
-        action_group.insert(action)
+        action_group.add_action(action)
         menu_model.append(_("Move layer up"), "layer.%s" % action.get_name().replace(" ", "."))
 
         self.__move_layer_down_action = Gio.SimpleAction.new("move_layer_down", None)
         action = self.__move_layer_down_action
         action.connect("activate", self._moveLayerCb, 1)
-        action_group.insert(action)
+        action_group.add_action(action)
         menu_model.append(_("Move layer down"), "layer.%s" % action.get_name().replace(" ", "."))
 
         self.__move_layer_bottom_action = Gio.SimpleAction.new("move_layer_to_bottom", None)
         action = self.__move_layer_bottom_action
         action.connect("activate", self._moveLayerCb, 2)
-        action_group.insert(action)
+        action_group.add_action(action)
         menu_model.append(_("Move layer to bottom"), "layer.%s" % action.get_name().replace(" ", "."))
 
         self.__delete_layer_action = Gio.SimpleAction.new("delete_layer", None)
         action = self.__delete_layer_action
         action.connect("activate", self._deleteLayerCb)
-        action_group.insert(action)
+        action_group.add_action(action)
         menu_model.append(_("Delete layer"), "layer.%s" % action.get_name())
 
         return menu_model, action_group
diff --git a/pitivi/timeline/ruler.py b/pitivi/timeline/ruler.py
index fc2040e..4d0997b 100644
--- a/pitivi/timeline/ruler.py
+++ b/pitivi/timeline/ruler.py
@@ -72,11 +72,6 @@ class ScaleRuler(Gtk.DrawingArea, Zoomable, Loggable):
         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.timeline = timeline
         self._background_color = timeline.get_style_context().lookup_color(
             'theme_bg_color')[1]
@@ -113,14 +108,6 @@ class ScaleRuler(Gtk.DrawingArea, Zoomable, Loggable):
 
         self.scales = SCALES
 
-    def _focusInCb(self, unused_widget, unused_arg):
-        self.log("Ruler has grabbed focus")
-        self.timeline.setActionsSensitivity(True)
-
-    def _focusOutCb(self, unused_widget, unused_arg):
-        self.log("Ruler has lost focus")
-        self.timeline.setActionsSensitivity(False)
-
     def _hadjValueChangedCb(self, unused_arg):
         self.pixbuf_offset = self.hadj.get_value()
         self.queue_draw()
@@ -182,7 +169,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.app.gui.focusTimeline()
         return False
 
     def do_motion_notify_event(self, event):
diff --git a/pitivi/timeline/timeline.py b/pitivi/timeline/timeline.py
index bf5254e..ae98d42 100644
--- a/pitivi/timeline/timeline.py
+++ b/pitivi/timeline/timeline.py
@@ -212,15 +212,13 @@ class Marquee(Gtk.Box, Loggable):
 
 class Timeline(Gtk.EventBox, Zoomable, Loggable):
     """
-    The main timeline Widget, it contains the representation of the GESTimeline
-    without any extra widgets.
+    Contains the layer controls and the layers representation.
     """
 
     __gtype_name__ = "PitiviTimeline"
 
     def __init__(self, container, app):
-        super(Timeline, self).__init__()
-
+        Gtk.EventBox.__init__(self)
         Zoomable.__init__(self)
         Loggable.__init__(self)
 
@@ -229,12 +227,16 @@ class Timeline(Gtk.EventBox, Zoomable, Loggable):
         self._project = None
         self.bTimeline = None
 
+        self.props.can_focus = False
+
         hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL)
         self.add(hbox)
 
         # Stuff the layers representation in a Layout so we can have other
         # widgets there, see below.
         self.layout = Gtk.Layout()
+        self.layout.props.can_focus = True
+        self.layout.props.can_default = True
         self.__layers_vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
         self.__layers_vbox.props.width_request = self.get_allocated_width()
         self.__layers_vbox.props.height_request = self.get_allocated_height()
@@ -587,9 +589,10 @@ class Timeline(Gtk.EventBox, Zoomable, Loggable):
         return False
 
     def __buttonPressEventCb(self, unused_widget, event):
+        self.debug("PRESSED %s", event)
+        self.app.gui.focusTimeline()
         event_widget = self.get_event_widget(event)
 
-        self.debug("PRESSED %s", event)
         res, button = event.get_button()
         if res and button == 1:
             self.draggingElement = self._getParentOfType(event_widget, Clip)
@@ -1121,28 +1124,23 @@ class TimelineContainer(Gtk.Grid, Zoomable, Loggable):
     Container for zoom box, ruler, timeline, scrollbars and toolbar.
     """
 
-    def __init__(self, gui, instance, ui_manager):
+    def __init__(self, gui, instance):
         Zoomable.__init__(self)
         Gtk.Grid.__init__(self)
         Loggable.__init__(self)
 
-        # Allows stealing focus from other GTK widgets, prevent accidents:
-        self.props.can_focus = True
-
         self.gui = gui
-        self.ui_manager = ui_manager
         self.app = instance
         self._settings = self.app.settings
+        self._autoripple_active = self._settings.timelineAutoRipple
 
         self._projectmanager = None
         self._project = None
         self.bTimeline = None
         self.__copiedGroup = None
 
-        self.ui_manager.add_ui_from_file(
-            os.path.join(get_ui_dir(), "timelinecontainer.xml"))
-        self._createActions()
         self._createUi()
+        self._createActions()
 
         self._settings.connect("edgeSnapDeadbandChanged",
                                self._snapDistanceChangedCb)
@@ -1269,21 +1267,17 @@ class TimelineContainer(Gtk.Grid, 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)
-
-        sensitive = sensitive and self.timeline.selection
-        self.selection_actions.set_sensitive(sensitive)
-        self.debug("Editing shortcuts sensitivity set to %s", sensitive)
+    def updateActions(self):
+        selection_non_empty = bool(self.timeline.selection)
+        self.delete_action.set_enabled(selection_non_empty)
+        self.group_action.set_enabled(selection_non_empty)
+        self.ungroup_action.set_enabled(selection_non_empty)
+        self.copy_action.set_enabled(selection_non_empty)
+        can_paste = bool(self.__copiedGroup and
+                         self.__copiedGroup.get_children(True))
+        self.paste_action.set_enabled(can_paste)
+        self.align_action.set_enabled(selection_non_empty)
+        self.keyframe_action.set_enabled(selection_non_empty)
 
     # Internal API
 
@@ -1308,14 +1302,15 @@ class TimelineContainer(Gtk.Grid, Zoomable, Loggable):
         self.ruler.setProjectFrameRate(24.)
         self.ruler.hide()
 
-        toolbar = self.ui_manager.get_widget("/TimelineToolBar")
-        toolbar.get_style_context().add_class(Gtk.STYLE_CLASS_INLINE_TOOLBAR)
-        toolbar.set_orientation(Gtk.Orientation.VERTICAL)
-        toolbar.set_style(Gtk.ToolbarStyle.ICONS)
-        toolbar.get_accessible().set_name("timeline toolbar")
+        builder = Gtk.Builder()
+        builder.add_from_file(os.path.join(get_ui_dir(), "timelinetoolbar.ui"))
+        self.toolbar = builder.get_object("timeline_toolbar")
+        self.toolbar.get_style_context().add_class(Gtk.STYLE_CLASS_INLINE_TOOLBAR)
+        self.toolbar.get_accessible().set_name("timeline toolbar")
+
+        self.gapless_button = builder.get_object("gapless_button")
+        self.gapless_button.set_active(self._autoripple_active)
 
-        alter_style_class(".%s" % Gtk.STYLE_CLASS_INLINE_TOOLBAR, toolbar,
-                          "padding-left: %dpx; border-width: 0px; background: alpha (@base_color, 0.0);" % 
(SPACING / 2))
         alter_style_class(
             ".%s.trough" % Gtk.STYLE_CLASS_SCROLLBAR, self._vscrollbar,
             "border: alpha (@base_color, 0.0); background: alpha (@base_color, 0.0);")
@@ -1323,24 +1318,12 @@ class TimelineContainer(Gtk.Grid, Zoomable, Loggable):
             ".%s.trough" % Gtk.STYLE_CLASS_SCROLLBAR, self._hscrollbar,
             "border: alpha (@base_color, 0.0); background: alpha (@base_color, 0.0);")
 
-        # Toggle/pushbuttons like the "gapless mode" ones are special, it seems
-        # you can't insert them as normal "actions", so we create them here:
-        gapless_mode_button = Gtk.ToggleToolButton()
-        gapless_mode_button.set_stock_id("pitivi-gapless")
-        gapless_mode_button.set_tooltip_markup(_("Toggle gapless mode\n"
-                                                 "When enabled, adjacent clips automatically move to fill 
gaps."))
-        toolbar.add(gapless_mode_button)
-        # Restore the state of the timeline's "gapless" mode:
-        self._autoripple_active = self._settings.timelineAutoRipple
-        gapless_mode_button.set_active(self._autoripple_active)
-        gapless_mode_button.connect("toggled", self._gaplessmodeToggledCb)
-
         self.attach(self.zoomBox, 0, 0, 1, 1)
         self.attach(self.ruler, 1, 0, 1, 1)
         self.attach(self.timeline, 0, 1, 2, 1)
         self.attach(self._vscrollbar, 2, 1, 1, 1)
         self.attach(self._hscrollbar, 1, 2, 1, 1)
-        self.attach(toolbar, 3, 1, 1, 1)
+        self.attach(self.toolbar, 3, 1, 1, 1)
 
         min_height = (self.ruler.get_size_request()[1] +
                       (EXPANDED_SIZE + SPACING) * 2 +
@@ -1396,91 +1379,86 @@ class TimelineContainer(Gtk.Grid, Zoomable, Loggable):
         return longest_layer
 
     def _createActions(self):
-        """
-        Sets up the GtkActions. This allows managing the sensitivity of widgets
-        to the mouse and keyboard shortcuts.
-        """
-        # TODO: use GAction + GActionGroup (Gio.SimpleAction +
-        # Gio.SimpleActionGroup)
-
-        # Action list items can vary in size (1-6 items). The first one is the
-        # name, and it is the only mandatory option. All the other options are
-        # optional, and if omitted will default to None.
-        #
-        # name (required), stock ID, translatable label,
-        # keyboard shortcut, translatable tooltip, callback function
-        zoom_in_tooltip = _("Zoom In")
-        zoom_out_tooltip = _("Zoom Out")
-        zoom_fit_tooltip = _("Zoom Fit")
-        actions = (
-            ("ZoomIn", Gtk.STOCK_ZOOM_IN, None,
-             "<Control>plus", zoom_in_tooltip, self._zoomInCb),
-
-            ("ZoomOut", Gtk.STOCK_ZOOM_OUT, None,
-             "<Control>minus", zoom_out_tooltip, self._zoomOutCb),
-
-            ("ZoomFit", Gtk.STOCK_ZOOM_FIT, None,
-             "<Control>0", zoom_fit_tooltip, self._zoomFitCb),
-
-            # Alternate keyboard shortcuts to the actions above
-            ("ControlEqualAccel", Gtk.STOCK_ZOOM_IN, None,
-             "<Control>equal", zoom_in_tooltip, self._zoomInCb),
-
-            ("ControlKPAddAccel", Gtk.STOCK_ZOOM_IN, None,
-             "<Control>KP_Add", zoom_in_tooltip, self._zoomInCb),
-
-            ("ControlKPSubtractAccel", Gtk.STOCK_ZOOM_OUT, None,
-             "<Control>KP_Subtract", zoom_out_tooltip, self._zoomOutCb),
-        )
-
-        selection_actions = (
-            ("DeleteObj", Gtk.STOCK_DELETE, None,
-             "Delete", _("Delete Selected"), self._deleteSelected),
-
-            ("UngroupObj", "pitivi-ungroup", _("Ungroup"),
-             "<Shift><Control>G", _("Ungroup clips"), self._ungroupSelected),
-
-            # Translators: This is an action, the title of a button
-            ("GroupObj", "pitivi-group", _("Group"),
-             "<Control>G", _("Group clips"), self._groupSelected),
-
-            ("Copy", "copy", _("Copy"),
-             "<Control>c", _("Copy clips"), self.__copyClipsCb),
-
-            ("Paste", "paste", _("Paste"),
-             "<Control>v", _("Paste clips"), self.__pasteClipsCb),
-
-            # TODO: Fix the align feature.
-            # ("AlignObj", "pitivi-align", _("Align"),
-            #  "<Shift><Control>A", _("Align clips based on their soundtracks"), self._alignSelected),
-        )
-
-        playhead_actions = (
-            ("PlayPause", Gtk.STOCK_MEDIA_PLAY, None,
-             "space", _("Start Playback"), self._playPauseCb),
-
-            ("Split", "pitivi-split", _("Split"),
-             "S", _("Split clip at playhead position"), self._splitCb),
-
-            ("Keyframe", "pitivi-keyframe", _("Add a Keyframe"),
-             "K", _("Add a keyframe"), self._keyframeCb),
-        )
-
-        actiongroup = Gtk.ActionGroup(name="timelinepermanent")
-        self.selection_actions = Gtk.ActionGroup(name="timelineselection")
-        self.playhead_actions = Gtk.ActionGroup(name="timelineplayhead")
-
-        actiongroup.add_actions(actions)
-
-        self.ui_manager.insert_action_group(actiongroup, 0)
-        self.selection_actions.add_actions(selection_actions)
-        self.selection_actions.set_sensitive(False)
-        self.ui_manager.insert_action_group(self.selection_actions, -1)
-        self.playhead_actions.add_actions(playhead_actions)
-        self.ui_manager.insert_action_group(self.playhead_actions, -1)
-
-        self.selection_actions.get_action("Copy").set_gicon(Gio.Icon.new_for_string("edit-copy"))
-        self.selection_actions.get_action("Paste").set_gicon(Gio.Icon.new_for_string("edit-paste"))
+        # The actions below are all added to this action group and they
+        # are accessible only to the self.timeline.layout and self.toolbar
+        # widgets (and their children) using the "timeline" prefix.
+        # When the action for an accelerator is searched, due to the "timeline"
+        # prefix, the accelerators work only when the focus is on one of these
+        # two widgets: the layout with the layers representation (excluding the
+        # controls) and the timeline toolbar.
+        group = Gio.SimpleActionGroup()
+        self.timeline.layout.insert_action_group("timeline", group)
+        self.toolbar.insert_action_group("timeline", group)
+
+        self.zoom_in_action = Gio.SimpleAction.new("zoom_in", None)
+        self.zoom_in_action.connect("activate", self._zoomInCb)
+        group.add_action(self.zoom_in_action)
+        self.app.add_accelerator("<Control>plus", "timeline.zoom_in", None)
+        self.app.add_accelerator("<Control>equal", "timeline.zoom_in", None)
+        self.app.add_accelerator("<Control>KP_Add", "timeline.zoom_in", None)
+
+        self.zoom_out_action = Gio.SimpleAction.new("zoom_out", None)
+        self.zoom_out_action.connect("activate", self._zoomOutCb)
+        group.add_action(self.zoom_out_action)
+        self.app.add_accelerator("<Control>minus", "timeline.zoom_out", None)
+        self.app.add_accelerator("<Control>KP_Subtract", "timeline.zoom_out", None)
+
+        self.zoom_fit_action = Gio.SimpleAction.new("zoom_fit", None)
+        self.zoom_fit_action.connect("activate", self._zoomFitCb)
+        group.add_action(self.zoom_fit_action)
+        self.app.add_accelerator("<Control>0", "timeline.zoom_fit", None)
+
+        # Clips actions.
+        self.delete_action = Gio.SimpleAction.new("delete_selected_clips", None)
+        self.delete_action.connect("activate", self._deleteSelected)
+        group.add_action(self.delete_action)
+        self.app.add_accelerator("Delete", "timeline.delete_selected_clips", None)
+
+        self.group_action = Gio.SimpleAction.new("group_selected_clips", None)
+        self.group_action.connect("activate", self._groupSelected)
+        group.add_action(self.group_action)
+        self.app.add_accelerator("<Control>g", "timeline.group_selected_clips", None)
+
+        self.ungroup_action = Gio.SimpleAction.new("ungroup_selected_clips", None)
+        self.ungroup_action.connect("activate", self._ungroupSelected)
+        group.add_action(self.ungroup_action)
+        self.app.add_accelerator("<Shift><Control>g", "timeline.ungroup_selected_clips", None)
+
+        self.copy_action = Gio.SimpleAction.new("copy_selected_clips", None)
+        self.copy_action.connect("activate", self.__copyClipsCb)
+        group.add_action(self.copy_action)
+        self.app.add_accelerator("<Control>c", "timeline.copy_selected_clips", None)
+
+        self.paste_action = Gio.SimpleAction.new("paste_clips", None)
+        self.paste_action.connect("activate", self.__pasteClipsCb)
+        group.add_action(self.paste_action)
+        self.app.add_accelerator("<Control>v", "timeline.paste_clips", None)
+
+        self.align_action = Gio.SimpleAction.new("align_selected_clips", None)
+        self.align_action.connect("activate", self._alignSelectedCb)
+        group.add_action(self.align_action)
+        self.app.add_accelerator("<Shift><Control>a", "timeline.align_selected_clips", None)
+
+        self.gapless_action = Gio.SimpleAction.new("toggle_gapless_mode", None)
+        self.gapless_action.connect("activate", self._gaplessmodeToggledCb)
+        group.add_action(self.gapless_action)
+
+        # Playhead actions.
+        self.play_action = Gio.SimpleAction.new("play", None)
+        self.play_action.connect("activate", self._playPauseCb)
+        group.add_action(self.play_action)
+        self.app.add_accelerator("space", "timeline.play", None)
+
+        self.split_action = Gio.SimpleAction.new("split_clips", None)
+        self.split_action.connect("activate", self._splitCb)
+        group.add_action(self.split_action)
+        self.app.add_accelerator("S", "timeline.split_clips", None)
+        self.split_action.set_enabled(True)
+
+        self.keyframe_action = Gio.SimpleAction.new("keyframe_selected_clips", None)
+        self.keyframe_action.connect("activate", self._keyframeCb)
+        group.add_action(self.keyframe_action)
+        self.app.add_accelerator("K", "timeline.keyframe_selected_clips", None)
 
     def _setBestZoomRatio(self, allow_zoom_in=False):
         """
@@ -1557,7 +1535,7 @@ class TimelineContainer(Gtk.Grid, Zoomable, Loggable):
         self.timeline.queue_draw()
         return False
 
-    def _deleteSelected(self, unused_action):
+    def _deleteSelected(self, unused_action, unused_parameter):
         if self.bTimeline:
             self.app.action_log.begin("delete clip")
 
@@ -1572,7 +1550,7 @@ class TimelineContainer(Gtk.Grid, Zoomable, Loggable):
 
             self.timeline.selection.setSelection([], SELECT)
 
-    def _ungroupSelected(self, unused_action):
+    def _ungroupSelected(self, unused_action, unused_parameter):
         if self.bTimeline:
             self.app.action_log.begin("ungroup")
 
@@ -1589,7 +1567,7 @@ class TimelineContainer(Gtk.Grid, Zoomable, Loggable):
             self.app.action_log.commit()
             self._project.pipeline.commit_timeline()
 
-    def _groupSelected(self, unused_action):
+    def _groupSelected(self, unused_action, unused_parameter):
         if self.bTimeline:
             self.app.action_log.begin("group")
 
@@ -1612,11 +1590,12 @@ class TimelineContainer(Gtk.Grid, Zoomable, Loggable):
             self._project.pipeline.commit_timeline()
             self.app.action_log.commit()
 
-    def __copyClipsCb(self, unused_action):
+    def __copyClipsCb(self, unused_action, unused_parameter):
         if self.timeline.current_group:
             self.__copiedGroup = self.timeline.current_group.copy(True)
+            self.updateActions()
 
-    def __pasteClipsCb(self, unused_action):
+    def __pasteClipsCb(self, unused_action, unused_parameter):
         if self.__copiedGroup:
             save = self.__copiedGroup.copy(True)
             position = self._project.pipeline.getPosition()
@@ -1624,7 +1603,7 @@ class TimelineContainer(Gtk.Grid, Zoomable, Loggable):
             self.__copiedGroup = save
             self._project.pipeline.commit_timeline()
 
-    def _alignSelected(self, unused_action):
+    def _alignSelectedCb(self, unused_action, unused_parameter):
         if not self.bTimeline:
             self.error(
                 "Trying to use the autoalign feature with an empty timeline")
@@ -1647,7 +1626,7 @@ class TimelineContainer(Gtk.Grid, Zoomable, Loggable):
             self.error("Could not start the autoaligner: %s", e)
             progress_dialog.window.destroy()
 
-    def _splitCb(self, unused_action):
+    def _splitCb(self, unused_action, unused_parameter):
         """
         If clips are selected, split them at the current playhead position.
         Otherwise, split all clips at the playhead position.
@@ -1683,7 +1662,7 @@ class TimelineContainer(Gtk.Grid, Zoomable, Loggable):
         if not splitted and splitting_selection:
             self._splitElements()
 
-    def _keyframeCb(self, unused_action):
+    def _keyframeCb(self, unused_action, unused_parameter):
         """
         Add or remove a keyframe at the current position of the selected clip.
         """
@@ -1708,7 +1687,7 @@ class TimelineContainer(Gtk.Grid, Zoomable, Loggable):
                     interpolator.newKeyframe(position_in_obj)
                     self.app.action_log.commit()
 
-    def _playPauseCb(self, unused_action):
+    def _playPauseCb(self, unused_action, unused_parameter):
         self._project.pipeline.togglePlayback()
 
     def transposeXY(self, x, y):
@@ -1750,12 +1729,15 @@ class TimelineContainer(Gtk.Grid, Zoomable, Loggable):
             else:
                 self._project.pipeline.stepFrame(self._framerate, -1)
             self.timeline.scrollToPlayhead(align=Gtk.Align.CENTER, when_not_in_view=True)
+            return True
         elif event.keyval == Gdk.KEY_Right:
             if self._shiftMask:
                 self._seeker.seekRelative(Gst.SECOND)
             else:
                 self._project.pipeline.stepFrame(self._framerate, 1)
             self.timeline.scrollToPlayhead(align=Gtk.Align.CENTER, when_not_in_view=True)
+            return True
+        return False
 
     def do_key_release_event(self, event):
         if event.keyval == Gdk.KEY_Shift_L:
@@ -1765,17 +1747,11 @@ class TimelineContainer(Gtk.Grid, Zoomable, Loggable):
 
     def do_focus_in_event(self, unused_event):
         self.log("Timeline has grabbed focus")
-        self.setActionsSensitivity(True)
+        self.updateActions()
 
     def do_focus_out_event(self, unused_event):
         self.log("Timeline has lost focus")
-        self.setActionsSensitivity(False)
-
-    def do_button_press_event(self, event):
-        self.pressed = True
-        self.grab_focus()  # Prevent other widgets from being confused
-
-        return True
+        self.updateActions()
 
     # Callbacks
     def _renderingSettingsChangedCb(self, project, item, value):
@@ -1838,33 +1814,22 @@ class TimelineContainer(Gtk.Grid, Zoomable, Loggable):
 
         self.setProject(project)
 
-    def _zoomInCb(self, unused_action):
+    def _zoomInCb(self, unused_action, unused_parameter):
         Zoomable.zoomIn()
 
-    def _zoomOutCb(self, unused_action):
+    def _zoomOutCb(self, unused_action, unused_parameter):
         Zoomable.zoomOut()
 
-    def _zoomFitCb(self, unused_action):
+    def _zoomFitCb(self, unused_action, unused_parameter):
         self.zoomFit()
 
     def _selectionChangedCb(self, selection):
         """
-        The selected clips on the timeline canvas have changed with the
-        "selection-changed" signal.
-
-        This is where you apply global UI changes, unlike individual
-        track elements' "selected-changed" signal from the Selected class.
+        The selected clips on the timeline have changed.
         """
-        if selection:
-            self.selection_actions.set_sensitive(True)
-        else:
-            self.selection_actions.set_sensitive(False)
+        self.updateActions()
 
-    def _gaplessmodeToggledCb(self, button):
-        if button.get_active():
-            self.info("Automatic ripple activated")
-            self._autoripple_active = True
-        else:
-            self.info("Automatic ripple deactivated")
-            self._autoripple_active = False
+    def _gaplessmodeToggledCb(self, unused_action, unused_parameter):
+        self._autoripple_active = self.gapless_button.get_active()
+        self.info("Automatic ripple: %s", self._autoripple_active)
         self._settings.timelineAutoRipple = self._autoripple_active


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