diff --git a/documentation/manual/source/songs.rst b/documentation/manual/source/songs.rst index 56928d831..23f054127 100644 --- a/documentation/manual/source/songs.rst +++ b/documentation/manual/source/songs.rst @@ -99,4 +99,131 @@ completed. Press :guilabel:`Finish` and OpenLP will be ready to use your songs imported from CCLI SongSelect. +Creating or editing a song slide +================================ +If you want to create a new song slide or, once you have a song imported, you +can edit and rearrange the Title & Lyrics, Author, Topics & Song Book, +assign a Theme, or edit *Copyright Info & Comments* as needed. This is done +through the `Song Editor`. To use the `Song Editor` to edit an existing song you +can click on a song in the `Media Manager` and then click the button to +:guilabel:`Edit the selected song` or right click a song from either the +`Media Manager` or from the `Service Manager` and click :guilabel:`Edit item`. +If you are adding a new song click :guilabel:`Add a new Song` in the +`Media Manager`. + +.. image:: pics/song_edit_lyrics.png + +**Title:** This is where you would name your song or edit a song name. + +**Alternate title:** You can add a name in this box that will bring up the song +in Titles search. **Example:** You could use an alternate title of "hymn" on all +your hymn song titles for grouping. When you search "hymn" it will show all the +hymns that have "hymn" for the Alternate title. + +**Lyrics:** The *Lyrics* window shows all lyrics imported or added. On the left +side of the lyrics you will see a capital letter followed by a number. A V1 +would represent verse 1, C1 would be Chorus 1. You will use these letters and +numbers for the order to display the lyrics. + +**Verse Order:** After you entered or edited your song, you will want OpenLP to +display the verses in the correct order you want them displayed. On the left side +of your lyrics you will see C1, V1, V2 etc. the way they were imported or added. +To put your lyrics in the correct order is as simple as typing in the +:guilabel:`Verse order box` at the bottom, the correct order you want them +displayed, with only a blank space in between each entry. The correct format will +look like this: V1 C1 V2 C1 V3 C1. If you forget to put a space in between the +order, or if you do not have the corresponding verse number, OpenLP will politely +tell you with a pop-up error message what is wrong so you can correct your +mistake and save it. + +.. image:: pics/song_edit_verse_error.png + +Adding or editing the lyrics +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +**Add:** To Add a new verse, click on :guilabel:`Add`. The main window is where +you will type your lyrics. OpenLP is packaged with a spell checker for most +languages. If you misspell a word it will be underlined. Right click the +underlined word and left click *Spelling Suggestions* or you can ignore it and +continue typing. You also have the ability to format the font using *Formatting +Tags*. Highlight the word/words you want to format and right click the highlight. +Left click *Formatting Tags* and choose the format you want to apply to the font +and the format tags will be entered with your lyrics. These tags are not visible +when displayed. To remove the format, delete the tag on each end of the word or +sentence. + +**Edit:** To edit an existing verse, click on the verse you wish to *Edit* then click on +:guilabel:`Edit`, make your changes and click :guilabel:`Save`. + +**Edit All:** To edit the whole song at once, click on :guilabel:`Edit All`. + +**Delete:** To delete a verse, click on the verse you want to delete and it will +highlight, click on the :guilabel:`Delete` button and it will be deleted. +**Warning:**, once you click the :guilabel:`Delete` button, you will not be +asked again, it will be deleted immediately. + +.. image:: pics/song_edit_verse_type.png + +**Verse type:** gives you 7 ways to classify your lyrics. Verse, Chorus, Bridge, +Pre-Chorus, Intro, Ending, Other. + +If you have more than one verse, you would number them Verse 1, 2, 3 as needed. +If you find the verse has too many lines for your screen, you can edit and +shorten the verse and :guilabel:`Add` another slide. + +Authors, Topics & Song Book +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Once your *Title & Lyrics* are added or edited the way you want them you must +add or enter the author or authors of the song. OpenLP requires all songs to +have an author entered. You can add a blank space for the author name. + +.. image:: pics/song_edit_authors.png + +**Authors:** Click the drop down arrow to view all authors or start typing a name +in the box and a list will appear. If the authors name has not been added, type +the authors name in the box and click :guilabel:`Add to Song`. The authors name +will appear below and will also be added to your database. If you accidently add +the wrong author you can click on the authors name and click :guilabel:`Remove`. + +:guilabel:`Manage Authors, Topics, Song Books:` Clicking this button will bring +up your complete list of authors. + +.. image:: pics/song_edit_maintenance.png + +**Add:** Clicking the :guilabel:`Add` button will bring up a box where you will +add the Authors First name, Last name and Display name. Click :guilabel:`Save` +when you are finished. + +.. image:: pics/song_edit_author_maintenance.png + +**Edit:** The :guilabel:`Edit` button will bring up window where you can edit +the info that is already there. + +**Delete:** The :guilabel:`Delete` button will remove the author you have +highlighted. Note: You cannot delete an author that is assigned to a song. +Authors names are displayed in the footer. + +Theme, Copyright info & Comments +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +On this tab you can assign a *Theme* to a song, enter the *Copyright information* +and add the *CCLI number*. If you imported a song from SongSelect this +information will usually be entered. + +.. image:: pics/song_edit_theme_copyright.png + +**Theme:** Click the drop down arrow to display your list of themes or start +typing a theme name in the box and the list will appear. You can also create a +new theme by clicking the :guilabel:`New Theme` button. + +**Copyright information:** Add or edit the copyright information in this box. If +you would like to use the © symbol click "guilabel:`©` button. This information +is displayed in the footer. + +**CCLI number:** Enter the CCLI number in this box. Note: this is the CCLI number +of the song, not your contract number. This number is not displayed in the footer + +**Comments:** You can add comments in this box. This information is not +dispayed in the footer. diff --git a/openlp.pyw b/openlp.pyw index 57dbcb698..5c3b8ca77 100755 --- a/openlp.pyw +++ b/openlp.pyw @@ -116,7 +116,7 @@ class OpenLP(QtGui.QApplication): self.processEvents() # start the main app window self.mainWindow = MainWindow(screens, self.clipboard(), - self.arguments()) + self.arguments()) self.mainWindow.show() if show_splash: # now kill the splashscreen diff --git a/openlp/core/lib/__init__.py b/openlp/core/lib/__init__.py index e62cb3e44..491f3e652 100644 --- a/openlp/core/lib/__init__.py +++ b/openlp/core/lib/__init__.py @@ -166,58 +166,6 @@ def build_icon(icon): 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 dockwidget import OpenLPDockWidget from renderer import Renderer from rendermanager import RenderManager from mediamanageritem import MediaManagerItem +from openlp.core.utils.actions import ActionList diff --git a/openlp/core/lib/htmlbuilder.py b/openlp/core/lib/htmlbuilder.py index c4361a421..a80fedd06 100644 --- a/openlp/core/lib/htmlbuilder.py +++ b/openlp/core/lib/htmlbuilder.py @@ -452,7 +452,7 @@ def build_lyrics_css(item, webkitvers): .lyricsshadow { %s } - """ + """ theme = item.themedata lyricstable = u'' lyrics = u'' @@ -460,8 +460,7 @@ def build_lyrics_css(item, webkitvers): outline = u'' shadow = u'' if theme and item.main: - lyricstable = u'left: %spx; top: %spx;' % \ - (item.main.x(), item.main.y()) + lyricstable = u'left: %spx; top: %spx;' % (item.main.x(), item.main.y()) lyrics = build_lyrics_format_css(theme, item.main.width(), item.main.height()) # For performance reasons we want to show as few DIV's as possible, diff --git a/openlp/core/lib/mediamanageritem.py b/openlp/core/lib/mediamanageritem.py index 63132b141..7671064df 100644 --- a/openlp/core/lib/mediamanageritem.py +++ b/openlp/core/lib/mediamanageritem.py @@ -31,10 +31,10 @@ import os 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 @@ class MediaManagerItem(QtGui.QWidget): 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, + QtCore.Qt.Key_Return], 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) diff --git a/openlp/core/lib/searchedit.py b/openlp/core/lib/searchedit.py index 4841d76dc..d32961ef9 100644 --- a/openlp/core/lib/searchedit.py +++ b/openlp/core/lib/searchedit.py @@ -29,6 +29,7 @@ import logging 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 @@ class SearchEdit(QtGui.QLineEdit): 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)'), diff --git a/openlp/core/lib/toolbar.py b/openlp/core/lib/toolbar.py index d5d2fa4f8..d2b37df51 100644 --- a/openlp/core/lib/toolbar.py +++ b/openlp/core/lib/toolbar.py @@ -51,8 +51,7 @@ class OpenLPToolbar(QtGui.QToolBar): 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 @@ class OpenLPToolbar(QtGui.QToolBar): 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 @@ class OpenLPToolbar(QtGui.QToolBar): 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 @@ class OpenLPToolbar(QtGui.QToolBar): 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): diff --git a/openlp/core/lib/ui.py b/openlp/core/lib/ui.py index c1a9f8b35..3365b32a0 100644 --- a/openlp/core/lib/ui.py +++ b/openlp/core/lib/ui.py @@ -31,6 +31,7 @@ import logging 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__) @@ -49,14 +50,18 @@ class UiStrings(object): Cancel = translate('OpenLP.Ui', 'Cancel') CCLINumberLabel = translate('OpenLP.Ui', 'CCLI number:') CreateService = translate('OpenLP.Ui', 'Create a new service.') + Continuous = translate('OpenLP.Ui', 'Continuous') Default = unicode(translate('OpenLP.Ui', 'Default')) Delete = translate('OpenLP.Ui', '&Delete') + DisplayStyle = translate('OpenLP.Ui', 'Display style:') Edit = translate('OpenLP.Ui', '&Edit') 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 +69,7 @@ class UiStrings(object): 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 +87,7 @@ class UiStrings(object): 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 +98,19 @@ class UiStrings(object): 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') + VersePerSlide = translate('OpenLP.Ui', 'Verse Per Slide') + VersePerLine = translate('OpenLP.Ui', 'Verse Per Line') Version = translate('OpenLP.Ui', 'Version') + View = translate('OpenLP.Ui', 'View') + ViewMode = translate('OpenLP.Ui', 'View Model') def add_welcome_page(parent, image): """ @@ -238,45 +251,128 @@ def create_up_down_push_button_set(parent): 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. @@ -315,3 +411,20 @@ def create_valign_combo(form, parent, layout): form.verticalComboBox.addItem(UiStrings.Bottom) verticalLabel.setBuddy(form.verticalComboBox) layout.addRow(verticalLabel, form.verticalComboBox) + +def find_and_set_in_combo_box(combo_box, value_to_find): + """ + Find a string in a combo box and set it as the selected item if present + + ``combo_box`` + The combo box to check for selected items + + ``value_to_find`` + The value to find + """ + index = combo_box.findText(value_to_find, + QtCore.Qt.MatchExactly) + if index == -1: + # Not Found. + index = 0 + combo_box.setCurrentIndex(index) \ No newline at end of file diff --git a/openlp/core/ui/mainwindow.py b/openlp/core/ui/mainwindow.py index 38775d68e..2038e1972 100644 --- a/openlp/core/ui/mainwindow.py +++ b/openlp/core/ui/mainwindow.py @@ -33,12 +33,13 @@ from PyQt4 import QtCore, QtGui 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 @@ class Ui_MainWindow(object): 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 @@ class Ui_MainWindow(object): 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 @@ class Ui_MainWindow(object): # 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 @@ class Ui_MainWindow(object): 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 @@ class Ui_MainWindow(object): 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 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): """ 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 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): 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 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): 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 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): 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 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): """ Show the shortcuts dialog """ - self.shortcutForm.exec_(self.actionList) + if self.shortcutForm.exec_(): + self.shortcutForm.save() def onModeDefaultItemClicked(self): """ @@ -928,19 +887,16 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): unicode(translate('OpenLP.MainWindow', 'Default Theme: %s')) % theme) - def toggleMediaManager(self, visible): - if self.mediaManagerDock.isVisible() != visible: - self.mediaManagerDock.setVisible(visible) + def toggleMediaManager(self): + self.mediaManagerDock.setVisible(not self.mediaManagerDock.isVisible()) - def toggleServiceManager(self, visible): - if self.serviceManagerDock.isVisible() != visible: - self.serviceManagerDock.setVisible(visible) + def toggleServiceManager(self): + self.serviceManagerDock.setVisible(not self.serviceManagerDock.isVisible()) - def toggleThemeManager(self, visible): - if self.themeManagerDock.isVisible() != visible: - self.themeManagerDock.setVisible(visible) + def toggleThemeManager(self): + self.themeManagerDock.setVisible(not self.themeManagerDock.isVisible()) - def setPreviewPanelVisibility(self, visible): + def setPreviewPanelVisibility(self, visible=None): """ Sets the visibility of the preview panel including saving the setting and updating the menu. @@ -950,12 +906,14 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): 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 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): 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 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): 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) diff --git a/openlp/core/ui/printservicedialog.py b/openlp/core/ui/printservicedialog.py index 97f4b4060..9593e9ec4 100644 --- a/openlp/core/ui/printservicedialog.py +++ b/openlp/core/ui/printservicedialog.py @@ -132,6 +132,8 @@ class Ui_PrintServiceDialog(object): self.groupLayout = QtGui.QVBoxLayout() self.slideTextCheckBox = QtGui.QCheckBox() self.groupLayout.addWidget(self.slideTextCheckBox) + self.pageBreakAfterText = QtGui.QCheckBox() + self.groupLayout.addWidget(self.pageBreakAfterText) self.notesCheckBox = QtGui.QCheckBox() self.groupLayout.addWidget(self.notesCheckBox) self.metaDataCheckBox = QtGui.QCheckBox() @@ -149,6 +151,8 @@ class Ui_PrintServiceDialog(object): printServiceDialog.setWindowTitle(UiStrings.PrintServiceOrder) self.slideTextCheckBox.setText(translate('OpenLP.PrintServiceForm', 'Include slide text if available')) + self.pageBreakAfterText.setText(translate('OpenLP.PrintServiceForm', + 'Add page break before each text item.')) self.notesCheckBox.setText(translate('OpenLP.PrintServiceForm', 'Include service item notes')) self.metaDataCheckBox.setText(translate('OpenLP.PrintServiceForm', diff --git a/openlp/core/ui/printserviceform.py b/openlp/core/ui/printserviceform.py index 4e0f018a4..01b937d61 100644 --- a/openlp/core/ui/printserviceform.py +++ b/openlp/core/ui/printserviceform.py @@ -24,12 +24,65 @@ # Temple Place, Suite 330, Boston, MA 02111-1307 USA # ############################################################################### import datetime +import os from PyQt4 import QtCore, QtGui +from lxml import html -from openlp.core.lib import translate +from openlp.core.lib import translate, get_text_file_string from openlp.core.lib.ui import UiStrings from openlp.core.ui.printservicedialog import Ui_PrintServiceDialog, ZoomSize +from openlp.core.utils import AppLocation + +DEFAULT_CSS = """/* +Edit this file to customize the service order print. Note, that not all CSS +properties are supported. See: +http://doc.trolltech.com/4.7/richtext-html-subset.html#css-properties +*/ + +.serviceTitle { + font-weight:600; + font-size:x-large; + color:black; +} + +.itemTitle { + font-weight:600; + font-size:large; + color:black; +} + +.itemText { + color:black; +} + +.itemFooter { + font-size:8px; + color:black; +} + +.itemNotesTitle { + font-weight:bold; + font-size:12px; + color:black; +} + +.itemNotesText { + font-size:11px; + color:black; +} + +.customNotesTitle { + font-weight:bold; + font-size:11px; + color:black; +} + +.customNotesText { + font-size:11px; + color:black; +} +""" class PrintServiceForm(QtGui.QDialog, Ui_PrintServiceDialog): @@ -50,6 +103,10 @@ class PrintServiceForm(QtGui.QDialog, Ui_PrintServiceDialog): settings.beginGroup(u'advanced') self.slideTextCheckBox.setChecked(settings.value( u'print slide text', QtCore.QVariant(False)).toBool()) + self.pageBreakAfterText.setChecked(settings.value( + u'add page break', QtCore.QVariant(False)).toBool()) + if not self.slideTextCheckBox.isChecked(): + self.pageBreakAfterText.setDisabled(True) self.metaDataCheckBox.setChecked(settings.value( u'print file meta data', QtCore.QVariant(False)).toBool()) self.notesCheckBox.setChecked(settings.value( @@ -76,6 +133,9 @@ class PrintServiceForm(QtGui.QDialog, Ui_PrintServiceDialog): QtCore.SIGNAL(u'triggered()'), self.copyText) QtCore.QObject.connect(self.htmlCopy, QtCore.SIGNAL(u'triggered()'), self.copyHtmlText) + QtCore.QObject.connect(self.slideTextCheckBox, + QtCore.SIGNAL(u'stateChanged(int)'), + self.onSlideTextCheckBoxChanged) self.updatePreviewText() def toggleOptions(self, checked): @@ -93,59 +153,124 @@ class PrintServiceForm(QtGui.QDialog, Ui_PrintServiceDialog): """ Creates the html text and updates the html of *self.document*. """ - text = u'' - if self.titleLineEdit.text(): - text += u'

