← Back to team overview

openlp-core team mailing list archive

[Merge] lp:~googol-hush/openlp/tweaks into lp:openlp

 

Andreas Preikschat has proposed merging lp:~googol-hush/openlp/tweaks into lp:openlp.

Requested reviews:
  Raoul Snyman (raoul-snyman)
  Jonathan Corwin (j-corwin)
  Tim Bentley (trb143)
Related bugs:
  Bug #739779 in OpenLP: "No keyboard shortcut for blank"
  https://bugs.launchpad.net/openlp/+bug/739779

For more details, see:
https://code.launchpad.net/~googol-hush/openlp/tweaks/+merge/57052

Hello

I finished implementing shortcuts, this includes:
- changing shortcuts,
- saving/loading them to the config, so that they will be restored
- shourtcuts can now be easily added/removed to the action list

- fixed bug #739779.
- fixed "+" shortcut in the service manager

Note, if you want to create a shortcut action, add the action to the list, even when you do not want the shortcut to be editable. In this case, just do not specify a category.

Cheers
-- 
https://code.launchpad.net/~googol-hush/openlp/tweaks/+merge/57052
Your team OpenLP Core is subscribed to branch lp:openlp.
=== modified file 'openlp/core/lib/__init__.py'
--- openlp/core/lib/__init__.py	2011-04-02 09:52:32 +0000
+++ openlp/core/lib/__init__.py	2011-04-09 16:26:46 +0000
@@ -166,58 +166,6 @@
             QtGui.QIcon.Normal, QtGui.QIcon.Off)
     return button_icon
 
-def context_menu_action(base, icon, text, slot, shortcuts=None):
-    """
-    Utility method to help build context menus for plugins
-
-    ``base``
-        The parent menu to add this menu item to
-
-    ``icon``
-        An icon for this action
-
-    ``text``
-        The text to display for this action
-
-    ``slot``
-        The code to run when this action is triggered
-    """
-    action = QtGui.QAction(text, base)
-    if icon:
-        action.setIcon(build_icon(icon))
-    QtCore.QObject.connect(action, QtCore.SIGNAL(u'triggered()'), slot)
-    if shortcuts:
-        action.setShortcuts(shortcuts)
-    return action
-
-def context_menu(base, icon, text):
-    """
-    Utility method to help build context menus for plugins
-
-    ``base``
-        The parent object to add this menu to
-
-    ``icon``
-        An icon for this menu
-
-    ``text``
-        The text to display for this menu
-    """
-    action = QtGui.QMenu(text, base)
-    action.setIcon(build_icon(icon))
-    return action
-
-def context_menu_separator(base):
-    """
-    Add a separator to a context menu
-
-    ``base``
-        The menu object to add the separator to
-    """
-    action = QtGui.QAction(u'', base)
-    action.setSeparator(True)
-    return action
-
 def image_to_byte(image):
     """
     Resize an image to fit on the current screen for the web and returns
@@ -343,3 +291,4 @@
 from renderer import Renderer
 from rendermanager import RenderManager
 from mediamanageritem import MediaManagerItem
+from openlp.core.utils.actions import ActionList

=== modified file 'openlp/core/lib/mediamanageritem.py'
--- openlp/core/lib/mediamanageritem.py	2011-04-02 09:52:32 +0000
+++ openlp/core/lib/mediamanageritem.py	2011-04-09 16:26:46 +0000
@@ -31,10 +31,10 @@
 
 from PyQt4 import QtCore, QtGui
 
-from openlp.core.lib import context_menu_action, context_menu_separator, \
-    SettingsManager, OpenLPToolbar, ServiceItem, StringContent, build_icon, \
-    translate, Receiver, ListWidgetWithDnD
-from openlp.core.lib.ui import UiStrings
+from openlp.core.lib import SettingsManager, OpenLPToolbar, ServiceItem, \
+    StringContent, build_icon, translate, Receiver, ListWidgetWithDnD
+from openlp.core.lib.ui import UiStrings, context_menu_action, \
+    context_menu_separator
 
 log = logging.getLogger(__name__)
 
@@ -260,39 +260,42 @@
                 context_menu_action(
                     self.listView, u':/general/general_edit.png',
                     self.plugin.getString(StringContent.Edit)[u'title'],
-                    self.onEditClick))
+                    self.onEditClick, context=QtCore.Qt.WidgetShortcut))
             self.listView.addAction(context_menu_separator(self.listView))
         if self.hasDeleteIcon:
             self.listView.addAction(
                 context_menu_action(
                     self.listView, u':/general/general_delete.png',
                     self.plugin.getString(StringContent.Delete)[u'title'],
-                    self.onDeleteClick, [QtCore.Qt.Key_Delete]))
+                    self.onDeleteClick, [QtCore.Qt.Key_Delete],
+                    context=QtCore.Qt.WidgetShortcut))
             self.listView.addAction(context_menu_separator(self.listView))
         self.listView.addAction(
             context_menu_action(
                 self.listView, u':/general/general_preview.png',
                 self.plugin.getString(StringContent.Preview)[u'title'],
-                self.onPreviewClick, [QtCore.Qt.Key_Enter]))
+                self.onPreviewClick, [QtCore.Qt.Key_Enter],
+                context=QtCore.Qt.WidgetShortcut))
         self.listView.addAction(
             context_menu_action(
                 self.listView, u':/general/general_live.png',
                 self.plugin.getString(StringContent.Live)[u'title'],
                 self.onLiveClick, [QtCore.Qt.ShiftModifier + \
                 QtCore.Qt.Key_Enter, QtCore.Qt.ShiftModifier + \
-                QtCore.Qt.Key_Return]))
+                QtCore.Qt.Key_Return], context=QtCore.Qt.WidgetShortcut))
         self.listView.addAction(
             context_menu_action(
                 self.listView, u':/general/general_add.png',
                 self.plugin.getString(StringContent.Service)[u'title'],
-                self.onAddClick, [QtCore.Qt.Key_Plus, QtCore.Qt.Key_Equal]))
+                self.onAddClick, [QtCore.Qt.Key_Plus, QtCore.Qt.Key_Equal],
+                context=QtCore.Qt.WidgetShortcut))
         if self.addToServiceItem:
             self.listView.addAction(
                 context_menu_action(
                     self.listView, u':/general/general_add.png',
                     translate('OpenLP.MediaManagerItem',
                     '&Add to selected Service Item'),
-                    self.onAddEditClick))
+                    self.onAddEditClick, context=QtCore.Qt.WidgetShortcut))
         QtCore.QObject.connect(self.listView,
             QtCore.SIGNAL(u'doubleClicked(QModelIndex)'),
             self.onClickPressed)

=== modified file 'openlp/core/lib/searchedit.py'
--- openlp/core/lib/searchedit.py	2011-03-24 19:04:02 +0000
+++ openlp/core/lib/searchedit.py	2011-04-09 16:26:46 +0000
@@ -29,6 +29,7 @@
 from PyQt4 import QtCore, QtGui
 
 from openlp.core.lib import build_icon
+from openlp.core.lib.ui import icon_action
 
 log = logging.getLogger(__name__)
 
@@ -132,7 +133,8 @@
         menu = QtGui.QMenu(self)
         first = None
         for identifier, icon, title in items:
-            action = QtGui.QAction(build_icon(icon), title, menu)
+            action = icon_action(menu, u'', icon)
+            action.setText(title)
             action.setData(QtCore.QVariant(identifier))
             menu.addAction(action)
             QtCore.QObject.connect(action, QtCore.SIGNAL(u'triggered(bool)'),

=== modified file 'openlp/core/lib/toolbar.py'
--- openlp/core/lib/toolbar.py	2011-03-24 19:04:02 +0000
+++ openlp/core/lib/toolbar.py	2011-04-09 16:26:46 +0000
@@ -51,8 +51,7 @@
         log.debug(u'Init done for %s' % parent.__class__.__name__)
 
     def addToolbarButton(self, title, icon, tooltip=None, slot=None,
-        checkable=False, shortcut=0, alternate=0,
-        context=QtCore.Qt.WidgetShortcut):
+        checkable=False, shortcuts=None, context=QtCore.Qt.WidgetShortcut):
         """
         A method to help developers easily add a button to the toolbar.
 
@@ -74,16 +73,12 @@
             If *True* the button has two, *off* and *on*, states. Default is
             *False*, which means the buttons has only one state.
 
-        ``shortcut``
-            The primary shortcut for this action
-
-        ``alternate``
-            The alternate shortcut for this action
+        ``shortcuts``
+            The list of shortcuts for this action
 
         ``context``
             Specify the context in which this shortcut is valid
         """
-        newAction = None
         if icon:
             actionIcon = build_icon(icon)
             if slot and not checkable:
@@ -92,7 +87,7 @@
                 newAction = self.addAction(actionIcon, title)
             self.icons[title] = actionIcon
         else:
-            newAction = QtGui.QAction(title, newAction)
+            newAction = QtGui.QAction(title, self)
             self.addAction(newAction)
             QtCore.QObject.connect(newAction,
                 QtCore.SIGNAL(u'triggered()'), slot)
@@ -103,8 +98,9 @@
             QtCore.QObject.connect(newAction,
                 QtCore.SIGNAL(u'toggled(bool)'), slot)
         self.actions[title] = newAction
-        newAction.setShortcuts([shortcut, alternate])
-        newAction.setShortcutContext(context)
+        if shortcuts is not None:
+            newAction.setShortcuts(shortcuts)
+            newAction.setShortcutContext(context)
         return newAction
 
     def addToolbarSeparator(self, handle):

=== modified file 'openlp/core/lib/ui.py'
--- openlp/core/lib/ui.py	2011-03-27 16:30:40 +0000
+++ openlp/core/lib/ui.py	2011-04-09 16:26:46 +0000
@@ -31,6 +31,7 @@
 from PyQt4 import QtCore, QtGui
 
 from openlp.core.lib import build_icon, Receiver, translate
+from openlp.core.utils.actions import ActionList
 
 log = logging.getLogger(__name__)
 
@@ -55,8 +56,10 @@
     EmptyField = translate('OpenLP.Ui', 'Empty Field')
     Error = translate('OpenLP.Ui', 'Error')
     Export = translate('OpenLP.Ui', 'Export')
+    File = translate('OpenLP.Ui', 'File')
     FontSizePtUnit = translate('OpenLP.Ui', 'pt',
         'Abbreviated font pointsize unit')
+    Help = translate('OpenLP.Ui', 'Help')
     Hours = translate('OpenLP.Ui', 'h', 'The abbreviated unit for hours')
     Image = translate('OpenLP.Ui', 'Image')
     Import = translate('OpenLP.Ui', 'Import')
@@ -64,6 +67,7 @@
     Live = translate('OpenLP.Ui', 'Live')
     LiveBGError = translate('OpenLP.Ui', 'Live Background Error')
     LivePanel = translate('OpenLP.Ui', 'Live Panel')
+    LiveToolbar = translate('OpenLP.Ui', 'Live Toolbar')
     Load = translate('OpenLP.Ui', 'Load')
     Minutes = translate('OpenLP.Ui', 'm', 'The abbreviated unit for minutes')
     Middle = translate('OpenLP.Ui', 'Middle')
@@ -81,6 +85,7 @@
     OpenService = translate('OpenLP.Ui', 'Open Service')
     Preview = translate('OpenLP.Ui', 'Preview')
     PreviewPanel = translate('OpenLP.Ui', 'Preview Panel')
+    PreviewToolbar = translate('OpenLP.Ui', 'Preview Toolbar')
     PrintServiceOrder = translate('OpenLP.Ui', 'Print Service Order')
     ReplaceBG = translate('OpenLP.Ui', 'Replace Background')
     ReplaceLiveBG = translate('OpenLP.Ui', 'Replace Live Background')
@@ -91,13 +96,17 @@
     Search = translate('OpenLP.Ui', 'Search')
     SelectDelete = translate('OpenLP.Ui', 'You must select an item to delete.')
     SelectEdit = translate('OpenLP.Ui', 'You must select an item to edit.')
+    Settings = translate('OpenLP.Ui', 'Settings')
     SaveService = translate('OpenLP.Ui', 'Save Service')
     Service = translate('OpenLP.Ui', 'Service')
     StartTimeCode = unicode(translate('OpenLP.Ui', 'Start %s'))
     Theme = translate('OpenLP.Ui', 'Theme', 'Singular')
     Themes = translate('OpenLP.Ui', 'Themes', 'Plural')
+    Tools = translate('OpenLP.Ui', 'Tools')
     Top = translate('OpenLP.Ui', 'Top')
     Version = translate('OpenLP.Ui', 'Version')
+    View = translate('OpenLP.Ui', 'View')
+    ViewMode = translate('OpenLP.Ui', 'View Model')
 
 def add_welcome_page(parent, image):
     """
@@ -238,45 +247,128 @@
         QtCore.SIGNAL(u'clicked()'), parent.onDownButtonClicked)
     return up_button, down_button
 
-def base_action(parent, name):
+def base_action(parent, name, category=None):
     """
     Return the most basic action with the object name set.
+
+    ``category``
+        The category the action should be listed in the shortcut dialog. If you
+        not wish, that this action is added to the shortcut dialog, then do not
+        state any.
     """
     action = QtGui.QAction(parent)
     action.setObjectName(name)
+    if category is not None:
+        action_list = ActionList.get_instance()
+        action_list.add_action(action, category)
     return action
 
-def checkable_action(parent, name, checked=None):
+def checkable_action(parent, name, checked=None, category=None):
     """
     Return a standard action with the checkable attribute set.
     """
-    action = base_action(parent, name)
+    action = base_action(parent, name, category)
     action.setCheckable(True)
     if checked is not None:
         action.setChecked(checked)
     return action
 
-def icon_action(parent, name, icon, checked=None):
+def icon_action(parent, name, icon, checked=None, category=None):
     """
     Return a standard action with an icon.
     """
     if checked is not None:
-        action = checkable_action(parent, name, checked)
+        action = checkable_action(parent, name, checked, category)
     else:
-        action = base_action(parent, name)
+        action = base_action(parent, name, category)
     action.setIcon(build_icon(icon))
     return action
 
-def shortcut_action(parent, text, shortcuts, function):
+def shortcut_action(parent, name, shortcuts, function, icon=None, checked=None,
+    category=None, context=QtCore.Qt.WindowShortcut):
     """
     Return a shortcut enabled action.
     """
-    action = QtGui.QAction(text, parent)
+    action = QtGui.QAction(parent)
+    action.setObjectName(name)
+    if icon is not None:
+        action.setIcon(build_icon(icon))
+    if checked is not None:
+        action.setCheckable(True)
+        action.setChecked(checked)
     action.setShortcuts(shortcuts)
-    action.setShortcutContext(QtCore.Qt.WidgetWithChildrenShortcut)
+    action.setShortcutContext(context)
+    action_list = ActionList.get_instance()
+    action_list.add_action(action, category)
     QtCore.QObject.connect(action, QtCore.SIGNAL(u'triggered()'), function)
     return action
 
+def context_menu_action(base, icon, text, slot, shortcuts=None, category=None,
+    context=QtCore.Qt.WindowShortcut):
+    """
+    Utility method to help build context menus for plugins
+
+    ``base``
+        The parent menu to add this menu item to
+
+    ``icon``
+        An icon for this action
+
+    ``text``
+        The text to display for this action
+
+    ``slot``
+        The code to run when this action is triggered
+
+    ``shortcuts``
+        The action's shortcuts.
+
+    ``category``
+        The category the shortcut should be listed in the shortcut dialog. If
+        left to None, then the action will be hidden in the shortcut dialog.
+    
+    ``context``
+        The context the shortcut is valid.
+    """
+    action = QtGui.QAction(text, base)
+    if icon:
+        action.setIcon(build_icon(icon))
+    QtCore.QObject.connect(action, QtCore.SIGNAL(u'triggered()'), slot)
+    if shortcuts is not None:
+        action.setShortcuts(shortcuts)
+        action.setShortcutContext(context)
+        action_list = ActionList.get_instance()
+        action_list.add_action(action)
+    return action
+
+def context_menu(base, icon, text):
+    """
+    Utility method to help build context menus for plugins
+
+    ``base``
+        The parent object to add this menu to
+
+    ``icon``
+        An icon for this menu
+
+    ``text``
+        The text to display for this menu
+    """
+    action = QtGui.QMenu(text, base)
+    action.setIcon(build_icon(icon))
+    return action
+
+def context_menu_separator(base):
+    """
+    Add a separator to a context menu
+
+    ``base``
+        The menu object to add the separator to
+    """
+    action = QtGui.QAction(u'', base)
+    action.setSeparator(True)
+    return action
+
 def add_widget_completer(cache, widget):
     """
     Adds a text autocompleter to a widget.

=== modified file 'openlp/core/ui/mainwindow.py'
--- openlp/core/ui/mainwindow.py	2011-04-03 13:35:58 +0000
+++ openlp/core/ui/mainwindow.py	2011-04-09 16:26:46 +0000
@@ -33,12 +33,13 @@
 from openlp.core.lib import RenderManager, build_icon, OpenLPDockWidget, \
     SettingsManager, PluginManager, Receiver, translate
 from openlp.core.lib.ui import UiStrings, base_action, checkable_action, \
-    icon_action
+    icon_action, shortcut_action
 from openlp.core.ui import AboutForm, SettingsForm, ServiceManager, \
     ThemeManager, SlideController, PluginForm, MediaDockManager, \
     ShortcutListForm, DisplayTagForm
 from openlp.core.utils import AppLocation, add_actions, LanguageManager, \
-    ActionList, get_application_version
+    get_application_version
+from openlp.core.utils.actions import ActionList, CategoryOrder
 
 log = logging.getLogger(__name__)
 
@@ -161,74 +162,86 @@
         mainWindow.addDockWidget(QtCore.Qt.RightDockWidgetArea,
             self.themeManagerDock)
         # Create the menu items
-        self.FileNewItem = icon_action(mainWindow, u'FileNewItem',
-            u':/general/general_new.png')
-        mainWindow.actionList.add_action(self.FileNewItem, u'File')
-        self.FileOpenItem = icon_action(mainWindow, u'FileOpenItem',
-            u':/general/general_open.png')
-        mainWindow.actionList.add_action(self.FileOpenItem, u'File')
-        self.FileSaveItem = icon_action(mainWindow, u'FileSaveItem',
-            u':/general/general_save.png')
-        mainWindow.actionList.add_action(self.FileSaveItem, u'File')
-        self.FileSaveAsItem = base_action(mainWindow, u'FileSaveAsItem')
-        mainWindow.actionList.add_action(self.FileSaveAsItem, u'File')
-        self.printServiceOrderItem = base_action(
-            mainWindow, u'printServiceItem')
-        mainWindow.actionList.add_action(
-            self.printServiceOrderItem, u'Print Service Order')
-        self.FileExitItem = icon_action(mainWindow, u'FileExitItem',
-            u':/system/system_exit.png')
-        mainWindow.actionList.add_action(self.FileExitItem, u'File')
-        self.ImportThemeItem = base_action(mainWindow, u'ImportThemeItem')
-        mainWindow.actionList.add_action(self.ImportThemeItem, u'Import')
-        self.ImportLanguageItem = base_action(mainWindow, u'ImportLanguageItem')
-        mainWindow.actionList.add_action(self.ImportLanguageItem, u'Import')
-        self.ExportThemeItem = base_action(mainWindow, u'ExportThemeItem')
-        mainWindow.actionList.add_action(self.ExportThemeItem, u'Export')
-        self.ExportLanguageItem = base_action(mainWindow, u'ExportLanguageItem')
-        mainWindow.actionList.add_action(self.ExportLanguageItem, u'Export')
-        self.ViewMediaManagerItem = icon_action(mainWindow,
-            u'ViewMediaManagerItem', u':/system/system_mediamanager.png',
-            self.mediaManagerDock.isVisible())
-        self.ViewThemeManagerItem = icon_action(mainWindow,
-            u'ViewThemeManagerItem', u':/system/system_thememanager.png',
-            self.themeManagerDock.isVisible())
-        mainWindow.actionList.add_action(self.ViewMediaManagerItem, u'View')
-        self.ViewServiceManagerItem = icon_action(mainWindow,
-            u'ViewServiceManagerItem', u':/system/system_servicemanager.png',
-            self.serviceManagerDock.isVisible())
-        mainWindow.actionList.add_action(self.ViewServiceManagerItem, u'View')
-        self.ViewPreviewPanel = checkable_action(mainWindow,
-            u'ViewPreviewPanel', previewVisible)
-        mainWindow.actionList.add_action(self.ViewPreviewPanel, u'View')
-        self.ViewLivePanel = checkable_action(mainWindow, u'ViewLivePanel',
-            liveVisible)
-        mainWindow.actionList.add_action(self.ViewLivePanel, u'View')
-        self.ModeDefaultItem = checkable_action(mainWindow, u'ModeDefaultItem')
-        mainWindow.actionList.add_action(self.ModeDefaultItem, u'View Mode')
-        self.ModeSetupItem = checkable_action(mainWindow, u'ModeLiveItem')
-        mainWindow.actionList.add_action(self.ModeSetupItem, u'View Mode')
-        self.ModeLiveItem = checkable_action(mainWindow, u'ModeLiveItem', True)
-        mainWindow.actionList.add_action(self.ModeLiveItem, u'View Mode')
+        action_list = ActionList.get_instance()
+        action_list.add_category(UiStrings.File, CategoryOrder.standardMenu)
+        self.FileNewItem = shortcut_action(mainWindow, u'FileNewItem',
+            [QtGui.QKeySequence(u'Ctrl+N')],
+            self.ServiceManagerContents.onNewServiceClicked,
+            u':/general/general_new.png', category=UiStrings.File)
+        self.FileOpenItem = shortcut_action(mainWindow, u'FileOpenItem',
+            [QtGui.QKeySequence(u'Ctrl+O')],
+            self.ServiceManagerContents.onLoadServiceClicked,
+            u':/general/general_open.png', category=UiStrings.File)
+        self.FileSaveItem = shortcut_action(mainWindow, u'FileSaveItem',
+            [QtGui.QKeySequence(u'Ctrl+S')],
+            self.ServiceManagerContents.saveFile,
+            u':/general/general_save.png', category=UiStrings.File)
+        self.FileSaveAsItem = shortcut_action(mainWindow, u'FileSaveAsItem',
+            [QtGui.QKeySequence(u'Ctrl+Shift+S')],
+            self.ServiceManagerContents.saveFileAs, category=UiStrings.File)
+        self.printServiceOrderItem = shortcut_action(mainWindow,
+            u'printServiceItem', [QtGui.QKeySequence(u'Ctrl+P')],
+            self.ServiceManagerContents.printServiceOrder,
+            category=UiStrings.File)
+        self.FileExitItem = shortcut_action(mainWindow, u'FileExitItem',
+            [QtGui.QKeySequence(u'Alt+F4')], mainWindow.close,
+            u':/system/system_exit.png', category=UiStrings.File)
+        action_list.add_category(UiStrings.Import, CategoryOrder.standardMenu)
+        self.ImportThemeItem = base_action(
+            mainWindow, u'ImportThemeItem', UiStrings.Import)
+        self.ImportLanguageItem = base_action(
+            mainWindow, u'ImportLanguageItem')#, UiStrings.Import)
+        action_list.add_category(UiStrings.Export, CategoryOrder.standardMenu)
+        self.ExportThemeItem = base_action(
+            mainWindow, u'ExportThemeItem', UiStrings.Export)
+        self.ExportLanguageItem = base_action(
+            mainWindow, u'ExportLanguageItem')#, UiStrings.Export)
+        action_list.add_category(UiStrings.View, CategoryOrder.standardMenu)
+        self.ViewMediaManagerItem = shortcut_action(mainWindow,
+            u'ViewMediaManagerItem', [QtGui.QKeySequence(u'F8')],
+            self.toggleMediaManager, u':/system/system_mediamanager.png',
+            self.mediaManagerDock.isVisible(), UiStrings.View)
+        self.ViewThemeManagerItem = shortcut_action(mainWindow,
+            u'ViewThemeManagerItem', [QtGui.QKeySequence(u'F10')],
+            self.toggleThemeManager,  u':/system/system_thememanager.png',
+            self.themeManagerDock.isVisible(), UiStrings.View)
+        self.ViewServiceManagerItem = shortcut_action(mainWindow,
+            u'ViewServiceManagerItem', [QtGui.QKeySequence(u'F9')],
+            self.toggleServiceManager, u':/system/system_servicemanager.png',
+            self.serviceManagerDock.isVisible(), UiStrings.View)
+        self.ViewPreviewPanel = shortcut_action(mainWindow,
+            u'ViewPreviewPanel', [QtGui.QKeySequence(u'F11')],
+            self.setPreviewPanelVisibility, checked=previewVisible,
+            category=UiStrings.View)
+        self.ViewLivePanel = shortcut_action(mainWindow, u'ViewLivePanel',
+            [QtGui.QKeySequence(u'F12')], self.setLivePanelVisibility,
+            checked=liveVisible, category=UiStrings.View)
+        action_list.add_category(UiStrings.ViewMode, CategoryOrder.standardMenu)
+        self.ModeDefaultItem = checkable_action(
+            mainWindow, u'ModeDefaultItem', category=UiStrings.ViewMode)
+        self.ModeSetupItem = checkable_action(
+            mainWindow, u'ModeLiveItem', category=UiStrings.ViewMode)
+        self.ModeLiveItem = checkable_action(
+            mainWindow, u'ModeLiveItem', True, UiStrings.ViewMode)
         self.ModeGroup = QtGui.QActionGroup(mainWindow)
         self.ModeGroup.addAction(self.ModeDefaultItem)
         self.ModeGroup.addAction(self.ModeSetupItem)
         self.ModeGroup.addAction(self.ModeLiveItem)
         self.ModeDefaultItem.setChecked(True)
+        action_list.add_category(UiStrings.Tools, CategoryOrder.standardMenu)
         self.ToolsAddToolItem = icon_action(mainWindow, u'ToolsAddToolItem',
-            u':/tools/tools_add.png')
-        mainWindow.actionList.add_action(self.ToolsAddToolItem, u'Tools')
+            u':/tools/tools_add.png', category=UiStrings.Tools)
         self.ToolsOpenDataFolder = icon_action(mainWindow,
-            u'ToolsOpenDataFolder', u':/general/general_open.png')
-        mainWindow.actionList.add_action(self.ToolsOpenDataFolder, u'Tools')
-        self.settingsPluginListItem = icon_action(mainWindow,
-            u'settingsPluginListItem', u':/system/settings_plugin_list.png')
-        mainWindow.actionList.add_action(self.settingsPluginListItem,
-            u'Settings')
+            u'ToolsOpenDataFolder', u':/general/general_open.png',
+            category=UiStrings.Tools)
+        action_list.add_category(UiStrings.Settings, CategoryOrder.standardMenu)
+        self.settingsPluginListItem = shortcut_action(mainWindow,
+            u'settingsPluginListItem', [QtGui.QKeySequence(u'Alt+F7')],
+            self.onPluginItemClicked, u':/system/settings_plugin_list.png',
+            category=UiStrings.Settings)
         # i18n Language Items
         self.AutoLanguageItem = checkable_action(mainWindow,
             u'AutoLanguageItem', LanguageManager.auto_language)
-        mainWindow.actionList.add_action(self.AutoLanguageItem, u'Settings')
         self.LanguageGroup = QtGui.QActionGroup(mainWindow)
         self.LanguageGroup.setExclusive(True)
         self.LanguageGroup.setObjectName(u'LanguageGroup')
@@ -241,24 +254,26 @@
             add_actions(self.LanguageGroup, [languageItem])
         self.SettingsShortcutsItem = icon_action(mainWindow,
             u'SettingsShortcutsItem',
-            u':/system/system_configure_shortcuts.png')
+            u':/system/system_configure_shortcuts.png',
+            category=UiStrings.Settings)
         self.DisplayTagItem = icon_action(mainWindow,
-            u'DisplayTagItem', u':/system/tag_editor.png')
+            u'DisplayTagItem', u':/system/tag_editor.png',
+            category=UiStrings.Settings)
         self.SettingsConfigureItem = icon_action(mainWindow,
-            u'SettingsConfigureItem', u':/system/system_settings.png')
-        mainWindow.actionList.add_action(self.SettingsShortcutsItem,
-            u'Settings')
+            u'SettingsConfigureItem', u':/system/system_settings.png',
+            category=UiStrings.Settings)
+        action_list.add_category(UiStrings.Help, CategoryOrder.standardMenu)
         self.HelpDocumentationItem = icon_action(mainWindow,
-            u'HelpDocumentationItem', u':/system/system_help_contents.png')
+            u'HelpDocumentationItem', u':/system/system_help_contents.png',
+            category=None)#UiStrings.Help)
         self.HelpDocumentationItem.setEnabled(False)
-        mainWindow.actionList.add_action(self.HelpDocumentationItem, u'Help')
-        self.HelpAboutItem = icon_action(mainWindow, u'HelpAboutItem',
-            u':/system/system_about.png')
-        mainWindow.actionList.add_action(self.HelpAboutItem, u'Help')
-        self.HelpOnlineHelpItem = base_action(mainWindow, u'HelpOnlineHelpItem')
-        mainWindow.actionList.add_action(self.HelpOnlineHelpItem, u'Help')
-        self.helpWebSiteItem = base_action(mainWindow, u'helpWebSiteItem')
-        mainWindow.actionList.add_action(self.helpWebSiteItem, u'Help')
+        self.HelpAboutItem = shortcut_action(mainWindow, u'HelpAboutItem',
+            [QtGui.QKeySequence(u'Ctrl+F1')], self.onHelpAboutItemClicked,
+            u':/system/system_about.png', category=UiStrings.Help)
+        self.HelpOnlineHelpItem = base_action(
+            mainWindow, u'HelpOnlineHelpItem', category=UiStrings.Help)
+        self.helpWebSiteItem = base_action(
+            mainWindow, u'helpWebSiteItem', category=UiStrings.Help)
         add_actions(self.FileImportMenu,
             (self.ImportThemeItem, self.ImportLanguageItem))
         add_actions(self.FileExportMenu,
@@ -294,14 +309,11 @@
         # Connect up some signals and slots
         QtCore.QObject.connect(self.FileMenu,
             QtCore.SIGNAL(u'aboutToShow()'), self.updateFileMenu)
-        QtCore.QObject.connect(self.FileExitItem,
-            QtCore.SIGNAL(u'triggered()'), mainWindow.close)
         QtCore.QMetaObject.connectSlotsByName(mainWindow)
         # Hide the entry, as it does not have any functionality yet.
         self.ToolsAddToolItem.setVisible(False)
         self.ImportLanguageItem.setVisible(False)
         self.ExportLanguageItem.setVisible(False)
-        self.SettingsShortcutsItem.setVisible(False)
         self.HelpDocumentationItem.setVisible(False)
 
     def retranslateUi(self, mainWindow):
@@ -329,36 +341,27 @@
         self.FileNewItem.setText(translate('OpenLP.MainWindow', '&New'))
         self.FileNewItem.setToolTip(UiStrings.NewService)
         self.FileNewItem.setStatusTip(UiStrings.CreateService)
-        self.FileNewItem.setShortcut(translate('OpenLP.MainWindow', 'Ctrl+N'))
         self.FileOpenItem.setText(translate('OpenLP.MainWindow', '&Open'))
         self.FileOpenItem.setToolTip(UiStrings.OpenService)
         self.FileOpenItem.setStatusTip(
             translate('OpenLP.MainWindow', 'Open an existing service.'))
-        self.FileOpenItem.setShortcut(translate('OpenLP.MainWindow', 'Ctrl+O'))
         self.FileSaveItem.setText(translate('OpenLP.MainWindow', '&Save'))
         self.FileSaveItem.setToolTip(UiStrings.SaveService)
         self.FileSaveItem.setStatusTip(
             translate('OpenLP.MainWindow', 'Save the current service to disk.'))
-        self.FileSaveItem.setShortcut(translate('OpenLP.MainWindow', 'Ctrl+S'))
         self.FileSaveAsItem.setText(
             translate('OpenLP.MainWindow', 'Save &As...'))
         self.FileSaveAsItem.setToolTip(
             translate('OpenLP.MainWindow', 'Save Service As'))
         self.FileSaveAsItem.setStatusTip(translate('OpenLP.MainWindow',
             'Save the current service under a new name.'))
-        self.FileSaveAsItem.setShortcut(
-            translate('OpenLP.MainWindow', 'Ctrl+Shift+S'))
         self.printServiceOrderItem.setText(UiStrings.PrintServiceOrder)
         self.printServiceOrderItem.setStatusTip(translate('OpenLP.MainWindow',
             'Print the current Service Order.'))
-        self.printServiceOrderItem.setShortcut(
-            translate('OpenLP.MainWindow', 'Ctrl+P'))
         self.FileExitItem.setText(
             translate('OpenLP.MainWindow', 'E&xit'))
         self.FileExitItem.setStatusTip(
             translate('OpenLP.MainWindow', 'Quit OpenLP'))
-        self.FileExitItem.setShortcut(
-            translate('OpenLP.MainWindow', 'Alt+F4'))
         self.ImportThemeItem.setText(
             translate('OpenLP.MainWindow', '&Theme'))
         self.ImportLanguageItem.setText(
@@ -379,53 +382,39 @@
             translate('OpenLP.MainWindow', 'Toggle Media Manager'))
         self.ViewMediaManagerItem.setStatusTip(translate('OpenLP.MainWindow',
             'Toggle the visibility of the media manager.'))
-        self.ViewMediaManagerItem.setShortcut(
-            translate('OpenLP.MainWindow', 'F8'))
         self.ViewThemeManagerItem.setText(
             translate('OpenLP.MainWindow', '&Theme Manager'))
         self.ViewThemeManagerItem.setToolTip(
             translate('OpenLP.MainWindow', 'Toggle Theme Manager'))
         self.ViewThemeManagerItem.setStatusTip(translate('OpenLP.MainWindow',
             'Toggle the visibility of the theme manager.'))
-        self.ViewThemeManagerItem.setShortcut(
-            translate('OpenLP.MainWindow', 'F10'))
         self.ViewServiceManagerItem.setText(
             translate('OpenLP.MainWindow', '&Service Manager'))
         self.ViewServiceManagerItem.setToolTip(
             translate('OpenLP.MainWindow', 'Toggle Service Manager'))
         self.ViewServiceManagerItem.setStatusTip(translate('OpenLP.MainWindow',
             'Toggle the visibility of the service manager.'))
-        self.ViewServiceManagerItem.setShortcut(
-            translate('OpenLP.MainWindow', 'F9'))
         self.ViewPreviewPanel.setText(
             translate('OpenLP.MainWindow', '&Preview Panel'))
         self.ViewPreviewPanel.setToolTip(
             translate('OpenLP.MainWindow', 'Toggle Preview Panel'))
         self.ViewPreviewPanel.setStatusTip(translate('OpenLP.MainWindow',
             'Toggle the visibility of the preview panel.'))
-        self.ViewPreviewPanel.setShortcut(
-            translate('OpenLP.MainWindow', 'F11'))
         self.ViewLivePanel.setText(
             translate('OpenLP.MainWindow', '&Live Panel'))
         self.ViewLivePanel.setToolTip(
             translate('OpenLP.MainWindow', 'Toggle Live Panel'))
         self.ViewLivePanel.setStatusTip(translate('OpenLP.MainWindow',
             'Toggle the visibility of the live panel.'))
-        self.ViewLivePanel.setShortcut(
-            translate('OpenLP.MainWindow', 'F12'))
         self.settingsPluginListItem.setText(translate('OpenLP.MainWindow',
             '&Plugin List'))
         self.settingsPluginListItem.setStatusTip(
             translate('OpenLP.MainWindow', 'List the Plugins'))
-        self.settingsPluginListItem.setShortcut(
-            translate('OpenLP.MainWindow', 'Alt+F7'))
         self.HelpDocumentationItem.setText(
             translate('OpenLP.MainWindow', '&User Guide'))
         self.HelpAboutItem.setText(translate('OpenLP.MainWindow', '&About'))
         self.HelpAboutItem.setStatusTip(
             translate('OpenLP.MainWindow', 'More information about OpenLP'))
-        self.HelpAboutItem.setShortcut(
-            translate('OpenLP.MainWindow', 'Ctrl+F1'))
         self.HelpOnlineHelpItem.setText(
             translate('OpenLP.MainWindow', '&Online Help'))
         # Uncomment after 1.9.5 beta string freeze
@@ -467,8 +456,6 @@
     """
     log.info(u'MainWindow loaded')
 