%s

' % unicode(self.titleLineEdit.text()) - for item in self.serviceManager.serviceItems: + html_data = html.fromstring( + u'%s' % unicode(self.titleLineEdit.text())) + css_path = os.path.join( + AppLocation.get_data_path(), u'servicePrint.css') + if not os.path.isfile(css_path): + # Create default css file. + css_file = open(css_path, u'w') + css_file.write(DEFAULT_CSS) + css_file.close() + custom_css = get_text_file_string(css_path) + self._addChildToParent( + u'style', custom_css, html_data.head, u'type', u'text/css') + self._addChildToParent(u'body', parent=html_data) + self._addChildToParent(u'span', unicode(self.titleLineEdit.text()), + html_data.body, u'class', u'serviceTitle') + for index, item in enumerate(self.serviceManager.serviceItems): item = item[u'service_item'] + div = self._addChildToParent(u'div', parent=html_data.body) # Add the title of the service item. - text += u'

%s

' % (item.icon, - item.get_display_title()) - # Add slide text of the service item. + item_title = self._addChildToParent( + u'h2', parent=div, attribute=u'class', value=u'itemTitle') + self._addChildToParent( + u'img', parent=item_title, attribute=u'src', value=item.icon) + self._fromstring( + u' %s' % item.get_display_title(), item_title) if self.slideTextCheckBox.isChecked(): + # Add the text of the service item. if item.is_text(): - # Add the text of the service item. - verse = None + verse_def = None for slide in item.get_frames(): - if not verse: - text += u'