-    actionList = ActionList()
-
     def __init__(self, screens, clipboard, arguments):
         """
         This constructor sets up the interface, the various managers, and the
@@ -485,7 +472,6 @@
         self.serviceSettingsSection = u'servicemanager'
         self.songsSettingsSection = u'songs'
         self.serviceNotSaved = False
-        self.actionList = ActionList()
         self.settingsmanager = SettingsManager(screens)
         self.aboutForm = AboutForm(self)
         self.settingsForm = SettingsForm(self.screens, self, self)
@@ -510,16 +496,6 @@
         QtCore.QObject.connect(self.ExportThemeItem,
             QtCore.SIGNAL(u'triggered()'),
             self.themeManagerContents.onExportTheme)
-        QtCore.QObject.connect(self.ViewMediaManagerItem,
-            QtCore.SIGNAL(u'triggered(bool)'), self.toggleMediaManager)
-        QtCore.QObject.connect(self.ViewServiceManagerItem,
-            QtCore.SIGNAL(u'triggered(bool)'), self.toggleServiceManager)
-        QtCore.QObject.connect(self.ViewThemeManagerItem,
-            QtCore.SIGNAL(u'triggered(bool)'), self.toggleThemeManager)
-        QtCore.QObject.connect(self.ViewPreviewPanel,
-            QtCore.SIGNAL(u'toggled(bool)'), self.setPreviewPanelVisibility)
-        QtCore.QObject.connect(self.ViewLivePanel,
-            QtCore.SIGNAL(u'toggled(bool)'), self.setLivePanelVisibility)
         QtCore.QObject.connect(self.mediaManagerDock,
             QtCore.SIGNAL(u'visibilityChanged(bool)'),
             self.ViewMediaManagerItem.setChecked)
@@ -533,32 +509,14 @@
             QtCore.SIGNAL(u'triggered()'), self.onHelpWebSiteClicked)
         QtCore.QObject.connect(self.HelpOnlineHelpItem,
             QtCore.SIGNAL(u'triggered()'), self.onHelpOnLineHelpClicked)
-        QtCore.QObject.connect(self.HelpAboutItem,
-            QtCore.SIGNAL(u'triggered()'), self.onHelpAboutItemClicked)
         QtCore.QObject.connect(self.ToolsOpenDataFolder,
             QtCore.SIGNAL(u'triggered()'), self.onToolsOpenDataFolderClicked)
-        QtCore.QObject.connect(self.settingsPluginListItem,
-            QtCore.SIGNAL(u'triggered()'), self.onPluginItemClicked)
         QtCore.QObject.connect(self.DisplayTagItem,
             QtCore.SIGNAL(u'triggered()'), self.onDisplayTagItemClicked)
         QtCore.QObject.connect(self.SettingsConfigureItem,
             QtCore.SIGNAL(u'triggered()'), self.onSettingsConfigureItemClicked)
         QtCore.QObject.connect(self.SettingsShortcutsItem,
             QtCore.SIGNAL(u'triggered()'), self.onSettingsShortcutsItemClicked)
-        QtCore.QObject.connect(self.FileNewItem, QtCore.SIGNAL(u'triggered()'),
-            self.ServiceManagerContents.onNewServiceClicked)
-        QtCore.QObject.connect(self.FileOpenItem,
-            QtCore.SIGNAL(u'triggered()'),
-            self.ServiceManagerContents.onLoadServiceClicked)
-        QtCore.QObject.connect(self.FileSaveItem,
-            QtCore.SIGNAL(u'triggered()'),
-            self.ServiceManagerContents.saveFile)
-        QtCore.QObject.connect(self.FileSaveAsItem,
-            QtCore.SIGNAL(u'triggered()'),
-            self.ServiceManagerContents.saveFileAs)
-        QtCore.QObject.connect(self.printServiceOrderItem,
-            QtCore.SIGNAL(u'triggered()'),
-            self.ServiceManagerContents.printServiceOrder)
         # i18n set signals for languages
         self.LanguageGroup.triggered.connect(LanguageManager.set_language)
         QtCore.QObject.connect(self.ModeDefaultItem,
@@ -781,7 +739,8 @@
         """
         Show the shortcuts dialog
         """
-        self.shortcutForm.exec_(self.actionList)
+        if self.shortcutForm.exec_():
+            self.shortcutForm.save()
 
     def onModeDefaultItemClicked(self):
         """
@@ -928,19 +887,16 @@
             unicode(translate('OpenLP.MainWindow', 'Default Theme: %s')) %
                 theme)
 
-    def toggleMediaManager(self, visible):
-        if self.mediaManagerDock.isVisible() != visible:
-            self.mediaManagerDock.setVisible(visible)
-
-    def toggleServiceManager(self, visible):
-        if self.serviceManagerDock.isVisible() != visible:
-            self.serviceManagerDock.setVisible(visible)
-
-    def toggleThemeManager(self, visible):
-        if self.themeManagerDock.isVisible() != visible:
-            self.themeManagerDock.setVisible(visible)
-
-    def setPreviewPanelVisibility(self, visible):
+    def toggleMediaManager(self):
+        self.mediaManagerDock.setVisible(not self.mediaManagerDock.isVisible())
+
+    def toggleServiceManager(self):
+        self.serviceManagerDock.setVisible(not self.serviceManagerDock.isVisible())
+
+    def toggleThemeManager(self):
+        self.themeManagerDock.setVisible(not self.themeManagerDock.isVisible())
+
+    def setPreviewPanelVisibility(self, visible=None):
         """
         Sets the visibility of the preview panel including saving the setting
         and updating the menu.
@@ -950,12 +906,14 @@
                 True - Visible
                 False - Hidden
         """
+        if visible is None:
+            visible = self.ViewPreviewPanel.isVisible()
         self.previewController.panel.setVisible(visible)
         QtCore.QSettings().setValue(u'user interface/preview panel',
             QtCore.QVariant(visible))
         self.ViewPreviewPanel.setChecked(visible)
 
-    def setLivePanelVisibility(self, visible):
+    def setLivePanelVisibility(self, visible=None):
         """
         Sets the visibility of the live panel including saving the setting and
         updating the menu.
@@ -965,6 +923,8 @@
                 True - Visible
                 False - Hidden
         """
+        if visible is None:
+            visible = self.ViewLivePanel.isVisible()
         self.liveController.panel.setVisible(visible)
         QtCore.QSettings().setValue(u'user interface/live panel',
             QtCore.QVariant(visible))
@@ -1022,8 +982,9 @@
             self.FileMenu.addSeparator()
             for fileId, filename in enumerate(recentFilesToDisplay):
                 log.debug('Recent file name: %s', filename)
-                action = QtGui.QAction(u'&%d %s' % (fileId + 1,
-                    QtCore.QFileInfo(filename).fileName()), self)
+                action =  base_action(self, u'')
+                action.setText(u'&%d %s' % 
+                    (fileId + 1, QtCore.QFileInfo(filename).fileName()))
                 action.setData(QtCore.QVariant(filename))
                 self.connect(action, QtCore.SIGNAL(u'triggered()'),
                     self.ServiceManagerContents.onRecentServiceClicked)

=== modified file 'openlp/core/ui/servicemanager.py'
--- openlp/core/ui/servicemanager.py	2011-04-02 09:53:08 +0000
+++ openlp/core/ui/servicemanager.py	2011-04-09 16:26:46 +0000
@@ -32,14 +32,15 @@
 
 from PyQt4 import QtCore, QtGui
 
-from openlp.core.lib import OpenLPToolbar, ServiceItem, context_menu_action, \
-    Receiver, build_icon, ItemCapabilities, SettingsManager, translate
+from openlp.core.lib import OpenLPToolbar, ServiceItem, Receiver, build_icon, \
+    ItemCapabilities, SettingsManager, translate
 from openlp.core.lib.theme import ThemeLevel
-from openlp.core.lib.ui import UiStrings, critical_error_message_box
+from openlp.core.lib.ui import UiStrings, critical_error_message_box, context_menu_action
 from openlp.core.ui import ServiceNoteForm, ServiceItemEditForm, StartTimeForm
 from openlp.core.ui.printserviceform import PrintServiceForm
 from openlp.core.utils import AppLocation, delete_file, file_is_unicode, \
     split_filename
+from openlp.core.utils.actions import ActionList, CategoryOrder
 
 class ServiceManagerList(QtGui.QTreeWidget):
     """
@@ -164,38 +165,55 @@
             u':/services/service_top.png',
             translate('OpenLP.ServiceManager',
             'Move item to the top of the service.'),
-            self.onServiceTop, shortcut=QtCore.Qt.Key_Home)
+            self.onServiceTop, shortcuts=[QtCore.Qt.Key_Home])
+        self.serviceManagerList.moveTop.setObjectName(u'moveTop')
+        action_list = ActionList.get_instance()
+        action_list.add_category(UiStrings.Service, CategoryOrder.standardToolbar)
+        action_list.add_action(
+            self.serviceManagerList.moveTop, UiStrings.Service)
         self.serviceManagerList.moveUp = self.orderToolbar.addToolbarButton(
             translate('OpenLP.ServiceManager', 'Move &up'),
             u':/services/service_up.png',
             translate('OpenLP.ServiceManager',
             'Move item up one position in the service.'),
-            self.onServiceUp, shortcut=QtCore.Qt.Key_PageUp)
+            self.onServiceUp, shortcuts=[QtCore.Qt.Key_PageUp])
+        self.serviceManagerList.moveUp.setObjectName(u'moveUp')
+        action_list.add_action(self.serviceManagerList.moveUp, UiStrings.Service)
         self.serviceManagerList.moveDown = self.orderToolbar.addToolbarButton(
             translate('OpenLP.ServiceManager', 'Move &down'),
             u':/services/service_down.png',
             translate('OpenLP.ServiceManager',
             'Move item down one position in the service.'),
-            self.onServiceDown, shortcut=QtCore.Qt.Key_PageDown)
+            self.onServiceDown, shortcuts=[QtCore.Qt.Key_PageDown])
+        self.serviceManagerList.moveDown.setObjectName(u'moveDown')
+        action_list.add_action(
+            self.serviceManagerList.moveDown, UiStrings.Service)
         self.serviceManagerList.moveBottom = self.orderToolbar.addToolbarButton(
             translate('OpenLP.ServiceManager', 'Move to &bottom'),
             u':/services/service_bottom.png',
             translate('OpenLP.ServiceManager',
             'Move item to the end of the service.'),
-            self.onServiceEnd, shortcut=QtCore.Qt.Key_End)
+            self.onServiceEnd, shortcuts=[QtCore.Qt.Key_End])
+        self.serviceManagerList.moveBottom.setObjectName(u'moveBottom')
+        action_list.add_action(
+            self.serviceManagerList.moveBottom, UiStrings.Service)
         self.serviceManagerList.down = self.orderToolbar.addToolbarButton(
             translate('OpenLP.ServiceManager', 'Move &down'),
             None,
             translate('OpenLP.ServiceManager',
             'Moves the selection down the window.'),
-            self.onMoveSelectionDown, shortcut=QtCore.Qt.Key_Down)
+            self.onMoveSelectionDown, shortcuts=[QtCore.Qt.Key_Down])
+        self.serviceManagerList.down.setObjectName(u'down')
+        action_list.add_action(self.serviceManagerList.down)
         self.serviceManagerList.down.setVisible(False)
         self.serviceManagerList.up = self.orderToolbar.addToolbarButton(
             translate('OpenLP.ServiceManager', 'Move up'),
             None,
             translate('OpenLP.ServiceManager',
             'Moves the selection up the window.'),
-            self.onMoveSelectionUp, shortcut=QtCore.Qt.Key_Up)
+            self.onMoveSelectionUp, shortcuts=[QtCore.Qt.Key_Up])
+        self.serviceManagerList.up.setObjectName(u'up')
+        action_list.add_action(self.serviceManagerList.up)
         self.serviceManagerList.up.setVisible(False)
         self.orderToolbar.addSeparator()
         self.serviceManagerList.delete = self.orderToolbar.addToolbarButton(
@@ -210,22 +228,28 @@
             u':/services/service_expand_all.png',
             translate('OpenLP.ServiceManager',
             'Expand all the service items.'),
-            self.onExpandAll, shortcut=QtCore.Qt.Key_Plus)
+            self.onExpandAll, shortcuts=[QtCore.Qt.Key_Plus])
+        self.serviceManagerList.expand.setObjectName(u'expand')
+        action_list.add_action(self.serviceManagerList.expand, UiStrings.Service)
         self.serviceManagerList.collapse = self.orderToolbar.addToolbarButton(
             translate('OpenLP.ServiceManager', '&Collapse all'),
             u':/services/service_collapse_all.png',
             translate('OpenLP.ServiceManager',
             'Collapse all the service items.'),
-            self.onCollapseAll, shortcut=QtCore.Qt.Key_Minus)
+            self.onCollapseAll, shortcuts=[QtCore.Qt.Key_Minus])
+        self.serviceManagerList.collapse.setObjectName(u'collapse')
+        action_list.add_action(
+            self.serviceManagerList.collapse, UiStrings.Service)
         self.orderToolbar.addSeparator()
         self.serviceManagerList.makeLive = self.orderToolbar.addToolbarButton(
             translate('OpenLP.ServiceManager', 'Go Live'),
             u':/general/general_live.png',
             translate('OpenLP.ServiceManager',
-            'Send the selected item to Live.'),
-            self.makeLive, shortcut=QtCore.Qt.Key_Enter,
-            alternate=QtCore.Qt.Key_Return)
-        self.orderToolbar.setObjectName(u'orderToolbar')
+            'Send the selected item to Live.'), self.makeLive,
+            shortcuts=[QtCore.Qt.Key_Enter, QtCore.Qt.Key_Return])
+        self.serviceManagerList.makeLive.setObjectName(u'orderToolbar')
+        action_list.add_action(
+            self.serviceManagerList.makeLive, UiStrings.Service)
         self.layout.addWidget(self.orderToolbar)
         # Connect up our signals and slots
         QtCore.QObject.connect(self.themeComboBox,
@@ -300,7 +324,6 @@
         self.themeMenu = QtGui.QMenu(
             translate('OpenLP.ServiceManager', '&Change Item Theme'))
         self.menu.addMenu(self.themeMenu)
-        self.setServiceHotkeys()
         self.serviceManagerList.addActions(
             [self.serviceManagerList.moveDown,
             self.serviceManagerList.moveUp,
@@ -314,19 +337,6 @@
             ])
         self.configUpdated()
 
-    def setServiceHotkeys(self):
-        actionList = self.mainwindow.actionList
-        actionList.add_action(self.serviceManagerList.moveDown, u'Service')
-        actionList.add_action(self.serviceManagerList.moveUp, u'Service')
-        actionList.add_action(self.serviceManagerList.moveTop, u'Service')
-        actionList.add_action(self.serviceManagerList.moveBottom, u'Service')
-        actionList.add_action(self.serviceManagerList.makeLive, u'Service')
-        actionList.add_action(self.serviceManagerList.up, u'Service')
-        actionList.add_action(self.serviceManagerList.down, u'Service')
-        actionList.add_action(self.serviceManagerList.expand, u'Service')
-        actionList.add_action(self.serviceManagerList.collapse, u'Service')
-
-
     def setModified(self, modified=True):
         """
         Setter for property "modified". Sets whether or not the current service
@@ -1259,7 +1269,7 @@
         for theme in theme_list:
             self.themeComboBox.addItem(theme)
             action = context_menu_action(self.serviceManagerList, None, theme,
-                self.onThemeChangeAction)
+                self.onThemeChangeAction, context=QtCore.Qt.WidgetShortcut)
             self.themeMenu.addAction(action)
         index = self.themeComboBox.findText(self.service_theme,
             QtCore.Qt.MatchExactly)

=== modified file 'openlp/core/ui/shortcutlistdialog.py'
--- openlp/core/ui/shortcutlistdialog.py	2011-03-24 19:04:02 +0000
+++ openlp/core/ui/shortcutlistdialog.py	2011-04-09 16:26:46 +0000
@@ -31,41 +31,67 @@
 class Ui_ShortcutListDialog(object):
     def setupUi(self, shortcutListDialog):
         shortcutListDialog.setObjectName(u'shortcutListDialog')
-        self.dialogLayout = QtGui.QVBoxLayout(shortcutListDialog)
-        self.dialogLayout.setObjectName(u'dialogLayout')
+        shortcutListDialog.resize(500, 438)
+        self.shortcutListLayout = QtGui.QVBoxLayout(shortcutListDialog)
+        self.shortcutListLayout.setObjectName(u'shortcutListLayout')
         self.treeWidget = QtGui.QTreeWidget(shortcutListDialog)
+        self.treeWidget.setObjectName(u'treeWidget')
         self.treeWidget.setAlternatingRowColors(True)
-        self.treeWidget.setObjectName(u'treeWidget')
         self.treeWidget.setColumnCount(3)