' + slide[u'html'] - verse = slide[u'verseTag'] - elif verse != slide[u'verseTag']: - text += u'<\p>

' + slide[u'html'] - verse = slide[u'verseTag'] + if not verse_def or verse_def != slide[u'verseTag']: + p = self._addChildToParent(u'p', parent=div, + attribute=u'class', value=u'itemText') else: - text += u'
' + slide[u'html'] - text += u'

' + self._addChildToParent(u'br', parent=p) + self._fromstring(u'%s' % slide[u'html'], p) + verse_def = slide[u'verseTag'] + # Break the page before the div element. + if index != 0 and self.pageBreakAfterText.isChecked(): + div.set(u'style', u'page-break-before:always') + # Add the image names of the service item. elif item.is_image(): - # Add the image names of the service item. - text += u'
    ' + ol = self._addChildToParent(u'ol', parent=div) for slide in range(len(item.get_frames())): - text += u'
  1. %s

  2. ' % \ - item.get_frame_title(slide) - text += u'
' + self._addChildToParent(u'li', item.get_frame_title(slide), ol) + # add footer if item.foot_text: - # add footer - text += u'

%s

' % item.foot_text + self._fromstring( + item.foot_text, div, u'class', u'itemFooter') # Add service items' notes. if self.notesCheckBox.isChecked(): if item.notes: - text += u'

%s

%s' % (translate( - 'OpenLP.ServiceManager', 'Notes:'), - item.notes.replace(u'\n', u'
')) + p = self._addChildToParent(u'p', parent=div) + self._addChildToParent(u'span', unicode( + translate('OpenLP.ServiceManager', 'Notes:')), p, + u'class', u'itemNotesTitle') + self._fromstring(u' %s' % item.notes.replace( + u'\n', u'
'), p, u'class', u'itemNotesText') # Add play length of media files. if item.is_media() and self.metaDataCheckBox.isChecked(): tme = item.media_length if item.end_time > 0: tme = item.end_time - item.start_time - text += u'

%s %s

' % (translate( - 'OpenLP.ServiceManager', u'Playing time:'), - unicode(datetime.timedelta(seconds=tme))) + title = self._fromstring(u'

%s

' % + translate('OpenLP.ServiceManager', 'Playing time:'), div) + self._fromstring(u'%s' % + unicode(datetime.timedelta(seconds=tme)), title) + # Add the custom service notes: if self.footerTextEdit.toPlainText(): - text += u'

%s