-        self.dialogLayout.addWidget(self.treeWidget)
-        self.defaultButton = QtGui.QRadioButton(shortcutListDialog)
-        self.defaultButton.setChecked(True)
-        self.defaultButton.setObjectName(u'defaultButton')
-        self.dialogLayout.addWidget(self.defaultButton)
-        self.customLayout = QtGui.QHBoxLayout()
-        self.customLayout.setObjectName(u'customLayout')
-        self.customButton = QtGui.QRadioButton(shortcutListDialog)
-        self.customButton.setObjectName(u'customButton')
-        self.customLayout.addWidget(self.customButton)
-        self.shortcutButton = QtGui.QPushButton(shortcutListDialog)
-        self.shortcutButton.setIcon(
-            build_icon(u':/system/system_configure_shortcuts.png'))
-        self.shortcutButton.setCheckable(True)
-        self.shortcutButton.setObjectName(u'shortcutButton')
-        self.customLayout.addWidget(self.shortcutButton)
-        self.clearShortcutButton = QtGui.QToolButton(shortcutListDialog)
-        self.clearShortcutButton.setIcon(
-            build_icon(u':/system/clear_shortcut.png'))
-        self.clearShortcutButton.setAutoRaise(True)
-        self.clearShortcutButton.setObjectName(u'clearShortcutButton')
-        self.customLayout.addWidget(self.clearShortcutButton)
-        self.customLayout.addStretch()
-        self.dialogLayout.addLayout(self.customLayout)
+        self.shortcutListLayout.addWidget(self.treeWidget)
+        self.detailsLayout = QtGui.QGridLayout()
+        self.detailsLayout.setObjectName(u'detailsLayout')
+        self.detailsLayout.setContentsMargins(-1, 0, -1, -1)
+        self.defaultRadioButton = QtGui.QRadioButton(shortcutListDialog)
+        self.defaultRadioButton.setObjectName(u'defaultRadioButton')
+        self.defaultRadioButton.setChecked(True)
+        self.detailsLayout.addWidget(self.defaultRadioButton, 0, 0, 1, 1)
+        self.customRadioButton = QtGui.QRadioButton(shortcutListDialog)
+        self.customRadioButton.setObjectName(u'customRadioButton')
+        self.detailsLayout.addWidget(self.customRadioButton, 1, 0, 1, 1)
+        self.primaryLayout = QtGui.QHBoxLayout()
+        self.primaryLayout.setObjectName(u'primaryLayout')
+        self.primaryPushButton = QtGui.QPushButton(shortcutListDialog)
+        self.primaryPushButton.setObjectName(u'primaryPushButton')
+        self.primaryPushButton.setMinimumSize(QtCore.QSize(84, 0))
+        self.primaryPushButton.setIcon(
+            build_icon(u':/system/system_configure_shortcuts.png'))
+        self.primaryPushButton.setCheckable(True)
+        self.primaryLayout.addWidget(self.primaryPushButton)
+        self.clearPrimaryButton = QtGui.QToolButton(shortcutListDialog)
+        self.clearPrimaryButton.setObjectName(u'clearPrimaryButton')
+        self.clearPrimaryButton.setMinimumSize(QtCore.QSize(0, 16))
+        self.clearPrimaryButton.setIcon(
+            build_icon(u':/system/clear_shortcut.png'))
+        self.primaryLayout.addWidget(self.clearPrimaryButton)
+        self.detailsLayout.addLayout(self.primaryLayout, 1, 1, 1, 1)
+        self.alternateLayout = QtGui.QHBoxLayout()
+        self.alternateLayout.setObjectName(u'alternateLayout')
+        self.alternatePushButton = QtGui.QPushButton(shortcutListDialog)
+        self.alternatePushButton.setObjectName(u'alternatePushButton')
+        self.alternatePushButton.setCheckable(True)
+        self.alternatePushButton.setIcon(
+            build_icon(u':/system/system_configure_shortcuts.png'))
+        self.alternateLayout.addWidget(self.alternatePushButton)
+        self.clearAlternateButton = QtGui.QToolButton(shortcutListDialog)
+        self.clearAlternateButton.setObjectName(u'clearAlternateButton')
+        self.clearAlternateButton.setIcon(
+            build_icon(u':/system/clear_shortcut.png'))
+        self.alternateLayout.addWidget(self.clearAlternateButton)
+        self.detailsLayout.addLayout(self.alternateLayout, 1, 2, 1, 1)
+        self.primaryLabel = QtGui.QLabel(shortcutListDialog)
+        self.primaryLabel.setObjectName(u'primaryLabel')
+        self.detailsLayout.addWidget(self.primaryLabel, 0, 1, 1, 1)
+        self.alternateLabel = QtGui.QLabel(shortcutListDialog)
+        self.alternateLabel.setObjectName(u'alternateLabel')
+        self.detailsLayout.addWidget(self.alternateLabel, 0, 2, 1, 1)
+        self.shortcutListLayout.addLayout(self.detailsLayout)
         self.buttonBox = QtGui.QDialogButtonBox(shortcutListDialog)
+        self.buttonBox.setObjectName(u'buttonBox')
+        self.buttonBox.setOrientation(QtCore.Qt.Horizontal)
         self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Cancel |
-            QtGui.QDialogButtonBox.Ok | QtGui.QDialogButtonBox.Reset)
-        self.buttonBox.setObjectName(u'buttonBox')
-        self.dialogLayout.addWidget(self.buttonBox)
+            QtGui.QDialogButtonBox.Ok | QtGui.QDialogButtonBox.RestoreDefaults)
+        self.shortcutListLayout.addWidget(self.buttonBox)
         self.retranslateUi(shortcutListDialog)
         QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(u'accepted()'),
             shortcutListDialog.accept)
@@ -76,13 +102,24 @@
     def retranslateUi(self, shortcutListDialog):
         shortcutListDialog.setWindowTitle(
             translate('OpenLP.ShortcutListDialog', 'Customize Shortcuts'))
+        #self.descriptionLabel.setText(translate('OpenLP.ShortcutListDialog',
+            #'Select an action and click the button below to start capturing '
+            #'a new shortcut.'))
         self.treeWidget.setHeaderLabels([
             translate('OpenLP.ShortcutListDialog', 'Action'),
             translate('OpenLP.ShortcutListDialog', 'Shortcut'),
             translate('OpenLP.ShortcutListDialog', 'Alternate')])
-        self.defaultButton.setText(
-            translate('OpenLP.ShortcutListDialog', 'Default: %s'))
-        self.customButton.setText(
-            translate('OpenLP.ShortcutListDialog', 'Custom:'))
-        self.shortcutButton.setText(
-            translate('OpenLP.ShortcutListDialog', 'None'))
+        self.defaultRadioButton.setText(
+            translate('OpenLP.ShortcutListDialog', 'Default'))
+        self.customRadioButton.setText(
+            translate('OpenLP.ShortcutListDialog', 'Custom'))
+        self.primaryPushButton.setToolTip(
+            translate('OpenLP.ShortcutListDialog', 'Capture shortcut.'))
+        self.alternatePushButton.setToolTip(
+            translate('OpenLP.ShortcutListDialog', 'Capture shortcut.'))
+        self.clearPrimaryButton.setToolTip(
+            translate('OpenLP.ShortcutListDialog',
+            'Restore the default shortcut of this action.'))
+        self.clearAlternateButton.setToolTip(
+            translate('OpenLP.ShortcutListDialog',
+            'Restore the default shortcut of this action.'))

=== modified file 'openlp/core/ui/shortcutlistform.py'
--- openlp/core/ui/shortcutlistform.py	2011-03-24 19:04:02 +0000
+++ openlp/core/ui/shortcutlistform.py	2011-04-09 16:26:46 +0000
@@ -30,6 +30,7 @@
 from PyQt4 import QtCore, QtGui
 
 from openlp.core.utils import translate
+from openlp.core.utils.actions import ActionList
 from shortcutlistdialog import Ui_ShortcutListDialog
 
 REMOVE_AMPERSAND = re.compile(r'&{1}')
@@ -41,20 +42,45 @@
     The shortcut list dialog
     """
 
-    def __init__(self, parent):
-        """
-        Do some initialisation stuff
-        """
+    def __init__(self, parent=None):
         QtGui.QDialog.__init__(self, parent)
         self.setupUi(self)
-        self.actionList = None
-        self.captureShortcut = False
-        QtCore.QObject.connect(self.shortcutButton,
-            QtCore.SIGNAL(u'toggled(bool)'), self.onShortcutButtonClicked)
+        self.changedActions = {}
+        self.action_list = ActionList.get_instance()
+        QtCore.QObject.connect(self.primaryPushButton,
+            QtCore.SIGNAL(u'toggled(bool)'), self.onPrimaryPushButtonClicked)
+        QtCore.QObject.connect(self.alternatePushButton,
+            QtCore.SIGNAL(u'toggled(bool)'), self.onAlternatePushButtonClicked)
+        QtCore.QObject.connect(self.treeWidget, QtCore.SIGNAL(
+            u'currentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*)'),
+            self.onCurrentItemChanged)
+        QtCore.QObject.connect(self.treeWidget,
+            QtCore.SIGNAL(u'itemDoubleClicked(QTreeWidgetItem*, int)'),
+            self.onItemDoubleClicked)
+        QtCore.QObject.connect(self.clearPrimaryButton,
+            QtCore.SIGNAL(u'clicked(bool)'), self.onClearPrimaryButtonClicked)
+        QtCore.QObject.connect(self.clearAlternateButton,
+            QtCore.SIGNAL(u'clicked(bool)'), self.onClearAlternateButtonClicked)
+        QtCore.QObject.connect(self.buttonBox,
+            QtCore.SIGNAL(u'clicked(QAbstractButton*)'),
+            self.onRestoreDefaultsClicked)
+        QtCore.QObject.connect(self.defaultRadioButton,
+            QtCore.SIGNAL(u'clicked(bool)'), self.onDefaultRadioButtonClicked)
+        QtCore.QObject.connect(self.customRadioButton,
+            QtCore.SIGNAL(u'clicked(bool)'), self.onCustomRadioButtonClicked)
+
+    def keyPressEvent(self, event):
+        if self.primaryPushButton.isChecked() or \
+            self.alternatePushButton.isChecked():
+            event.ignore()
+        elif event.key() == QtCore.Qt.Key_Escape:
+            event.accept()
+            self.close()
 
     def keyReleaseEvent(self, event):
         Qt = QtCore.Qt
-        if not self.captureShortcut:
+        if not self.primaryPushButton.isChecked() and \
+            not self.alternatePushButton.isChecked():
             return
         key = event.key()
         if key == Qt.Key_Shift or key == Qt.Key_Control or \
@@ -68,45 +94,336 @@
         if event.modifiers() & Qt.ShiftModifier == Qt.ShiftModifier:
             key_string = u'Shift+' + key_string
         key_sequence = QtGui.QKeySequence(key_string)
-        existing_key = QtGui.QKeySequence(u'Ctrl+Shift+F8')
-        if key_sequence == existing_key:
-            QtGui.QMessageBox.warning(
-                self,
+        # The action we are attempting to change.
+        changing_action = self._currentItemAction()
+        shortcut_valid = True
+        for category in self.action_list.categories:
+            for action in category.actions:
+                shortcuts = self._actionShortcuts(action)
+                if key_sequence not in shortcuts:
+                    continue
+                if action is changing_action:
+                    if self.primaryPushButton.isChecked() and \
+                        shortcuts.index(key_sequence) == 0:
+                        continue
+                    if self.alternatePushButton.isChecked() and \
+                        shortcuts.index(key_sequence) == 1:
+                        continue
+                # Have the same parent, thus they cannot have the same shortcut.
+                if action.parent() is changing_action.parent():
+                    shortcut_valid = False
+                # The new shortcut is already assigned, but if both shortcuts
+                # are only valid in a different widget the new shortcut is
+                # vaild, because they will not interfere.
+                if action.shortcutContext() in [QtCore.Qt.WindowShortcut,
+                    QtCore.Qt.ApplicationShortcut]:
+                    shortcut_valid = False
+                if changing_action.shortcutContext() in \
+                    [QtCore.Qt.WindowShortcut, QtCore.Qt.ApplicationShortcut]:
+                    shortcut_valid = False
+        if not shortcut_valid:
+            QtGui.QMessageBox.warning(self,
                 translate('OpenLP.ShortcutListDialog', 'Duplicate Shortcut'),
                 unicode(translate('OpenLP.ShortcutListDialog', 'The shortcut '
-                    '"%s" is already assigned to another action, please '
-                    'use a different shortcut.')) % key_sequence.toString(),
+                '"%s" is already assigned to another action, please '
+                'use a different shortcut.')) % key_sequence.toString(),
                 QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Ok),
                 QtGui.QMessageBox.Ok
             )
         else:
-            self.shortcutButton.setText(key_sequence.toString())
-        self.shortcutButton.setChecked(False)
-        self.captureShortcut = False
+            if self.primaryPushButton.isChecked():
+                self._adjustButton(self.primaryPushButton,
+                    False, text=key_sequence.toString())
+            elif self.alternatePushButton.isChecked():
+                self._adjustButton(self.alternatePushButton,
+                    False, text=key_sequence.toString())
 
-    def exec_(self, actionList):
-        self.actionList = actionList
-        self.refreshActions()
+    def exec_(self):
+        self.changedActions = {}
+        self.reloadShortcutList()
+        self._adjustButton(self.primaryPushButton, False, False, u'')
+        self._adjustButton(self.alternatePushButton, False, False, u'')
         return QtGui.QDialog.exec_(self)
 
-    def refreshActions(self):
+    def reloadShortcutList(self):
+        """
+        Reload the ``treeWidget`` list to add new and remove old actions.
+        """
         self.treeWidget.clear()
-        for category in self.actionList.categories:
+        for category in self.action_list.categories:
+            # Check if the category is for internal use only.
+            if category.name is None:
+                continue
             item = QtGui.QTreeWidgetItem([category.name])
             for action in category.actions:
                 actionText = REMOVE_AMPERSAND.sub('', unicode(action.text()))
-                if (len(action.shortcuts()) == 2):
-                    shortcutText = action.shortcuts()[0].toString()
-                    alternateText = action.shortcuts()[1].toString()
-                else:
-                    shortcutText = action.shortcut().toString()
-                    alternateText = u''
-                actionItem = QtGui.QTreeWidgetItem(
-                    [actionText, shortcutText, alternateText])
+                actionItem = QtGui.QTreeWidgetItem([actionText])
                 actionItem.setIcon(0, action.icon())
+                actionItem.setData(0,
+                    QtCore.Qt.UserRole, QtCore.QVariant(action))
                 item.addChild(actionItem)
+            self.treeWidget.addTopLevelItem(item)
             item.setExpanded(True)
-            self.treeWidget.addTopLevelItem(item)
-
-    def onShortcutButtonClicked(self, toggled):
-        self.captureShortcut = toggled
+        self.refreshShortcutList()
+
+    def refreshShortcutList(self):
+        """
+        This refreshes the item's shortcuts shown in the list. Note, this
+        neither adds new actions nor removes old actions.
+        """
+        iterator = QtGui.QTreeWidgetItemIterator(self.treeWidget)
+        while iterator.value():
+            item = iterator.value()
+            iterator += 1
+            action = self._currentItemAction(item)
+            if action is None:
+                continue
+            shortcuts = self._actionShortcuts(action)
+            if len(shortcuts) == 0:
+                item.setText(1, u'')
+                item.setText(2, u'')
+            elif len(shortcuts) == 1:
+                item.setText(1, shortcuts[0].toString())
+                item.setText(2, u'')
+            else:
+                item.setText(1, shortcuts[0].toString())
+                item.setText(2, shortcuts[1].toString())
+        self.onCurrentItemChanged()
+
+    def onPrimaryPushButtonClicked(self, toggled):
+        """
+        Save the new primary shortcut.
+        """
+        self.customRadioButton.setChecked(True)
+        if toggled:
+            self.alternatePushButton.setChecked(False)
+            return
+        action = self._currentItemAction()
+        if action is None:
+            return
+        shortcuts = self._actionShortcuts(action)
+        new_shortcuts = [QtGui.QKeySequence(self.primaryPushButton.text())]
+        if len(shortcuts) == 2:
+            new_shortcuts.append(shortcuts[1])
+        self.changedActions[action] = new_shortcuts
+        self.refreshShortcutList()
+
+    def onAlternatePushButtonClicked(self, toggled):
+        """
+        Save the new alternate shortcut.
+        """
+        self.customRadioButton.setChecked(True)
+        if toggled:
+            self.primaryPushButton.setChecked(False)
+            return
+        action = self._currentItemAction()
+        if action is None:
+            return
+        shortcuts = self._actionShortcuts(action)
+        new_shortcuts = []
+        if len(shortcuts) != 0:
+            new_shortcuts.append(shortcuts[0])
+        new_shortcuts.append(
+            QtGui.QKeySequence(self.alternatePushButton.text()))
+        self.changedActions[action] = new_shortcuts
+        self.refreshShortcutList()
+
+    def onItemDoubleClicked(self, item, column):
+        """
+        A item has been double clicked. The ``primaryPushButton`` will be
+        checked and the item's shortcut will be displayed.
+        """
+        action = self._currentItemAction(item)
+        if action is None:
+            return
+        self.primaryPushButton.setChecked(column in [0, 1])
+        self.alternatePushButton.setChecked(column not in [0, 1])
+        if column in [0, 1]:
+            self.primaryPushButton.setFocus(QtCore.Qt.OtherFocusReason)
+        else:
+            self.alternatePushButton.setFocus(QtCore.Qt.OtherFocusReason)
+        self.onCurrentItemChanged(item)
+
+    def onCurrentItemChanged(self, item=None, previousItem=None):
+        """
+        A item has been pressed. We adjust the button's text to the action's
+        shortcut which is encapsulate in the item.
+        """
+        action = self._currentItemAction(item)
+        self.primaryPushButton.setEnabled(action is not None)
+        self.alternatePushButton.setEnabled(action is not None)
+        primary_text = u''
+        alternate_text = u''
+        primary_label_text = u''
+        alternate_label_text = u''
+        if action is None:
+            self.primaryPushButton.setChecked(False)
+            self.alternatePushButton.setChecked(False)
+        else:
+            if len(action.defaultShortcuts) != 0:
+                primary_label_text = action.defaultShortcuts[0].toString()
+                if len(action.defaultShortcuts) == 2:
+                    alternate_label_text = action.defaultShortcuts[1].toString()
+            shortcuts = self._actionShortcuts(action)
+            # We do not want to loose pending changes, that is why we have to
+            # keep the text when, this function has not been triggered by a signal.
+            if item is None:
+                primary_text = self.primaryPushButton.text()
+                alternate_text = self.alternatePushButton.text()
+            elif len(shortcuts) == 1:
+                primary_text = shortcuts[0].toString()
+            elif len(shortcuts) == 2:
+                primary_text = shortcuts[0].toString()
+                alternate_text = shortcuts[1].toString()
+        self.primaryPushButton.setText(primary_text)
+        self.alternatePushButton.setText(alternate_text)
+        self.primaryLabel.setText(primary_label_text)
+        self.alternateLabel.setText(alternate_label_text)
+        # We do not want to toggle and radio button, as the function has not
+        # been triggered by a signal.
+        if item is None:
+            return
+        if primary_label_text == primary_text and \
+            alternate_label_text == alternate_text:
+            self.defaultRadioButton.toggle()
+        else:
+            self.customRadioButton.toggle()
+
+    def onRestoreDefaultsClicked(self, button):
+        """
+        Restores all default shortcuts.
+        """
+        if self.buttonBox.buttonRole(button) != QtGui.QDialogButtonBox.ResetRole:
+            return
+        if QtGui.QMessageBox.question(self,
+            translate('OpenLP.ShortcutListDialog', 'Restore Default Shortcuts'),
+            translate('OpenLP.ShortcutListDialog', 'Do you want to restore all '
+            'shortcuts to their defaults?'), QtGui.QMessageBox.StandardButtons(
+            QtGui.QMessageBox.Yes |
+            QtGui.QMessageBox.No)) == QtGui.QMessageBox.No:
+            return
+        self._adjustButton(self.primaryPushButton, False, text=u'')
+        self._adjustButton(self.alternatePushButton, False, text=u'')
+        for category in self.action_list.categories:
+            for action in category.actions:
+                self.changedActions[action] = action.defaultShortcuts
+        self.refreshShortcutList()
+
+    def onDefaultRadioButtonClicked(self, toggled):
+        """
+        The default radio button has been clicked, which means we have to make
+        sure, that we use the default shortcuts for the action.
+        """
+        if not toggled:
+            return
+        action = self._currentItemAction()
+        if action is None:
+            return
+        temp_shortcuts = self._actionShortcuts(action)
+        self.changedActions[action] = action.defaultShortcuts
+        self.refreshShortcutList()
+        primary_button_text = u''
+        alternate_button_text = u''
+        if len(temp_shortcuts) != 0:
+            primary_button_text = temp_shortcuts[0].toString()
+        if len(temp_shortcuts) == 2:
+            alternate_button_text = temp_shortcuts[1].toString()
+        self.primaryPushButton.setText(primary_button_text)
+        self.alternatePushButton.setText(alternate_button_text)
+
+    def onCustomRadioButtonClicked(self, toggled):
+        """
+        The custom shortcut radio button was clicked, thus we have to restore
+        the custom shortcuts by calling those functions triggered by button
+        clicks.
+        """
+        if not toggled:
+            return
+        self.onPrimaryPushButtonClicked(False)
+        self.onAlternatePushButtonClicked(False)
+        self.refreshShortcutList()
+
+    def save(self):
+        """
+        Save the shortcuts. **Note**, that we do not have to load the shortcuts,
+        as they are loaded in :class:`~openlp.core.utils.ActionList`.
+        """
+        settings = QtCore.QSettings()
+        settings.beginGroup(u'shortcuts')
+        for category in self.action_list.categories:
+            # Check if the category is for internal use only.
+            if category.name is None:
+                continue
+            for action in category.actions:
+                if self.changedActions .has_key(action):
+                    action.setShortcuts(self.changedActions[action])
+                settings.setValue(
+                    action.objectName(), QtCore.QVariant(action.shortcuts()))
+        settings.endGroup()
+
+    def onClearPrimaryButtonClicked(self, toggled):
+        """
+        Restore the defaults of this action.
+        """
+        self.primaryPushButton.setChecked(False)
+        action = self._currentItemAction()
+        if action is None:
+            return
+        shortcuts = self._actionShortcuts(action)
+        new_shortcuts = []
+        if len(action.defaultShortcuts) != 0:
+            new_shortcuts.append(action.defaultShortcuts[0])
+        if len(shortcuts) == 2:
+            new_shortcuts.append(shortcuts[1])
+        self.changedActions[action] = new_shortcuts
+        self.refreshShortcutList()
+
+    def onClearAlternateButtonClicked(self, toggled):
+        """
+        Restore the defaults of this action.
+        """
+        self.alternatePushButton.setChecked(False)
+        action = self._currentItemAction()
+        if action is None:
+            return
+        shortcuts = self._actionShortcuts(action)
+        new_shortcuts = []
+        if len(shortcuts) != 0:
+            new_shortcuts.append(shortcuts[0])
+        if len(action.defaultShortcuts) == 2:
+            new_shortcuts.append(action.defaultShortcuts[1])
+        self.changedActions[action] = new_shortcuts
+        self.refreshShortcutList()
+
+    def _actionShortcuts(self, action):
+        """
+        This returns the shortcuts for the given ``action``, which also includes
+        those shortcuts which are not saved yet but already assigned (as changes
+        are applied when closing the dialog).
+        """
+        if self.changedActions.has_key(action):
+            return self.changedActions[action]
+        return action.shortcuts()
+
+    def _currentItemAction(self, item=None):
+        """
+        Returns the action of the given ``item``. If no item is given, we return
+        the action of the current item of the ``treeWidget``.
+        """
+        if item is None:
+            item = self.treeWidget.currentItem()
+            if item is None:
+                return
+        return item.data(0, QtCore.Qt.UserRole).toPyObject()
+
+    def _adjustButton(self, button, checked=None, enabled=None, text=None):
+        """
+        Can be called to adjust more properties of the given ``button`` at once.
+        """
+        # Set the text before checking the button, because this emits a signal.
+        if text is not None:
+            button.setText(text)
+        if checked is not None:
+            button.setChecked(checked)
+        if enabled is not None:
+            button.setEnabled(enabled)

=== modified file 'openlp/core/ui/slidecontroller.py'
--- openlp/core/ui/slidecontroller.py	2011-04-05 14:24:51 +0000
+++ openlp/core/ui/slidecontroller.py	2011-04-09 16:26:46 +0000
@@ -32,8 +32,9 @@
 
 from openlp.core.lib import OpenLPToolbar, Receiver, resize_image, \
     ItemCapabilities, translate
-from openlp.core.lib.ui import icon_action, UiStrings, shortcut_action
+from openlp.core.lib.ui import UiStrings, shortcut_action
 from openlp.core.ui import HideMode, MainDisplay
+from openlp.core.utils.actions import ActionList, CategoryOrder
 
 log = logging.getLogger(__name__)
 
@@ -140,12 +141,16 @@
             translate('OpenLP.SlideController', 'Previous Slide'),
             u':/slides/slide_previous.png',
             translate('OpenLP.SlideController', 'Move to previous'),
-            self.onSlideSelectedPrevious)
+            self.onSlideSelectedPrevious,
+            shortcuts=[QtCore.Qt.Key_Up, QtCore.Qt.Key_PageUp],
+            context=QtCore.Qt.WidgetWithChildrenShortcut)
         self.nextItem = self.toolbar.addToolbarButton(
             translate('OpenLP.SlideController', 'Next Slide'),
             u':/slides/slide_next.png',
             translate('OpenLP.SlideController', 'Move to next'),
-            self.onSlideSelectedNext)
+            self.onSlideSelectedNext,
+            shortcuts=[QtCore.Qt.Key_Down, QtCore.Qt.Key_PageDown],
+            context=QtCore.Qt.WidgetWithChildrenShortcut)
         self.toolbar.addToolbarSeparator(u'Close Separator')
         if self.isLive:
             self.hideMenu = QtGui.QToolButton(self.toolbar)
@@ -154,16 +159,20 @@
             self.toolbar.addToolbarWidget(u'Hide Menu', self.hideMenu)
             self.hideMenu.setMenu(QtGui.QMenu(
                 translate('OpenLP.SlideController', 'Hide'), self.toolbar))
-            self.blankScreen = icon_action(self.hideMenu, u'Blank Screen',
-                u':/slides/slide_blank.png', False)
+            self.blankScreen = shortcut_action(self.hideMenu, u'blankScreen',
+                [QtCore.Qt.Key_Period], self.onBlankDisplay,
+                u':/slides/slide_blank.png', False, UiStrings.LiveToolbar)
             self.blankScreen.setText(
                 translate('OpenLP.SlideController', 'Blank Screen'))
-            self.themeScreen = icon_action(self.hideMenu, u'Blank Theme',
-                u':/slides/slide_theme.png', False)
+            self.themeScreen = shortcut_action(self.hideMenu, u'themeScreen',
+                [QtGui.QKeySequence(u'T')], self.onThemeDisplay,
+                u':/slides/slide_theme.png', False, UiStrings.LiveToolbar)
             self.themeScreen.setText(
                 translate('OpenLP.SlideController', 'Blank to Theme'))
-            self.desktopScreen = icon_action(self.hideMenu, u'Desktop Screen',
-                u':/slides/slide_desktop.png', False)
+            self.desktopScreen = shortcut_action(self.hideMenu,
+                u'desktopScreen', [QtGui.QKeySequence(u'D')],
+                self.onHideDisplay, u':/slides/slide_desktop.png', False,
+                UiStrings.LiveToolbar)
             self.desktopScreen.setText(
                 translate('OpenLP.SlideController', 'Show Desktop'))
             self.hideMenu.setDefaultAction(self.blankScreen)
@@ -291,12 +300,6 @@
         QtCore.QObject.connect(self.previewListWidget,
             QtCore.SIGNAL(u'clicked(QModelIndex)'), self.onSlideSelected)
         if self.isLive:
-            QtCore.QObject.connect(self.blankScreen,
-                QtCore.SIGNAL(u'triggered(bool)'), self.onBlankDisplay)
-            QtCore.QObject.connect(self.themeScreen,
-                QtCore.SIGNAL(u'triggered(bool)'), self.onThemeDisplay)
-            QtCore.QObject.connect(self.desktopScreen,
-                QtCore.SIGNAL(u'triggered(bool)'), self.onHideDisplay)
             QtCore.QObject.connect(self.volumeSlider,
                 QtCore.SIGNAL(u'sliderReleased()'), self.mediaVolume)
             QtCore.QObject.connect(Receiver.get_receiver(),
@@ -362,33 +365,37 @@
             QtCore.SIGNAL(u'config_screen_changed'), self.screenSizeChanged)
 
     def setPreviewHotkeys(self, parent=None):
-        actionList = self.parent.actionList
-        self.previousItem.setShortcuts([QtCore.Qt.Key_Up, 0])
-        actionList.add_action(self.previousItem, u'Preview')
-        self.nextItem.setShortcuts([QtCore.Qt.Key_Down, 0])
-        actionList.add_action(self.nextItem, u'Preview')
+        self.previousItem.setObjectName(u'previousItemPreview')         
+        self.nextItem.setObjectName(u'nextItemPreview')
+        action_list = ActionList.get_instance()
+        action_list.add_category(
+            UiStrings.PreviewToolbar, CategoryOrder.standardToolbar)
+        action_list.add_action(self.previousItem, UiStrings.PreviewToolbar)
+        action_list.add_action(self.nextItem, UiStrings.PreviewToolbar)
 
     def setLiveHotkeys(self, parent=None):
-        actionList = self.parent.actionList
-        self.previousItem.setShortcuts([QtCore.Qt.Key_Up, QtCore.Qt.Key_PageUp])
-        self.previousItem.setShortcutContext(
-            QtCore.Qt.WidgetWithChildrenShortcut)
-        actionList.add_action(self.previousItem, u'Live')
-        self.nextItem.setShortcuts([QtCore.Qt.Key_Down, QtCore.Qt.Key_PageDown])
-        self.nextItem.setShortcutContext(QtCore.Qt.WidgetWithChildrenShortcut)
-        actionList.add_action(self.nextItem, u'Live')
-        self.previousService = shortcut_action(parent,
-            translate('OpenLP.SlideController', 'Previous Service'),
-            [QtCore.Qt.Key_Left, 0], self.servicePrevious)
-        actionList.add_action(self.previousService, u'Live')
-        self.nextService = shortcut_action(parent,
-            translate('OpenLP.SlideController', 'Next Service'),
-            [QtCore.Qt.Key_Right, 0], self.serviceNext)
-        actionList.add_action(self.nextService, u'Live')
-        self.escapeItem = shortcut_action(parent,
-            translate('OpenLP.SlideController', 'Escape Item'),
-            [QtCore.Qt.Key_Escape, 0], self.liveEscape)
-        actionList.add_action(self.escapeItem, u'Live')
+        self.previousItem.setObjectName(u'previousItemLive')         
+        self.nextItem.setObjectName(u'nextItemLive')
+        action_list = ActionList.get_instance()
+        action_list.add_category(
+            UiStrings.LiveToolbar, CategoryOrder.standardToolbar)
+        action_list.add_action(self.previousItem, UiStrings.LiveToolbar)
+        action_list.add_action(self.nextItem, UiStrings.LiveToolbar)
+        self.previousService = shortcut_action(parent, u'previousService',
+            [QtCore.Qt.Key_Left], self.servicePrevious, UiStrings.LiveToolbar)
+        self.previousService.setShortcutContext(QtCore.Qt.WidgetWithChildrenShortcut)
+        self.previousService.setText(
+            translate('OpenLP.SlideController', 'Previous Service'))
+        self.nextService = shortcut_action(parent, 'nextService',
+            [QtCore.Qt.Key_Right], self.serviceNext, UiStrings.LiveToolbar)
+        self.nextService.setShortcutContext(QtCore.Qt.WidgetWithChildrenShortcut)
+        self.nextService.setText(
+            translate('OpenLP.SlideController', 'Next Service'))
+        self.escapeItem = shortcut_action(parent, 'escapeItem',
+            [QtCore.Qt.Key_Escape], self.liveEscape, UiStrings.LiveToolbar)
+        self.escapeItem.setShortcutContext(QtCore.Qt.WidgetWithChildrenShortcut)
+        self.escapeItem.setText(
+            translate('OpenLP.SlideController', 'Escape Item'))
 
     def liveEscape(self):
         self.display.setVisible(False)
@@ -741,10 +748,12 @@
         """
         self.onBlankDisplay(False)
 