%s' % (translate('OpenLP.ServiceManager', - u'Custom Service Notes:'), self.footerTextEdit.toPlainText()) - self.document.setHtml(text) + self._addChildToParent(u'span', translate('OpenLP.ServiceManager', + u'Custom Service Notes:'), div, u'class', u'customNotesTitle') + self._addChildToParent( + u'span', u' %s' % self.footerTextEdit.toPlainText(), div, + u'class', u'customNotesText') + self.document.setHtml(html.tostring(html_data)) self.previewWidget.updatePreview() + def _addChildToParent(self, tag, text=None, parent=None, attribute=None, + value=None): + """ + Creates a html element. If ``text`` is given, the element's text will + set and if a ``parent`` is given, the element is appended. + + ``tag`` + The html tag, e. g. ``u'span'``. Defaults to ``None``. + + ``text`` + The text for the tag. Defaults to ``None``. + + ``parent`` + The parent element. Defaults to ``None``. + + ``attribute`` + An optional attribute, for instance ``u'class``. + + ``value`` + The value for the given ``attribute``. It does not have a meaning, + if the attribute is left to its default. + """ + element = html.Element(tag) + if text is not None: + element.text = unicode(text) + if parent is not None: + parent.append(element) + if attribute is not None: + element.set(attribute, value if value is not None else u'') + return element + + def _fromstring(self, string, parent, attribute=None, value=None): + """ + This is used to create a child html element from a string. + """ + element = html.fromstring(string) + if attribute is not None: + element.set(attribute, value if value is not None else u'') + parent.append(element) + return element + def paintRequested(self, printer): """ Paint the preview of the *self.document*. @@ -232,6 +357,13 @@ class PrintServiceForm(QtGui.QDialog, Ui_PrintServiceDialog): else: self.copyTextButton.setText(UiStrings.CopyToText) + def onSlideTextCheckBoxChanged(self, state): + """ + Disable or enable the ``pageBreakAfterText`` checkbox as it should only + be enabled, when the ``slideTextCheckBox`` is enabled. + """ + self.pageBreakAfterText.setDisabled(state == QtCore.Qt.Unchecked) + def saveOptions(self): """ Save the settings and close the dialog. @@ -241,6 +373,8 @@ class PrintServiceForm(QtGui.QDialog, Ui_PrintServiceDialog): settings.beginGroup(u'advanced') settings.setValue(u'print slide text', QtCore.QVariant(self.slideTextCheckBox.isChecked())) + settings.setValue(u'add page break', + QtCore.QVariant(self.pageBreakAfterText.isChecked())) settings.setValue(u'print file meta data', QtCore.QVariant(self.metaDataCheckBox.isChecked())) settings.setValue(u'print notes', diff --git a/openlp/core/ui/servicemanager.py b/openlp/core/ui/servicemanager.py index 9c1c63917..ba9ca718a 100644 --- a/openlp/core/ui/servicemanager.py +++ b/openlp/core/ui/servicemanager.py @@ -32,14 +32,16 @@ log = logging.getLogger(__name__) 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, find_and_set_in_combo_box 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 +166,55 @@ class ServiceManager(QtGui.QWidget): 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 +229,28 @@ class ServiceManager(QtGui.QWidget): 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 +325,6 @@ class ServiceManager(QtGui.QWidget): 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 +338,6 @@ class ServiceManager(QtGui.QWidget): ]) 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 @@ -691,9 +702,9 @@ class ServiceManager(QtGui.QWidget): Called by the SlideController to request a preview item be made live and allows the next preview to be updated if relevent. """ - id, row = message.split(u':') + uuid, row = message.split(u':') for sitem in self.serviceItems: - if sitem[u'service_item']._uuid == id: + if sitem[u'service_item']._uuid == uuid: item = self.serviceManagerList.topLevelItem(sitem[u'order'] - 1) self.serviceManagerList.setCurrentItem(item) self.makeLive(int(row)) @@ -1021,7 +1032,7 @@ class ServiceManager(QtGui.QWidget): editId, uuid = message.split(u':') for item in self.serviceItems: if item[u'service_item']._uuid == uuid: - item[u'service_item'].edit_id = editId + item[u'service_item'].edit_id = int(editId) self.setModified(True) def replaceServiceItem(self, newItem): @@ -1259,15 +1270,9 @@ class ServiceManager(QtGui.QWidget): 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) - # Not Found - if index == -1: - index = 0 - self.service_theme = u'' - self.themeComboBox.setCurrentIndex(index) + find_and_set_in_combo_box(self.themeComboBox, self.service_theme) self.mainwindow.renderManager.set_service_theme(self.service_theme) self.regenerateServiceItems() diff --git a/openlp/core/ui/shortcutlistdialog.py b/openlp/core/ui/shortcutlistdialog.py index 4e5b9e270..288086cba 100644 --- a/openlp/core/ui/shortcutlistdialog.py +++ b/openlp/core/ui/shortcutlistdialog.py @@ -31,41 +31,72 @@ from openlp.core.lib import translate, build_icon 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.descriptionLabel = QtGui.QLabel(shortcutListDialog) + self.descriptionLabel.setObjectName(u'descriptionLabel') + self.descriptionLabel.setWordWrap(True) + self.shortcutListLayout.addWidget(self.descriptionLabel) self.treeWidget = QtGui.QTreeWidget(shortcutListDialog) - self.treeWidget.setAlternatingRowColors(True) self.treeWidget.setObjectName(u'treeWidget') + self.treeWidget.setAlternatingRowColors(True) 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( + self.treeWidget.setColumnWidth(0, 250) + 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.shortcutButton.setCheckable(True) - self.shortcutButton.setObjectName(u'shortcutButton') - self.customLayout.addWidget(self.shortcutButton) - self.clearShortcutButton = QtGui.QToolButton(shortcutListDialog) - self.clearShortcutButton.setIcon( + 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.clearShortcutButton.setAutoRaise(True) - self.clearShortcutButton.setObjectName(u'clearShortcutButton') - self.customLayout.addWidget(self.clearShortcutButton) - self.customLayout.addStretch() - self.dialogLayout.addLayout(self.customLayout) + 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.setStandardButtons(QtGui.QDialogButtonBox.Cancel | - QtGui.QDialogButtonBox.Ok | QtGui.QDialogButtonBox.Reset) self.buttonBox.setObjectName(u'buttonBox') - self.dialogLayout.addWidget(self.buttonBox) + self.buttonBox.setOrientation(QtCore.Qt.Horizontal) + self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Cancel | + 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 +107,24 @@ class Ui_ShortcutListDialog(object): def retranslateUi(self, shortcutListDialog): shortcutListDialog.setWindowTitle( translate('OpenLP.ShortcutListDialog', 'Customize Shortcuts')) + self.descriptionLabel.setText(translate('OpenLP.ShortcutListDialog', + 'Select an action and click one of the buttons below to start ' + 'capturing a new primary or alternate shortcut, respectively.')) 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.')) diff --git a/openlp/core/ui/shortcutlistform.py b/openlp/core/ui/shortcutlistform.py index e87ba3ada..26bfddadd 100644 --- a/openlp/core/ui/shortcutlistform.py +++ b/openlp/core/ui/shortcutlistform.py @@ -30,6 +30,7 @@ import re 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,72 +42,391 @@ class ShortcutListForm(QtGui.QDialog, Ui_ShortcutListDialog): 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 \ - key == Qt.Key_Meta or key == Qt.Key_Alt: + if key == QtCore.Qt.Key_Shift or key == QtCore.Qt.Key_Control or \ + key == QtCore.Qt.Key_Meta or key == QtCore.Qt.Key_Alt: return key_string = QtGui.QKeySequence(key).toString() - if event.modifiers() & Qt.ControlModifier == Qt.ControlModifier: + if event.modifiers() & QtCore.Qt.ControlModifier == \ + QtCore.Qt.ControlModifier: key_string = u'Ctrl+' + key_string - if event.modifiers() & Qt.AltModifier == Qt.AltModifier: + if event.modifiers() & QtCore.Qt.AltModifier == QtCore.Qt.AltModifier: key_string = u'Alt+' + key_string - if event.modifiers() & Qt.ShiftModifier == Qt.ShiftModifier: + if event.modifiers() & QtCore.Qt.ShiftModifier == \ + QtCore.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) - item.setExpanded(True) self.treeWidget.addTopLevelItem(item) + item.setExpanded(True) + self.refreshShortcutList() - def onShortcutButtonClicked(self, toggled): - self.captureShortcut = toggled + 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() + self.onCurrentItemChanged(self.treeWidget.currentItem()) + + 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() + self.onCurrentItemChanged(self.treeWidget.currentItem()) + + 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) diff --git a/openlp/core/ui/slidecontroller.py b/openlp/core/ui/slidecontroller.py index 232653326..4f5ed1ea7 100644 --- a/openlp/core/ui/slidecontroller.py +++ b/openlp/core/ui/slidecontroller.py @@ -32,8 +32,9 @@ from PyQt4.phonon import Phonon 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 @@ class SlideController(QtGui.QWidget): 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 @@ class SlideController(QtGui.QWidget): 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 @@ class SlideController(QtGui.QWidget): 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 @@ class SlideController(QtGui.QWidget): 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 @@ class SlideController(QtGui.QWidget): """ 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 @@ class SlideController(QtGui.QWidget): 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 @@ class SlideController(QtGui.QWidget): 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) diff --git a/openlp/core/ui/themeform.py b/openlp/core/ui/themeform.py index 6653e7e1d..3a3b3bb61 100644 --- a/openlp/core/ui/themeform.py +++ b/openlp/core/ui/themeform.py @@ -63,26 +63,19 @@ class ThemeForm(QtGui.QWizard, Ui_ThemeWizard): QtCore.SIGNAL(u'currentIndexChanged(int)'), self.onGradientComboBoxCurrentIndexChanged) QtCore.QObject.connect(self.colorButton, - QtCore.SIGNAL(u'clicked()'), - self.onColorButtonClicked) + QtCore.SIGNAL(u'clicked()'), self.onColorButtonClicked) QtCore.QObject.connect(self.gradientStartButton, - QtCore.SIGNAL(u'clicked()'), - self.onGradientStartButtonClicked) + QtCore.SIGNAL(u'clicked()'), self.onGradientStartButtonClicked) QtCore.QObject.connect(self.gradientEndButton, - QtCore.SIGNAL(u'clicked()'), - self.onGradientEndButtonClicked) + QtCore.SIGNAL(u'clicked()'), self.onGradientEndButtonClicked) QtCore.QObject.connect(self.imageBrowseButton, - QtCore.SIGNAL(u'clicked()'), - self.onImageBrowseButtonClicked) + QtCore.SIGNAL(u'clicked()'), self.onImageBrowseButtonClicked) QtCore.QObject.connect(self.mainColorButton, - QtCore.SIGNAL(u'clicked()'), - self.onMainColorButtonClicked) + QtCore.SIGNAL(u'clicked()'), self.onMainColorButtonClicked) QtCore.QObject.connect(self.outlineColorButton, - QtCore.SIGNAL(u'clicked()'), - self.onOutlineColorButtonClicked) + QtCore.SIGNAL(u'clicked()'), self.onOutlineColorButtonClicked) QtCore.QObject.connect(self.shadowColorButton, - QtCore.SIGNAL(u'clicked()'), - self.onShadowColorButtonClicked) + QtCore.SIGNAL(u'clicked()'), self.onShadowColorButtonClicked) QtCore.QObject.connect(self.outlineCheckBox, QtCore.SIGNAL(u'stateChanged(int)'), self.onOutlineCheckCheckBoxStateChanged) @@ -90,8 +83,7 @@ class ThemeForm(QtGui.QWizard, Ui_ThemeWizard): QtCore.SIGNAL(u'stateChanged(int)'), self.onShadowCheckCheckBoxStateChanged) QtCore.QObject.connect(self.footerColorButton, - QtCore.SIGNAL(u'clicked()'), - self.onFooterColorButtonClicked) + QtCore.SIGNAL(u'clicked()'), self.onFooterColorButtonClicked) QtCore.QObject.connect(self.mainPositionCheckBox, QtCore.SIGNAL(u'stateChanged(int)'), self.onMainPositionCheckBoxStateChanged) @@ -99,26 +91,23 @@ class ThemeForm(QtGui.QWizard, Ui_ThemeWizard): QtCore.SIGNAL(u'stateChanged(int)'), self.onFooterPositionCheckBoxStateChanged) QtCore.QObject.connect(self, - QtCore.SIGNAL(u'currentIdChanged(int)'), - self.onCurrentIdChanged) + QtCore.SIGNAL(u'currentIdChanged(int)'), self.onCurrentIdChanged) QtCore.QObject.connect(Receiver.get_receiver(), - QtCore.SIGNAL(u'theme_line_count'), - self.updateLinesText) + QtCore.SIGNAL(u'theme_line_count'), self.updateLinesText) QtCore.QObject.connect(self.mainSizeSpinBox, - QtCore.SIGNAL(u'valueChanged(int)'), - self.calculateLines) + QtCore.SIGNAL(u'valueChanged(int)'), self.calculateLines) QtCore.QObject.connect(self.lineSpacingSpinBox, - QtCore.SIGNAL(u'valueChanged(int)'), - self.calculateLines) + QtCore.SIGNAL(u'valueChanged(int)'), self.calculateLines) QtCore.QObject.connect(self.outlineSizeSpinBox, - QtCore.SIGNAL(u'valueChanged(int)'), - self.calculateLines) + QtCore.SIGNAL(u'valueChanged(int)'), self.calculateLines) QtCore.QObject.connect(self.shadowSizeSpinBox, - QtCore.SIGNAL(u'valueChanged(int)'), - self.calculateLines) + QtCore.SIGNAL(u'valueChanged(int)'), self.calculateLines) QtCore.QObject.connect(self.mainFontComboBox, - QtCore.SIGNAL(u'activated(int)'), - self.calculateLines) + QtCore.SIGNAL(u'activated(int)'), self.calculateLines) + QtCore.QObject.connect(self.footerFontComboBox, + QtCore.SIGNAL(u'activated(int)'), self.updateTheme) + QtCore.QObject.connect(self.footerSizeSpinBox, + QtCore.SIGNAL(u'valueChanged(int)'), self.updateTheme) def setDefaults(self): """ @@ -389,7 +378,7 @@ class ThemeForm(QtGui.QWizard, Ui_ThemeWizard): Handle the display and state of the Footer Area page. """ self.footerFontComboBox.setCurrentFont( - QtGui.QFont(self.theme.font_main_name)) + QtGui.QFont(self.theme.font_footer_name)) self.footerColorButton.setStyleSheet(u'background-color: %s' % self.theme.font_footer_color) self.setField(u'footerSizeSpinBox', diff --git a/openlp/core/ui/thememanager.py b/openlp/core/ui/thememanager.py index d033daeb3..81da6e021 100644 --- a/openlp/core/ui/thememanager.py +++ b/openlp/core/ui/thememanager.py @@ -445,6 +445,7 @@ class ThemeManager(QtGui.QWidget): files = SettingsManager.get_files(self.settingsSection, u'.png') if firstTime: self.firstTime() + files = SettingsManager.get_files(self.settingsSection, u'.png') # No themes have been found so create one if len(files) == 0: theme = ThemeXML() diff --git a/openlp/core/ui/themestab.py b/openlp/core/ui/themestab.py index 1b76d2198..1415c6810 100644 --- a/openlp/core/ui/themestab.py +++ b/openlp/core/ui/themestab.py @@ -28,7 +28,7 @@ from PyQt4 import QtCore, QtGui from openlp.core.lib import SettingsTab, Receiver, translate from openlp.core.lib.theme import ThemeLevel -from openlp.core.lib.ui import UiStrings +from openlp.core.lib.ui import UiStrings, find_and_set_in_combo_box class ThemesTab(SettingsTab): """ @@ -185,12 +185,7 @@ class ThemesTab(SettingsTab): self.DefaultComboBox.clear() for theme in theme_list: self.DefaultComboBox.addItem(theme) - id = self.DefaultComboBox.findText( - self.global_theme, QtCore.Qt.MatchExactly) - if id == -1: - id = 0 # Not Found - self.global_theme = u'' - self.DefaultComboBox.setCurrentIndex(id) + find_and_set_in_combo_box(self.DefaultComboBox, self.global_theme) self.parent.renderManager.set_global_theme( self.global_theme, self.theme_level) if self.global_theme is not u'': @@ -206,4 +201,4 @@ class ThemesTab(SettingsTab): if not preview.isNull(): preview = preview.scaled(300, 255, QtCore.Qt.KeepAspectRatio, QtCore.Qt.SmoothTransformation) - self.DefaultListView.setPixmap(preview) + self.DefaultListView.setPixmap(preview) \ No newline at end of file diff --git a/openlp/core/utils/__init__.py b/openlp/core/utils/__init__.py index 3c639297e..1bc7037ae 100644 --- a/openlp/core/utils/__init__.py +++ b/openlp/core/utils/__init__.py @@ -495,7 +495,7 @@ def get_uno_instance(resolver): 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'] diff --git a/openlp/core/utils/actions.py b/openlp/core/utils/actions.py index 41ae41f4b..0c4eee655 100644 --- a/openlp/core/utils/actions.py +++ b/openlp/core/utils/actions.py @@ -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 @@ class CategoryActionList(object): Python 3 "next" method. """ if self.index >= len(self.actions): + self.index = 0 raise StopIteration else: self.index += 1 @@ -94,6 +97,12 @@ class CategoryActionList(object): 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 @@ class CategoryList(object): Python 3 "next" method for iterator. """ if self.index >= len(self.categories): + self.index = 0 raise StopIteration else: self.index += 1 @@ -163,6 +173,11 @@ class CategoryList(object): self.categories.append(category) self.categories.sort(key=lambda cat: cat.weight) + def remove(self, name): + for category in self.categories: + if category.name == name: + self.categories.remove(category) + class ActionList(object): """ @@ -171,13 +186,101 @@ class ActionList(object): 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) + return + self.categories.add(name, weight) + + +class CategoryOrder(object): + """ + An enumeration class for category weights. + """ + standardMenu = -20 + standardToolbar = -10 diff --git a/openlp/plugins/alerts/alertsplugin.py b/openlp/plugins/alerts/alertsplugin.py index db0ba3b7e..7d6eac6e2 100644 --- a/openlp/plugins/alerts/alertsplugin.py +++ b/openlp/plugins/alerts/alertsplugin.py @@ -30,6 +30,8 @@ from PyQt4 import QtCore, QtGui 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 @@ class AlertsPlugin(Plugin): 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 @@ class AlertsPlugin(Plugin): 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 @@ class AlertsPlugin(Plugin): 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 diff --git a/openlp/plugins/bibles/bibleplugin.py b/openlp/plugins/bibles/bibleplugin.py index 4f677f211..aea732688 100644 --- a/openlp/plugins/bibles/bibleplugin.py +++ b/openlp/plugins/bibles/bibleplugin.py @@ -29,6 +29,8 @@ import logging 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 @@ class BiblePlugin(Plugin): 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 @@ class BiblePlugin(Plugin): 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') - export_menu.addAction(self.exportBibleItem) + self.exportBibleItem = base_action(export_menu, u'exportBibleItem') self.exportBibleItem.setText(translate('BiblesPlugin', '&Bible')) + export_menu.addAction(self.exportBibleItem) self.exportBibleItem.setVisible(False) def onBibleImportClick(self): diff --git a/openlp/plugins/bibles/forms/bibleimportform.py b/openlp/plugins/bibles/forms/bibleimportform.py index 117ffaf4c..35cd17c4b 100644 --- a/openlp/plugins/bibles/forms/bibleimportform.py +++ b/openlp/plugins/bibles/forms/bibleimportform.py @@ -85,8 +85,18 @@ class BibleImportForm(OpenLPWizard): """ OpenLPWizard.setupUi(self, image) QtCore.QObject.connect(self.formatComboBox, - QtCore.SIGNAL(u'currentIndexChanged(int)'), self.selectStack, - QtCore.SLOT(u'setCurrentIndex(int)')) + QtCore.SIGNAL(u'currentIndexChanged(int)'), + self.onCurrentIndexChanged) + + def onCurrentIndexChanged(self, index): + """ + Called when the format combo box's index changed. We have to check if + the import is available and accordingly to disable or enable the next + button. + """ + self.selectStack.setCurrentIndex(index) + next_button = self.button(QtGui.QWizard.NextButton) + next_button.setEnabled(BibleFormat.get_availability(index)) def customInit(self): """ diff --git a/openlp/plugins/bibles/lib/biblestab.py b/openlp/plugins/bibles/lib/biblestab.py index 7a631ad09..914377e35 100644 --- a/openlp/plugins/bibles/lib/biblestab.py +++ b/openlp/plugins/bibles/lib/biblestab.py @@ -30,6 +30,7 @@ from PyQt4 import QtCore, QtGui from openlp.core.lib import Receiver, SettingsTab, translate from openlp.plugins.bibles.lib import LayoutStyle, DisplayStyle +from openlp.core.lib.ui import UiStrings, find_and_set_in_combo_box log = logging.getLogger(__name__) @@ -48,108 +49,107 @@ class BiblesTab(SettingsTab): def setupUi(self): self.setObjectName(u'BiblesTab') SettingsTab.setupUi(self) - self.VerseDisplayGroupBox = QtGui.QGroupBox(self.leftColumn) - self.VerseDisplayGroupBox.setObjectName(u'VerseDisplayGroupBox') - self.VerseDisplayLayout = QtGui.QFormLayout(self.VerseDisplayGroupBox) - self.VerseDisplayLayout.setObjectName(u'VerseDisplayLayout') - self.NewChaptersCheckBox = QtGui.QCheckBox(self.VerseDisplayGroupBox) - self.NewChaptersCheckBox.setObjectName(u'NewChaptersCheckBox') - self.VerseDisplayLayout.addRow(self.NewChaptersCheckBox) - self.DisplayStyleLabel = QtGui.QLabel(self.VerseDisplayGroupBox) - self.DisplayStyleLabel.setObjectName(u'DisplayStyleLabel') - self.DisplayStyleComboBox = QtGui.QComboBox(self.VerseDisplayGroupBox) - self.DisplayStyleComboBox.addItems([u'', u'', u'', u'']) - self.DisplayStyleComboBox.setObjectName(u'DisplayStyleComboBox') - self.VerseDisplayLayout.addRow(self.DisplayStyleLabel, - self.DisplayStyleComboBox) - self.LayoutStyleLabel = QtGui.QLabel(self.VerseDisplayGroupBox) - self.LayoutStyleLabel.setObjectName(u'LayoutStyleLabel') - self.LayoutStyleComboBox = QtGui.QComboBox(self.VerseDisplayGroupBox) - self.LayoutStyleComboBox.setObjectName(u'LayoutStyleComboBox') - self.LayoutStyleComboBox.addItems([u'', u'', u'']) - self.VerseDisplayLayout.addRow(self.LayoutStyleLabel, - self.LayoutStyleComboBox) - self.BibleSecondCheckBox = QtGui.QCheckBox(self.VerseDisplayGroupBox) - self.BibleSecondCheckBox.setObjectName(u'BibleSecondCheckBox') - self.VerseDisplayLayout.addRow(self.BibleSecondCheckBox) - self.BibleThemeLabel = QtGui.QLabel(self.VerseDisplayGroupBox) - self.BibleThemeLabel.setObjectName(u'BibleThemeLabel') - self.BibleThemeComboBox = QtGui.QComboBox(self.VerseDisplayGroupBox) - self.BibleThemeComboBox.setSizeAdjustPolicy( + self.verseDisplayGroupBox = QtGui.QGroupBox(self.leftColumn) + self.verseDisplayGroupBox.setObjectName(u'verseDisplayGroupBox') + self.verseDisplayLayout = QtGui.QFormLayout(self.verseDisplayGroupBox) + self.verseDisplayLayout.setObjectName(u'verseDisplayLayout') + self.newChaptersCheckBox = QtGui.QCheckBox(self.verseDisplayGroupBox) + self.newChaptersCheckBox.setObjectName(u'newChaptersCheckBox') + self.verseDisplayLayout.addRow(self.newChaptersCheckBox) + self.displayStyleLabel = QtGui.QLabel(self.verseDisplayGroupBox) + self.displayStyleLabel.setObjectName(u'displayStyleLabel') + self.displayStyleComboBox = QtGui.QComboBox(self.verseDisplayGroupBox) + self.displayStyleComboBox.addItems([u'', u'', u'', u'']) + self.displayStyleComboBox.setObjectName(u'displayStyleComboBox') + self.verseDisplayLayout.addRow(self.displayStyleLabel, + self.displayStyleComboBox) + self.layoutStyleLabel = QtGui.QLabel(self.verseDisplayGroupBox) + self.layoutStyleLabel.setObjectName(u'layoutStyleLabel') + self.layoutStyleComboBox = QtGui.QComboBox(self.verseDisplayGroupBox) + self.layoutStyleComboBox.setObjectName(u'layoutStyleComboBox') + self.layoutStyleComboBox.addItems([u'', u'', u'']) + self.verseDisplayLayout.addRow(self.layoutStyleLabel, + self.layoutStyleComboBox) + self.bibleSecondCheckBox = QtGui.QCheckBox(self.verseDisplayGroupBox) + self.bibleSecondCheckBox.setObjectName(u'bibleSecondCheckBox') + self.verseDisplayLayout.addRow(self.bibleSecondCheckBox) + self.bibleThemeLabel = QtGui.QLabel(self.verseDisplayGroupBox) + self.bibleThemeLabel.setObjectName(u'BibleThemeLabel') + self.bibleThemeComboBox = QtGui.QComboBox(self.verseDisplayGroupBox) + self.bibleThemeComboBox.setSizeAdjustPolicy( QtGui.QComboBox.AdjustToMinimumContentsLength) - self.BibleThemeComboBox.setSizePolicy( + self.bibleThemeComboBox.setSizePolicy( QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Fixed) - self.BibleThemeComboBox.addItem(u'') - self.BibleThemeComboBox.setObjectName(u'BibleThemeComboBox') - self.VerseDisplayLayout.addRow(self.BibleThemeLabel, - self.BibleThemeComboBox) - self.ChangeNoteLabel = QtGui.QLabel(self.VerseDisplayGroupBox) - self.ChangeNoteLabel.setWordWrap(True) - self.ChangeNoteLabel.setObjectName(u'ChangeNoteLabel') - self.VerseDisplayLayout.addRow(self.ChangeNoteLabel) - self.leftLayout.addWidget(self.VerseDisplayGroupBox) + self.bibleThemeComboBox.addItem(u'') + self.bibleThemeComboBox.setObjectName(u'BibleThemeComboBox') + self.verseDisplayLayout.addRow(self.bibleThemeLabel, + self.bibleThemeComboBox) + self.changeNoteLabel = QtGui.QLabel(self.verseDisplayGroupBox) + self.changeNoteLabel.setWordWrap(True) + self.changeNoteLabel.setObjectName(u'changeNoteLabel') + self.verseDisplayLayout.addRow(self.changeNoteLabel) + self.leftLayout.addWidget(self.verseDisplayGroupBox) self.leftLayout.addStretch() self.rightColumn.setSizePolicy( QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Preferred) self.rightLayout.addStretch() # Signals and slots QtCore.QObject.connect( - self.NewChaptersCheckBox, QtCore.SIGNAL(u'stateChanged(int)'), + self.newChaptersCheckBox, QtCore.SIGNAL(u'stateChanged(int)'), self.onNewChaptersCheckBoxChanged) QtCore.QObject.connect( - self.DisplayStyleComboBox, QtCore.SIGNAL(u'activated(int)'), + self.displayStyleComboBox, QtCore.SIGNAL(u'activated(int)'), self.onDisplayStyleComboBoxChanged) QtCore.QObject.connect( - self.BibleThemeComboBox, QtCore.SIGNAL(u'activated(int)'), + self.bibleThemeComboBox, QtCore.SIGNAL(u'activated(int)'), self.onBibleThemeComboBoxChanged) QtCore.QObject.connect( - self.LayoutStyleComboBox, QtCore.SIGNAL(u'activated(int)'), + self.layoutStyleComboBox, QtCore.SIGNAL(u'activated(int)'), self.onLayoutStyleComboBoxChanged) QtCore.QObject.connect( - self.BibleSecondCheckBox, QtCore.SIGNAL(u'stateChanged(int)'), + self.bibleSecondCheckBox, QtCore.SIGNAL(u'stateChanged(int)'), self.onBibleSecondCheckBox) QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'theme_update_list'), self.updateThemeList) def retranslateUi(self): - self.VerseDisplayGroupBox.setTitle( + self.verseDisplayGroupBox.setTitle( translate('BiblesPlugin.BiblesTab', 'Verse Display')) - self.NewChaptersCheckBox.setText( + self.newChaptersCheckBox.setText( translate('BiblesPlugin.BiblesTab', 'Only show new chapter numbers')) - self.LayoutStyleLabel.setText( + self.layoutStyleLabel.setText( translate('BiblesPlugin.BiblesTab', 'Layout style:')) - self.DisplayStyleLabel.setText( - translate('BiblesPlugin.BiblesTab', 'Display style:')) - self.BibleThemeLabel.setText( + self.displayStyleLabel.setText(UiStrings.DisplayStyle) + self.bibleThemeLabel.setText( translate('BiblesPlugin.BiblesTab', 'Bible theme:')) - self.LayoutStyleComboBox.setItemText(LayoutStyle.VersePerSlide, - translate('BiblesPlugin.BiblesTab', 'Verse Per Slide')) - self.LayoutStyleComboBox.setItemText(LayoutStyle.VersePerLine, - translate('BiblesPlugin.BiblesTab', 'Verse Per Line')) - self.LayoutStyleComboBox.setItemText(LayoutStyle.Continuous, - translate('BiblesPlugin.BiblesTab', 'Continuous')) - self.DisplayStyleComboBox.setItemText(DisplayStyle.NoBrackets, + self.layoutStyleComboBox.setItemText(LayoutStyle.VersePerSlide, + UiStrings.VersePerSlide) + self.layoutStyleComboBox.setItemText(LayoutStyle.VersePerLine, + UiStrings.VersePerLine) + self.layoutStyleComboBox.setItemText(LayoutStyle.Continuous, + UiStrings.Continuous) + self.displayStyleComboBox.setItemText(DisplayStyle.NoBrackets, translate('BiblesPlugin.BiblesTab', 'No Brackets')) - self.DisplayStyleComboBox.setItemText(DisplayStyle.Round, + self.displayStyleComboBox.setItemText(DisplayStyle.Round, translate('BiblesPlugin.BiblesTab', '( And )')) - self.DisplayStyleComboBox.setItemText(DisplayStyle.Curly, + self.displayStyleComboBox.setItemText(DisplayStyle.Curly, translate('BiblesPlugin.BiblesTab', '{ And }')) - self.DisplayStyleComboBox.setItemText(DisplayStyle.Square, + self.displayStyleComboBox.setItemText(DisplayStyle.Square, translate('BiblesPlugin.BiblesTab', '[ And ]')) - self.ChangeNoteLabel.setText(translate('BiblesPlugin.BiblesTab', + self.changeNoteLabel.setText(translate('BiblesPlugin.BiblesTab', 'Note:\nChanges do not affect verses already in the service.')) - self.BibleSecondCheckBox.setText( + self.bibleSecondCheckBox.setText( translate('BiblesPlugin.BiblesTab', 'Display second Bible verses')) def onBibleThemeComboBoxChanged(self): - self.bible_theme = self.BibleThemeComboBox.currentText() + self.bible_theme = self.bibleThemeComboBox.currentText() def onDisplayStyleComboBoxChanged(self): - self.display_style = self.DisplayStyleComboBox.currentIndex() + self.display_style = self.displayStyleComboBox.currentIndex() def onLayoutStyleComboBoxChanged(self): - self.layout_style = self.LayoutStyleComboBox.currentIndex() + self.layout_style = self.layoutStyleComboBox.currentIndex() def onNewChaptersCheckBoxChanged(self, check_state): self.show_new_chapters = False @@ -176,10 +176,10 @@ class BiblesTab(SettingsTab): settings.value(u'bible theme', QtCore.QVariant(u'')).toString()) self.second_bibles = settings.value( u'second bibles', QtCore.QVariant(True)).toBool() - self.NewChaptersCheckBox.setChecked(self.show_new_chapters) - self.DisplayStyleComboBox.setCurrentIndex(self.display_style) - self.LayoutStyleComboBox.setCurrentIndex(self.layout_style) - self.BibleSecondCheckBox.setChecked(self.second_bibles) + self.newChaptersCheckBox.setChecked(self.show_new_chapters) + self.displayStyleComboBox.setCurrentIndex(self.display_style) + self.layoutStyleComboBox.setCurrentIndex(self.layout_style) + self.bibleSecondCheckBox.setChecked(self.second_bibles) settings.endGroup() def save(self): @@ -204,14 +204,8 @@ class BiblesTab(SettingsTab): [u'Bible Theme', u'Song Theme'] """ - self.BibleThemeComboBox.clear() - self.BibleThemeComboBox.addItem(u'') + self.bibleThemeComboBox.clear() + self.bibleThemeComboBox.addItem(u'') for theme in theme_list: - self.BibleThemeComboBox.addItem(theme) - index = self.BibleThemeComboBox.findText( - unicode(self.bible_theme), QtCore.Qt.MatchExactly) - if index == -1: - # Not Found. - index = 0 - self.bible_theme = u'' - self.BibleThemeComboBox.setCurrentIndex(index) + self.bibleThemeComboBox.addItem(theme) + find_and_set_in_combo_box(self.bibleThemeComboBox, self.bible_theme) diff --git a/openlp/plugins/bibles/lib/mediaitem.py b/openlp/plugins/bibles/lib/mediaitem.py index a9694fd0c..118bdfc66 100644 --- a/openlp/plugins/bibles/lib/mediaitem.py +++ b/openlp/plugins/bibles/lib/mediaitem.py @@ -32,7 +32,7 @@ from openlp.core.lib import MediaManagerItem, Receiver, ItemCapabilities, \ translate from openlp.core.lib.searchedit import SearchEdit from openlp.core.lib.ui import UiStrings, add_widget_completer, \ - media_item_combo_box, critical_error_message_box + media_item_combo_box, critical_error_message_box, find_and_set_in_combo_box from openlp.plugins.bibles.forms import BibleImportForm from openlp.plugins.bibles.lib import LayoutStyle, DisplayStyle, \ VerseReferenceList, get_reference_match @@ -106,6 +106,12 @@ class BibleMediaItem(MediaManagerItem): translate('BiblesPlugin.MediaItem', 'Text Search')) ]) self.quickLayout.addRow(self.quickSearchLabel, self.quickSearchEdit) + self.quickLayoutLabel = QtGui.QLabel(self.quickTab) + self.quickLayoutLabel.setObjectName(u'quickClearLabel') + self.quickLayoutComboBox = media_item_combo_box(self.quickTab, + u'quickLayoutComboBox') + self.quickLayoutComboBox.addItems([u'', u'', u'']) + self.quickLayout.addRow(self.quickLayoutLabel, self.quickLayoutComboBox) self.quickClearLabel = QtGui.QLabel(self.quickTab) self.quickClearLabel.setObjectName(u'quickClearLabel') self.quickClearComboBox = media_item_combo_box(self.quickTab, @@ -210,6 +216,9 @@ class BibleMediaItem(MediaManagerItem): QtCore.SIGNAL(u'searchTypeChanged(int)'), self.updateAutoCompleter) QtCore.QObject.connect(self.quickVersionComboBox, QtCore.SIGNAL(u'activated(int)'), self.updateAutoCompleter) + QtCore.QObject.connect( + self.quickLayoutComboBox, QtCore.SIGNAL(u'activated(int)'), + self.onlayoutStyleComboBoxChanged) # Buttons QtCore.QObject.connect(self.advancedSearchButton, QtCore.SIGNAL(u'pressed()'), self.onAdvancedSearchButton) @@ -234,6 +243,7 @@ class BibleMediaItem(MediaManagerItem): self.advancedSecondComboBox.setVisible(False) self.quickSecondLabel.setVisible(False) self.quickSecondComboBox.setVisible(False) + self.quickLayoutComboBox.setCurrentIndex(self.settings.layout_style) def retranslateUi(self): log.debug(u'retranslateUi') @@ -269,11 +279,22 @@ class BibleMediaItem(MediaManagerItem): translate('BiblesPlugin.MediaItem', 'Clear')) self.advancedClearComboBox.addItem( translate('BiblesPlugin.MediaItem', 'Keep')) + self.quickLayoutLabel.setText(UiStrings.DisplayStyle) + self.quickLayoutComboBox.setItemText(LayoutStyle.VersePerSlide, + UiStrings.VersePerSlide) + self.quickLayoutComboBox.setItemText(LayoutStyle.VersePerLine, + UiStrings.VersePerLine) + self.quickLayoutComboBox.setItemText(LayoutStyle.Continuous, + UiStrings.Continuous) def initialise(self): log.debug(u'bible manager initialise') self.parent.manager.media = self self.loadBibles() + bible = QtCore.QSettings().value( + self.settingsSection + u'/quick bible', QtCore.QVariant( + self.quickVersionComboBox.currentText())).toString() + find_and_set_in_combo_box(self.quickVersionComboBox, bible) self.updateAutoCompleter() self.configUpdated() log.debug(u'bible manager initialise complete') @@ -298,23 +319,28 @@ class BibleMediaItem(MediaManagerItem): bibles = self.parent.manager.get_bibles().keys() bibles.sort() # Load the bibles into the combo boxes. - first = True for bible in bibles: if bible: self.quickVersionComboBox.addItem(bible) self.quickSecondComboBox.addItem(bible) self.advancedVersionComboBox.addItem(bible) self.advancedSecondComboBox.addItem(bible) - if first: - first = False - self.initialiseBible(bible) + # set the default value + bible = QtCore.QSettings().value( + self.settingsSection + u'/advanced bible', + QtCore.QVariant(u'')).toString() + if bible in bibles: + find_and_set_in_combo_box(self.advancedVersionComboBox, bible) + self.initialiseAdvancedBible(unicode(bible)) + elif len(bibles): + self.initialiseAdvancedBible(bibles[0]) def reloadBibles(self): log.debug(u'Reloading Bibles') self.parent.manager.reload_bibles() self.loadBibles() - def initialiseBible(self, bible): + def initialiseAdvancedBible(self, bible): """ This initialises the given bible, which means that its book names and their chapter numbers is added to the combo boxes on the @@ -324,7 +350,7 @@ class BibleMediaItem(MediaManagerItem): ``bible`` The bible to initialise (unicode). """ - log.debug(u'initialiseBible %s', bible) + log.debug(u'initialiseAdvancedBible %s', bible) book_data = self.parent.manager.get_books(bible) self.advancedBookComboBox.clear() first = True @@ -360,6 +386,8 @@ class BibleMediaItem(MediaManagerItem): completion depends on the bible. It is only updated when we are doing a reference search, otherwise the auto completion list is removed. """ + QtCore.QSettings().setValue(self.settingsSection + u'/quick bible', + QtCore.QVariant(self.quickVersionComboBox.currentText())) books = [] # We have to do a 'Reference Search'. if self.quickSearchEdit.currentSearchType() == BibleSearch.Reference: @@ -367,12 +395,14 @@ class BibleMediaItem(MediaManagerItem): bible = unicode(self.quickVersionComboBox.currentText()) if bible: book_data = bibles[bible].get_books() - books = [book.name for book in book_data] + books = [book.name + u' ' for book in book_data] books.sort() add_widget_completer(books, self.quickSearchEdit) def onAdvancedVersionComboBox(self): - self.initialiseBible( + QtCore.QSettings().setValue(self.settingsSection + u'/advanced bible', + QtCore.QVariant(self.advancedVersionComboBox.currentText())) + self.initialiseAdvancedBible( unicode(self.advancedVersionComboBox.currentText())) def onAdvancedBookComboBox(self): @@ -804,3 +834,11 @@ class BibleMediaItem(MediaManagerItem): if self.settings.display_style == DisplayStyle.Square: return u'{su}[%s]{/su}' % verse_text return u'{su}%s{/su}' % verse_text + + def onlayoutStyleComboBoxChanged(self): + self.settings.layout_style = self.quickLayoutComboBox.currentIndex() + self.settings.layoutStyleComboBox.setCurrentIndex( + self.settings.layout_style) + QtCore.QSettings().setValue( + self.settingsSection + u'/verse layout style', + QtCore.QVariant(self.settings.layout_style)) diff --git a/openlp/plugins/bibles/lib/versereferencelist.py b/openlp/plugins/bibles/lib/versereferencelist.py index bc28f2570..bab6d7e11 100644 --- a/openlp/plugins/bibles/lib/versereferencelist.py +++ b/openlp/plugins/bibles/lib/versereferencelist.py @@ -96,4 +96,7 @@ class VerseReferenceList(object): version[u'copyright']) if version[u'permission'].strip(): result = result + u', ' + version[u'permission'] + result = result.rstrip() + if result.endswith(u','): + return result[:len(result)-1] return result diff --git a/openlp/plugins/custom/forms/editcustomform.py b/openlp/plugins/custom/forms/editcustomform.py index f81bd4c7d..9312b5ddd 100644 --- a/openlp/plugins/custom/forms/editcustomform.py +++ b/openlp/plugins/custom/forms/editcustomform.py @@ -29,7 +29,7 @@ import logging from PyQt4 import QtCore, QtGui from openlp.core.lib import Receiver, translate -from openlp.core.lib.ui import critical_error_message_box +from openlp.core.lib.ui import critical_error_message_box, find_and_set_in_combo_box from openlp.plugins.custom.lib import CustomXMLBuilder, CustomXMLParser from openlp.plugins.custom.lib.db import CustomSlide from editcustomdialog import Ui_CustomEditDialog @@ -98,11 +98,7 @@ class EditCustomForm(QtGui.QDialog, Ui_CustomEditDialog): for slide in slideList: self.slideListView.addItem(slide[1]) theme = self.customSlide.theme_name - id = self.themeComboBox.findText(theme, QtCore.Qt.MatchExactly) - # No theme match - if id == -1: - id = 0 - self.themeComboBox.setCurrentIndex(id) + find_and_set_in_combo_box(self.themeComboBox, theme) # If not preview hide the preview button. self.previewButton.setVisible(False) if preview: @@ -265,4 +261,4 @@ class EditCustomForm(QtGui.QDialog, Ui_CustomEditDialog): message=translate('CustomPlugin.EditCustomForm', 'You need to add at least one slide')) return False - return True + return True \ No newline at end of file diff --git a/openlp/plugins/songs/forms/editsongform.py b/openlp/plugins/songs/forms/editsongform.py index 2f21e57cd..85294d92b 100644 --- a/openlp/plugins/songs/forms/editsongform.py +++ b/openlp/plugins/songs/forms/editsongform.py @@ -31,7 +31,7 @@ from PyQt4 import QtCore, QtGui from openlp.core.lib import Receiver, translate from openlp.core.lib.ui import UiStrings, add_widget_completer, \ - critical_error_message_box + critical_error_message_box, find_and_set_in_combo_box from openlp.plugins.songs.forms import EditVerseForm from openlp.plugins.songs.lib import SongXML, VerseType, clean_song from openlp.plugins.songs.lib.db import Book, Song, Author, Topic @@ -208,20 +208,9 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog): self.alternativeEdit.setText(u'') if self.song.song_book_id != 0: book_name = self.manager.get_object(Book, self.song.song_book_id) - id = self.songBookComboBox.findText( - unicode(book_name.name), QtCore.Qt.MatchExactly) - if id == -1: - # Not Found - id = 0 - self.songBookComboBox.setCurrentIndex(id) + find_and_set_in_combo_box(self.songBookComboBox, unicode(book_name.name)) if self.song.theme_name: - id = self.themeComboBox.findText( - unicode(self.song.theme_name), QtCore.Qt.MatchExactly) - if id == -1: - # Not Found - id = 0 - self.song.theme_name = None - self.themeComboBox.setCurrentIndex(id) + find_and_set_in_combo_box(self.themeComboBox, unicode(self.song.theme_name)) if self.song.copyright: self.copyrightEdit.setText(self.song.copyright) else: @@ -790,4 +779,4 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog): self.song.verse_order) except: log.exception(u'Problem processing song Lyrics \n%s', - sxml.dump_xml()) + sxml.dump_xml()) \ No newline at end of file diff --git a/openlp/plugins/songs/forms/songimportform.py b/openlp/plugins/songs/forms/songimportform.py index 6d20c8f41..468d2f341 100644 --- a/openlp/plugins/songs/forms/songimportform.py +++ b/openlp/plugins/songs/forms/songimportform.py @@ -66,7 +66,17 @@ class SongImportForm(OpenLPWizard): self.formatStack.setCurrentIndex(0) QtCore.QObject.connect(self.formatComboBox, QtCore.SIGNAL(u'currentIndexChanged(int)'), - self.formatStack.setCurrentIndex) + self.onCurrentIndexChanged) + + def onCurrentIndexChanged(self, index): + """ + Called when the format combo box's index changed. We have to check if + the import is available and accordingly to disable or enable the next + button. + """ + self.formatStack.setCurrentIndex(index) + next_button = self.button(QtGui.QWizard.NextButton) + next_button.setEnabled(SongFormat.get_availability(index)) def customInit(self): """ diff --git a/openlp/plugins/songs/lib/mediaitem.py b/openlp/plugins/songs/lib/mediaitem.py index f4803d653..e2882ed29 100644 --- a/openlp/plugins/songs/lib/mediaitem.py +++ b/openlp/plugins/songs/lib/mediaitem.py @@ -283,19 +283,20 @@ class SongMediaItem(MediaManagerItem): self.remoteTriggered = None self.remoteSong = -1 - def onRemoteEdit(self, songid): + def onRemoteEdit(self, message): """ Called by ServiceManager or SlideController by event passing the Song Id in the payload along with an indicator to say which type of display is required. """ - log.debug(u'onRemoteEdit %s' % songid) - fields = songid.split(u':') - valid = self.parent.manager.get_object(Song, fields[1]) + log.debug(u'onRemoteEdit %s' % message) + remote_type, song_id = message.split(u':') + song_id = int(song_id) + valid = self.parent.manager.get_object(Song, song_id) if valid: - self.remoteSong = fields[1] - self.remoteTriggered = fields[0] - self.edit_song_form.loadSong(fields[1], (fields[0] == u'P')) + self.remoteSong = song_id + self.remoteTriggered = remote_type + self.edit_song_form.loadSong(song_id, (remote_type == u'P')) self.edit_song_form.exec_() def onEditClick(self): diff --git a/openlp/plugins/songs/lib/oooimport.py b/openlp/plugins/songs/lib/oooimport.py index c9c05907e..2ab66820c 100644 --- a/openlp/plugins/songs/lib/oooimport.py +++ b/openlp/plugins/songs/lib/oooimport.py @@ -39,12 +39,8 @@ if os.name == u'nt': PAGE_AFTER = 5 PAGE_BOTH = 6 else: - try: - import uno - from com.sun.star.style.BreakType import PAGE_BEFORE, PAGE_AFTER, \ - PAGE_BOTH - except ImportError: - pass + import uno + from com.sun.star.style.BreakType import PAGE_BEFORE, PAGE_AFTER, PAGE_BOTH class OooImport(SongImport): """ diff --git a/openlp/plugins/songs/lib/openlyricsexport.py b/openlp/plugins/songs/lib/openlyricsexport.py index d3367bfa9..59b720d3e 100644 --- a/openlp/plugins/songs/lib/openlyricsexport.py +++ b/openlp/plugins/songs/lib/openlyricsexport.py @@ -73,6 +73,8 @@ class OpenLyricsExport(object): u', '.join([author.display_name for author in song.authors])) filename = re.sub( r'[/\\?*|<>\[\]":<>+%]+', u'_', filename).strip(u'_') - tree.write(os.path.join(self.save_path, filename), + # Pass a file object, because lxml does not cope with some special + # characters in the path (see lp:757673 and lp:744337). + tree.write(open(os.path.join(self.save_path, filename), u'w'), encoding=u'utf-8', xml_declaration=True, pretty_print=True) return True diff --git a/openlp/plugins/songs/lib/openlyricsimport.py b/openlp/plugins/songs/lib/openlyricsimport.py index 208ef3e52..c29abc0b5 100644 --- a/openlp/plugins/songs/lib/openlyricsimport.py +++ b/openlp/plugins/songs/lib/openlyricsimport.py @@ -63,7 +63,9 @@ class OpenLyricsImport(SongImport): self.import_wizard.incrementProgressBar( WizardStrings.ImportingType % os.path.basename(file_path)) try: - parsed_file = etree.parse(file_path, parser) + # Pass a file object, because lxml does not cope with some + # special characters in the path (see lp:757673 and lp:744337). + parsed_file = etree.parse(open(file_path, u'r'), parser) xml = unicode(etree.tostring(parsed_file)) if self.openLyrics.xml_to_song(xml) is None: log.debug(u'File could not be imported: %s' % file_path) diff --git a/openlp/plugins/songs/songsplugin.py b/openlp/plugins/songs/songsplugin.py index 1260a832b..af50f3f94 100644 --- a/openlp/plugins/songs/songsplugin.py +++ b/openlp/plugins/songs/songsplugin.py @@ -33,7 +33,8 @@ from PyQt4 import QtCore, QtGui 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 @@ class SongsPlugin(Plugin): 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 @@ class SongsPlugin(Plugin): 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 @@ class SongsPlugin(Plugin): 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 @@ class SongsPlugin(Plugin): 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 @@ class SongsPlugin(Plugin): 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) diff --git a/openlp/plugins/songusage/songusageplugin.py b/openlp/plugins/songusage/songusageplugin.py index 8ff40373a..5f21451b6 100644 --- a/openlp/plugins/songusage/songusageplugin.py +++ b/openlp/plugins/songusage/songusageplugin.py @@ -32,6 +32,8 @@ from PyQt4 import QtCore, QtGui 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 @@ class SongUsagePlugin(Plugin): 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 @@ class SongUsagePlugin(Plugin): 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 @@ class SongUsagePlugin(Plugin): 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 @@ class SongUsagePlugin(Plugin): 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 diff --git a/resources/forms/shortcutlistdialog.ui b/resources/forms/shortcutlistdialog.ui index 519925560..9a5c599d1 100644 --- a/resources/forms/shortcutlistdialog.ui +++ b/resources/forms/shortcutlistdialog.ui @@ -41,35 +41,35 @@ - + + + 0 + 8 - - 0 - - + - Default: None + Default: true - - + + + + Custom: + + + + + 8 - - - - Custom: - - - @@ -83,7 +83,7 @@ - :/system/system_settings.png:/system/system_settings.png + :/system/system_configure_shortcuts.png:/system/system_configure_shortcuts.png true @@ -110,21 +110,51 @@ + + + + + + 8 + - - - Qt::Horizontal + + + None - - - 40 - 20 - + + + :/system/system_configure_shortcuts.png:/system/system_configure_shortcuts.png - + + + + + + + + + + :/system/clear_shortcut.png:/system/clear_shortcut.png + + + + + + Ctrl+V + + + + + + + Shift+Ins + + +