-    def onBlankDisplay(self, checked):
+    def onBlankDisplay(self, checked=None):
         """
         Handle the blank screen button actions
         """
+        if checked is None:
+            checked = self.blankScreen.isChecked()
         log.debug(u'onBlankDisplay %s' % checked)
         self.hideMenu.setDefaultAction(self.blankScreen)
         self.blankScreen.setChecked(checked)
@@ -762,10 +771,12 @@
         self.blankPlugin(checked)
         self.updatePreview()
 
-    def onThemeDisplay(self, checked):
+    def onThemeDisplay(self, checked=None):
         """
         Handle the Theme screen button
         """
+        if checked is None:
+            checked = self.themeScreen.isChecked()
         log.debug(u'onThemeDisplay %s' % checked)
         self.hideMenu.setDefaultAction(self.themeScreen)
         self.blankScreen.setChecked(False)
@@ -783,10 +794,12 @@
         self.blankPlugin(checked)
         self.updatePreview()
 
-    def onHideDisplay(self, checked):
+    def onHideDisplay(self, checked=None):
         """
         Handle the Hide screen button
         """
+        if checked is None:
+            checked = self.desktopScreen.isChecked()
         log.debug(u'onHideDisplay %s' % checked)
         self.hideMenu.setDefaultAction(self.desktopScreen)
         self.blankScreen.setChecked(False)

=== modified file 'openlp/core/utils/__init__.py'
--- openlp/core/utils/__init__.py	2011-03-25 16:29:39 +0000
+++ openlp/core/utils/__init__.py	2011-04-09 16:26:46 +0000
@@ -495,7 +495,7 @@
 from languagemanager import LanguageManager
 from actions import ActionList
 
-__all__ = [u'AppLocation', u'check_latest_version', u'add_actions',
-    u'get_filesystem_encoding', u'LanguageManager', u'ActionList',
-    u'get_web_page', u'file_is_unicode', u'string_is_unicode',
+__all__ = [u'AppLocation', u'get_application_version', u'check_latest_version',
+    u'add_actions', u'get_filesystem_encoding', u'LanguageManager',
+    u'ActionList', u'get_web_page', u'file_is_unicode', u'string_is_unicode',
     u'get_uno_command', u'get_uno_instance', u'delete_file']

=== modified file 'openlp/core/utils/actions.py'
--- openlp/core/utils/actions.py	2011-03-24 19:04:02 +0000
+++ openlp/core/utils/actions.py	2011-04-09 16:26:46 +0000
@@ -27,6 +27,8 @@
 The :mod:`~openlp.core.utils.actions` module provides action list classes used
 by the shortcuts system.
 """
+from PyQt4 import QtCore, QtGui
+
 class ActionCategory(object):
     """
     The :class:`~openlp.core.utils.ActionCategory` class encapsulates a
@@ -67,6 +69,7 @@
         Python 3 "next" method.
         """
         if self.index >= len(self.actions):
+            self.index = 0
             raise StopIteration
         else:
             self.index += 1
@@ -94,6 +97,12 @@
         self.actions.append((weight, action))
         self.actions.sort(key=lambda act: act[0])
 
+    def remove(self, remove_action):
+        for action in self.actions:
+            if action[1] == remove_action:
+                self.actions.remove(action)
+                return
+
 
 class CategoryList(object):
     """
@@ -126,6 +135,7 @@
         Python 3 "next" method for iterator.
         """
         if self.index >= len(self.categories):
+            self.index = 0
             raise StopIteration
         else:
             self.index += 1
@@ -144,13 +154,10 @@
         return False
 
     def append(self, name, actions=None):
-        weight = 0
-        if len(self.categories) > 0:
-            weight = self.categories[-1].weight + 1
         if actions:
-            self.add(name, weight, actions)
+            self.add(name, actions=actions)
         else:
-            self.add(name, weight)
+            self.add(name)
 
     def add(self, name, weight=0, actions=None):
         category = ActionCategory(name, weight)
@@ -161,7 +168,12 @@
                 else:
                     category.actions.append(action)
         self.categories.append(category)
-        self.categories.sort(key=lambda cat: cat.weight)
+        self.categories.sort(key=lambda cat: cat.weight, reverse=True)
+
+    def remove(self, name):
+        for category in self.categories:
+            if category.name == name:
+                self.categories.remove(category)
 
 
 class ActionList(object):
@@ -171,13 +183,102 @@
     has a weight by which it is sorted when iterating through the list of
     actions or categories.
     """
+    instance = None
+
     def __init__(self):
         self.categories = CategoryList()
 
-    def add_action(self, action, category=u'Default', weight=None):
+    @staticmethod
+    def get_instance():
+        if ActionList.instance is None:
+            ActionList.instance = ActionList()
+        return ActionList.instance
+
+    def add_action(self, action, category=None, weight=None):
+        """
+        Add an action to the list of actions.
+
+        ``action``
+            The action to add (QAction).
+
+        ``category``
+            The category this action belongs to. The category can be a QString
+            or python unicode string. **Note**, if the category is ``None``, the
+            category and its actions are being hidden in the shortcut dialog.
+            However, if they are added, it is possible to avoid assigning
+            shortcuts twice, which is important.
+
+        ``weight``
+            The weight specifies how important a category is. However, this only
+            has an impact on the order the categories are displayed.
+        """
+        if category is not None:
+            category = unicode(category)
         if category not in self.categories:
             self.categories.append(category)
+        action.defaultShortcuts = action.shortcuts()
         if weight is None:
             self.categories[category].actions.append(action)
         else:
             self.categories[category].actions.add(action, weight)
+        if category is None:
+            # Stop here, as this action is not configurable.
+            return
+        # Load the shortcut from the config.
+        settings = QtCore.QSettings()
+        settings.beginGroup(u'shortcuts')
+        shortcuts = settings.value(action.objectName(),
+            QtCore.QVariant(action.shortcuts())).toStringList()
+        action.setShortcuts(
+            [QtGui.QKeySequence(shortcut) for shortcut in shortcuts])
+        settings.endGroup()
+
+    def remove_action(self, action, category=None):
+        """
+        This removes an action from its category. Empty categories are
+        automatically removed.
+
+        ``action``
+            The QAction object to be removed.
+
+        ``category``
+            The name (unicode string) of the category, which contains the
+            action. Defaults to None.
+        """
+        if category is not None:
+            category = unicode(category)
+        if category not in self.categories:
+            return
+        self.categories[category].actions.remove(action)
+        # Remove empty categories.
+        if len(self.categories[category].actions) == 0:
+            self.categories.remove(category)
+
+    def add_category(self, name, weight):
+        """
+        Add an empty category to the list of categories. This is ony convenient
+        for categories with a given weight.
+
+        ``name``
+            The category's name.
+
+        ``weight``
+            The category's weight (int).
+        """
+        if name in self.categories:
+            # Only change the weight and resort the categories again.
+            for category in self.categories:
+                if category.name == name:
+                    category.weight = weight
+            self.categories.categories.sort(
+                key=lambda cat: cat.weight, reverse=True)
+            return
+        self.categories.add(name, weight)
+
+
+class CategoryOrder(object):
+    """
+    An enumeration class for category weights.
+    """
+    standardMenu = 100
+    standardToolbar = 90

=== modified file 'openlp/plugins/alerts/alertsplugin.py'
--- openlp/plugins/alerts/alertsplugin.py	2011-03-24 19:04:02 +0000
+++ openlp/plugins/alerts/alertsplugin.py	2011-04-09 16:26:46 +0000
@@ -30,6 +30,8 @@
 
 from openlp.core.lib import Plugin, StringContent, build_icon, translate
 from openlp.core.lib.db import Manager
+from openlp.core.lib.ui import icon_action, UiStrings
+from openlp.core.utils.actions import ActionList
 from openlp.plugins.alerts.lib import AlertsManager, AlertsTab
 from openlp.plugins.alerts.lib.db import init_schema
 from openlp.plugins.alerts.forms import AlertForm
@@ -58,9 +60,8 @@
             use it as their parent.
         """
         log.info(u'add tools menu')
-        self.toolsAlertItem = QtGui.QAction(tools_menu)
-        self.toolsAlertItem.setIcon(build_icon(u':/plugins/plugin_alerts.png'))
-        self.toolsAlertItem.setObjectName(u'toolsAlertItem')
+        self.toolsAlertItem = icon_action(tools_menu, u'toolsAlertItem',
+            u':/plugins/plugin_alerts.png')
         self.toolsAlertItem.setText(translate('AlertsPlugin', '&Alert'))
         self.toolsAlertItem.setStatusTip(
             translate('AlertsPlugin', 'Show an alert message.'))
@@ -74,6 +75,8 @@
         log.info(u'Alerts Initialising')
         Plugin.initialise(self)
         self.toolsAlertItem.setVisible(True)
+        action_list = ActionList.get_instance()
+        action_list.add_action(self.toolsAlertItem, UiStrings.Tools)
         self.liveController.alertTab = self.settings_tab
 
     def finalise(self):
@@ -84,6 +87,8 @@
         self.manager.finalise()
         Plugin.finalise(self)
         self.toolsAlertItem.setVisible(False)
+        action_list = ActionList.get_instance()
+        action_list.remove_action(self.toolsAlertItem, u'Tools')
 
     def toggleAlertsState(self):
         self.alertsActive = not self.alertsActive

=== modified file 'openlp/plugins/bibles/bibleplugin.py'
--- openlp/plugins/bibles/bibleplugin.py	2011-03-24 19:04:02 +0000
+++ openlp/plugins/bibles/bibleplugin.py	2011-04-09 16:26:46 +0000
@@ -29,6 +29,8 @@
 from PyQt4 import QtCore, QtGui
 
 from openlp.core.lib import Plugin, StringContent, build_icon, translate
+from openlp.core.lib.ui import base_action, UiStrings
+from openlp.core.utils.actions import ActionList
 from openlp.plugins.bibles.lib import BibleManager, BiblesTab, BibleMediaItem
 
 log = logging.getLogger(__name__)
@@ -50,6 +52,10 @@
             self.manager = BibleManager(self)
         Plugin.initialise(self)
         self.importBibleItem.setVisible(True)
+        action_list = ActionList.get_instance()
+        action_list.add_action(self.importBibleItem, UiStrings.Import)
+        # Do not add the action to the list yet.
+        #action_list.add_action(self.exportBibleItem, UiStrings.Export)
         # Set to invisible until we can export bibles
         self.exportBibleItem.setVisible(False)
 
@@ -60,25 +66,25 @@
         log.info(u'Plugin Finalise')
         self.manager.finalise()
         Plugin.finalise(self)
+        action_list = ActionList.get_instance()
+        action_list.remove_action(self.importBibleItem, UiStrings.Import)
         self.importBibleItem.setVisible(False)
+        #action_list.remove_action(self.exportBibleItem, UiStrings.Export)
         self.exportBibleItem.setVisible(False)
 
     def addImportMenuItem(self, import_menu):
-        self.importBibleItem = QtGui.QAction(import_menu)
-        self.importBibleItem.setObjectName(u'importBibleItem')
+        self.importBibleItem = base_action(import_menu, u'importBibleItem')
+        self.importBibleItem.setText(translate('BiblesPlugin', '&Bible'))
         import_menu.addAction(self.importBibleItem)
-        self.importBibleItem.setText(
-            translate('BiblesPlugin', '&Bible'))
         # signals and slots
         QtCore.QObject.connect(self.importBibleItem,
             QtCore.SIGNAL(u'triggered()'), self.onBibleImportClick)
         self.importBibleItem.setVisible(False)
 
     def addExportMenuItem(self, export_menu):
-        self.exportBibleItem = QtGui.QAction(export_menu)
-        self.exportBibleItem.setObjectName(u'exportBibleItem')
+        self.exportBibleItem = base_action(export_menu, u'exportBibleItem')
+        self.exportBibleItem.setText(translate('BiblesPlugin', '&Bible'))
         export_menu.addAction(self.exportBibleItem)
-        self.exportBibleItem.setText(translate('BiblesPlugin', '&Bible'))
         self.exportBibleItem.setVisible(False)
 
     def onBibleImportClick(self):

=== modified file 'openlp/plugins/songs/songsplugin.py'
--- openlp/plugins/songs/songsplugin.py	2011-03-30 18:52:58 +0000
+++ openlp/plugins/songs/songsplugin.py	2011-04-09 16:26:46 +0000
@@ -33,7 +33,8 @@
 from openlp.core.lib import Plugin, StringContent, build_icon, translate, \
     Receiver
 from openlp.core.lib.db import Manager
-from openlp.core.lib.ui import UiStrings
+from openlp.core.lib.ui import UiStrings, base_action, icon_action
+from openlp.core.utils.actions import ActionList
 from openlp.plugins.songs.lib import clean_song, SongMediaItem, SongsTab
 from openlp.plugins.songs.lib.db import init_schema, Song
 from openlp.plugins.songs.lib.importer import SongFormat
@@ -65,6 +66,10 @@
         log.info(u'Songs Initialising')
         Plugin.initialise(self)
         self.toolsReindexItem.setVisible(True)
+        action_list = ActionList.get_instance()
+        action_list.add_action(self.SongImportItem, UiStrings.Import)
+        action_list.add_action(self.SongExportItem, UiStrings.Export)
+        action_list.add_action(self.toolsReindexItem, UiStrings.Tools)
         self.mediaItem.displayResultsSong(
             self.manager.get_all_objects(Song, order_by_ref=Song.search_title))
 
@@ -78,10 +83,8 @@
             use it as their parent.
         """
         # Main song import menu item - will eventually be the only one
-        self.SongImportItem = QtGui.QAction(import_menu)
-        self.SongImportItem.setObjectName(u'SongImportItem')
-        self.SongImportItem.setText(translate(
-            'SongsPlugin', '&Song'))
+        self.SongImportItem = base_action(import_menu, u'SongImportItem')
+        self.SongImportItem.setText(translate('SongsPlugin', '&Song'))
         self.SongImportItem.setToolTip(translate('SongsPlugin',
             'Import songs using the import wizard.'))
         import_menu.addAction(self.SongImportItem)
@@ -99,10 +102,8 @@
             use it as their parent.
         """
         # Main song import menu item - will eventually be the only one
-        self.SongExportItem = QtGui.QAction(export_menu)
-        self.SongExportItem.setObjectName(u'SongExportItem')
-        self.SongExportItem.setText(translate(
-            'SongsPlugin', '&Song'))
+        self.SongExportItem = base_action(export_menu, u'SongExportItem')
+        self.SongExportItem.setText(translate('SongsPlugin', '&Song'))
         self.SongExportItem.setToolTip(translate('SongsPlugin',
             'Exports songs using the export wizard.'))
         export_menu.addAction(self.SongExportItem)
@@ -120,9 +121,8 @@
             use it as their parent.
         """
         log.info(u'add tools menu')
-        self.toolsReindexItem = QtGui.QAction(tools_menu)
-        self.toolsReindexItem.setIcon(build_icon(u':/plugins/plugin_songs.png'))
-        self.toolsReindexItem.setObjectName(u'toolsReindexItem')
+        self.toolsReindexItem = icon_action(tools_menu, u'toolsReindexItem',
+            u':/plugins/plugin_songs.png')
         self.toolsReindexItem.setText(
             translate('SongsPlugin', '&Re-index Songs'))
         self.toolsReindexItem.setStatusTip(
@@ -259,4 +259,8 @@
         log.info(u'Songs Finalising')
         self.manager.finalise()
         self.toolsReindexItem.setVisible(False)
+        action_list = ActionList.get_instance()
+        action_list.remove_action(self.SongImportItem, UiStrings.Import)
+        action_list.remove_action(self.SongExportItem, UiStrings.Export)
+        action_list.remove_action(self.toolsReindexItem, UiStrings.Tools)
         Plugin.finalise(self)

=== modified file 'openlp/plugins/songusage/songusageplugin.py'
--- openlp/plugins/songusage/songusageplugin.py	2011-03-24 19:04:02 +0000
+++ openlp/plugins/songusage/songusageplugin.py	2011-04-09 16:26:46 +0000
@@ -32,6 +32,8 @@
 from openlp.core.lib import Plugin, StringContent, Receiver, build_icon, \
     translate
 from openlp.core.lib.db import Manager
+from openlp.core.lib.ui import base_action, shortcut_action, UiStrings
+from openlp.core.utils.actions import ActionList
 from openlp.plugins.songusage.forms import SongUsageDetailForm, \
     SongUsageDeleteForm
 from openlp.plugins.songusage.lib.db import init_schema, SongUsageItem
@@ -63,30 +65,25 @@
         self.SongUsageMenu.setObjectName(u'SongUsageMenu')
         self.SongUsageMenu.setTitle(translate(
             'SongUsagePlugin', '&Song Usage Tracking'))
-        #SongUsage Delete
-        self.SongUsageDelete = QtGui.QAction(tools_menu)
+        # SongUsage Delete
+        self.SongUsageDelete = base_action(tools_menu, u'SongUsageDelete')
         self.SongUsageDelete.setText(translate('SongUsagePlugin',
             '&Delete Tracking Data'))
         self.SongUsageDelete.setStatusTip(translate('SongUsagePlugin',
             'Delete song usage data up to a specified date.'))
-        self.SongUsageDelete.setObjectName(u'SongUsageDelete')
-        #SongUsage Report
-        self.SongUsageReport = QtGui.QAction(tools_menu)
+        # SongUsage Report
+        self.SongUsageReport = base_action(tools_menu, u'SongUsageReport')
         self.SongUsageReport.setText(
             translate('SongUsagePlugin', '&Extract Tracking Data'))
         self.SongUsageReport.setStatusTip(
             translate('SongUsagePlugin', 'Generate a report on song usage.'))
-        self.SongUsageReport.setObjectName(u'SongUsageReport')
-        #SongUsage activation
-        self.SongUsageStatus = QtGui.QAction(tools_menu)
-        self.SongUsageStatus.setCheckable(True)
-        self.SongUsageStatus.setChecked(False)
+        # SongUsage activation
+        self.SongUsageStatus = shortcut_action(tools_menu, u'SongUsageStatus',
+            [QtCore.Qt.Key_F4], self.toggleSongUsageState, checked=False)
         self.SongUsageStatus.setText(translate(
             'SongUsagePlugin', 'Toggle Tracking'))
         self.SongUsageStatus.setStatusTip(translate('SongUsagePlugin',
                 'Toggle the tracking of song usage.'))
-        self.SongUsageStatus.setShortcut(u'F4')
-        self.SongUsageStatus.setObjectName(u'SongUsageStatus')
         #Add Menus together
         self.toolsMenu.addAction(self.SongUsageMenu.menuAction())
         self.SongUsageMenu.addAction(self.SongUsageStatus)
@@ -97,9 +94,6 @@
         QtCore.QObject.connect(self.SongUsageStatus,
             QtCore.SIGNAL(u'visibilityChanged(bool)'),
             self.SongUsageStatus.setChecked)
-        QtCore.QObject.connect(self.SongUsageStatus,
-            QtCore.SIGNAL(u'triggered(bool)'),
-            self.toggleSongUsageState)
         QtCore.QObject.connect(self.SongUsageDelete,
             QtCore.SIGNAL(u'triggered()'), self.onSongUsageDelete)
         QtCore.QObject.connect(self.SongUsageReport,
@@ -116,6 +110,13 @@
             self.settingsSection + u'/active',
             QtCore.QVariant(False)).toBool()
         self.SongUsageStatus.setChecked(self.SongUsageActive)
+        action_list = ActionList.get_instance()
+        action_list.add_action(self.SongUsageDelete,
+            translate('SongUsagePlugin', 'Song Usage'))
+        action_list.add_action(self.SongUsageReport,
+            translate('SongUsagePlugin', 'Song Usage'))
+        action_list.add_action(self.SongUsageStatus,
+            translate('SongUsagePlugin', 'Song Usage'))
         if self.manager is None:
             self.manager = Manager(u'songusage', init_schema)
         self.SongUsagedeleteform = SongUsageDeleteForm(self.manager,
@@ -131,6 +132,13 @@
         self.manager.finalise()
         Plugin.finalise(self)
         self.SongUsageMenu.menuAction().setVisible(False)
+        action_list = ActionList.get_instance()
+        action_list.remove_action(self.SongUsageDelete,
+            translate('SongUsagePlugin', 'Song Usage'))
+        action_list.remove_action(self.SongUsageReport,
+            translate('SongUsagePlugin', 'Song Usage'))
+        action_list.remove_action(self.SongUsageStatus,
+            translate('SongUsagePlugin', 'Song Usage'))
         #stop any events being processed
         self.SongUsageActive = False
 

=== modified file 'resources/forms/shortcutlistdialog.ui'
--- resources/forms/shortcutlistdialog.ui	2010-10-07 21:27:26 +0000
+++ resources/forms/shortcutlistdialog.ui	2011-04-09 16:26:46 +0000
@@ -41,36 +41,36 @@
     </widget>
    </item>
    <item>
-    <layout class="QVBoxLayout" name="shortcutLayout">
+    <layout class="QGridLayout" name="detailsLayout">
+     <property name="topMargin">
+      <number>0</number>
+     </property>
      <property name="spacing">
       <number>8</number>
      </property>
-     <property name="leftMargin">
-      <number>0</number>
-     </property>
-     <item>
+     <item row="0" column="0">
       <widget class="QRadioButton" name="defaultRadioButton">
        <property name="text">
-        <string>Default: None</string>
+        <string>Default:</string>
        </property>
        <property name="checked">
         <bool>true</bool>
        </property>
       </widget>
      </item>
-     <item>
-      <layout class="QHBoxLayout" name="customShortcutLayout">
+     <item row="1" column="0">
+      <widget class="QRadioButton" name="customRadioButton">
+       <property name="text">
+        <string>Custom:</string>
+       </property>
+      </widget>
+     </item>
+     <item row="1" column="1">
+      <layout class="QHBoxLayout" name="shortcutLayout">
        <property name="spacing">
         <number>8</number>
        </property>
        <item>
-        <widget class="QRadioButton" name="customRadioButton">
-         <property name="text">
-          <string>Custom:</string>
-         </property>
-        </widget>
-       </item>
-       <item>
         <widget class="QPushButton" name="shortcutPushButton">
          <property name="minimumSize">
           <size>
@@ -83,7 +83,7 @@
          </property>
          <property name="icon">
           <iconset resource="../images/openlp-2.qrc">
-           <normaloff>:/system/system_settings.png</normaloff>:/system/system_settings.png</iconset>
+           <normaloff>:/system/system_configure_shortcuts.png</normaloff>:/system/system_configure_shortcuts.png</iconset>
          </property>
          <property name="checkable">
           <bool>true</bool>
@@ -110,20 +110,50 @@
          </property>
         </widget>
        </item>
-       <item>
-        <spacer name="customShortcutSpacer">
-         <property name="orientation">
-          <enum>Qt::Horizontal</enum>
-         </property>
-         <property name="sizeHint" stdset="0">
-          <size>
-           <width>40</width>
-           <height>20</height>
-          </size>
-         </property>
-        </spacer>
-       </item>
-      </layout>
+      </layout>
+     </item>
+     <item row="1" column="2">
+      <layout class="QHBoxLayout" name="alternateLayout">
+       <property name="spacing">
+        <number>8</number>
+       </property>
+       <item>
+        <widget class="QPushButton" name="alternatePushButton">
+         <property name="text">
+          <string>None</string>
+         </property>
+         <property name="icon">
+          <iconset resource="../images/openlp-2.qrc">
+           <normaloff>:/system/system_configure_shortcuts.png</normaloff>:/system/system_configure_shortcuts.png</iconset>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <widget class="QToolButton" name="clearAlternateButton">
+         <property name="text">
+          <string/>
+         </property>
+         <property name="icon">
+          <iconset resource="../images/openlp-2.qrc">
+           <normaloff>:/system/clear_shortcut.png</normaloff>:/system/clear_shortcut.png</iconset>
+         </property>
+        </widget>
+       </item>
+      </layout>
+     </item>
+     <item row="0" column="1">
+      <widget class="QLabel" name="shortcutLabel">
+       <property name="text">
+        <string>Ctrl+V</string>
+       </property>
+      </widget>
+     </item>
+     <item row="0" column="2">
+      <widget class="QLabel" name="alternateLabel">
+       <property name="text">
+        <string>Shift+Ins</string>
+       </property>
+      </widget>
      </item>
     </layout>
    </item>


Follow ups