diff --git a/openlp/core/lib/__init__.py b/openlp/core/lib/__init__.py index 150ad2ea6..4d8ba6bec 100644 --- a/openlp/core/lib/__init__.py +++ b/openlp/core/lib/__init__.py @@ -43,6 +43,26 @@ class MediaType(object): Audio = 1 Video = 2 + +class SlideLimits(object): + """ + Provides an enumeration for behaviour of OpenLP at the end limits of each + service item when pressing the up/down arrow keys + """ + End = 1 + Wrap = 2 + Next = 3 + + +class ServiceItemAction(object): + """ + Provides an enumeration for the required action moving between service + items by left/right arrow keys + """ + Previous = 1 + PreviousLastSlide = 2 + Next = 3 + def translate(context, text, comment=None, encoding=QtCore.QCoreApplication.CodecForTr, n=-1, translate=QtCore.QCoreApplication.translate): diff --git a/openlp/core/lib/eventreceiver.py b/openlp/core/lib/eventreceiver.py index e3914d98a..35459e9dd 100644 --- a/openlp/core/lib/eventreceiver.py +++ b/openlp/core/lib/eventreceiver.py @@ -111,6 +111,9 @@ class EventReceiver(QtCore.QObject): ``slidecontroller_live_spin_delay`` Pushes out the loop delay. + + ``slidecontroller_update_slide_limits`` + Updates the slide_limits variable from the saved settings. ``slidecontroller_live_stop_loop`` Stop the loop on the main display. diff --git a/openlp/core/ui/advancedtab.py b/openlp/core/ui/advancedtab.py index 045d38a7e..7c522bc67 100644 --- a/openlp/core/ui/advancedtab.py +++ b/openlp/core/ui/advancedtab.py @@ -31,6 +31,7 @@ from PyQt4 import QtCore, QtGui from openlp.core.lib import SettingsTab, translate, build_icon, Receiver from openlp.core.lib.ui import UiStrings +from openlp.core.lib import SlideLimits from openlp.core.utils import get_images_filter class AdvancedTab(SettingsTab): @@ -84,7 +85,6 @@ class AdvancedTab(SettingsTab): u'enableAutoCloseCheckBox') self.uiLayout.addRow(self.enableAutoCloseCheckBox) self.leftLayout.addWidget(self.uiGroupBox) - self.leftLayout.addStretch() self.defaultImageGroupBox = QtGui.QGroupBox(self.rightColumn) self.defaultImageGroupBox.setObjectName(u'defaultImageGroupBox') self.defaultImageLayout = QtGui.QFormLayout(self.defaultImageGroupBox) @@ -114,7 +114,7 @@ class AdvancedTab(SettingsTab): self.defaultFileLayout.addWidget(self.defaultRevertButton) self.defaultImageLayout.addRow(self.defaultFileLabel, self.defaultFileLayout) - self.rightLayout.addWidget(self.defaultImageGroupBox) + self.leftLayout.addWidget(self.defaultImageGroupBox) self.hideMouseGroupBox = QtGui.QGroupBox(self.leftColumn) self.hideMouseGroupBox.setObjectName(u'hideMouseGroupBox') self.hideMouseLayout = QtGui.QVBoxLayout(self.hideMouseGroupBox) @@ -122,7 +122,39 @@ class AdvancedTab(SettingsTab): self.hideMouseCheckBox = QtGui.QCheckBox(self.hideMouseGroupBox) self.hideMouseCheckBox.setObjectName(u'hideMouseCheckBox') self.hideMouseLayout.addWidget(self.hideMouseCheckBox) - self.rightLayout.addWidget(self.hideMouseGroupBox) + self.leftLayout.addWidget(self.hideMouseGroupBox) + self.leftLayout.addStretch() + # Service Item Slide Limits + self.slideGroupBox = QtGui.QGroupBox(self.rightColumn) + self.slideGroupBox.setObjectName(u'slideGroupBox') + self.slideLayout = QtGui.QFormLayout(self.slideGroupBox) + self.slideLayout.setLabelAlignment( + QtCore.Qt.AlignLeft | QtCore.Qt.AlignTop) + self.slideLayout.setFormAlignment( + QtCore.Qt.AlignLeft | QtCore.Qt.AlignTop) + self.slideLayout.setObjectName(u'slideLayout') + self.endSlideRadioButton = QtGui.QRadioButton(self.slideGroupBox) + self.endSlideRadioButton.setObjectName(u'endSlideRadioButton') + self.endSlideLabel = QtGui.QLabel(self.slideGroupBox) + self.endSlideLabel.setWordWrap(True) + self.endSlideLabel.setObjectName(u'endSlideLabel') + self.slideLayout.addRow(self.endSlideRadioButton, self.endSlideLabel) + self.wrapSlideRadioButton = QtGui.QRadioButton(self.slideGroupBox) + self.wrapSlideRadioButton.setObjectName(u'wrapSlideRadioButton') + self.wrapSlideLabel = QtGui.QLabel(self.slideGroupBox) + self.wrapSlideLabel.setWordWrap(True) + self.wrapSlideLabel.setObjectName(u'wrapSlideLabel') + self.slideLayout.addRow(self.wrapSlideRadioButton, + self.wrapSlideLabel) + self.nextItemRadioButton = QtGui.QRadioButton(self.slideGroupBox) + self.nextItemRadioButton.setChecked(True) + self.nextItemRadioButton.setObjectName(u'nextItemRadioButton') + self.nextItemLabel = QtGui.QLabel(self.slideGroupBox) + self.nextItemLabel.setWordWrap(True) + self.nextItemLabel.setObjectName(u'nextItemLabel') + self.slideLayout.addRow(self.nextItemRadioButton, + self.nextItemLabel) + self.rightLayout.addWidget(self.slideGroupBox) self.x11GroupBox = QtGui.QGroupBox(self.leftColumn) self.x11GroupBox.setObjectName(u'x11GroupBox') self.x11Layout = QtGui.QVBoxLayout(self.x11GroupBox) @@ -141,6 +173,12 @@ class AdvancedTab(SettingsTab): QtCore.SIGNAL(u'pressed()'), self.onDefaultRevertButtonPressed) QtCore.QObject.connect(self.x11BypassCheckBox, QtCore.SIGNAL(u'toggled(bool)'), self.onX11BypassCheckBoxToggled) + QtCore.QObject.connect(self.endSlideRadioButton, + QtCore.SIGNAL(u'pressed()'), self.onEndSlideButtonPressed) + QtCore.QObject.connect(self.wrapSlideRadioButton, + QtCore.SIGNAL(u'pressed()'), self.onWrapSlideButtonPressed) + QtCore.QObject.connect(self.nextItemRadioButton, + QtCore.SIGNAL(u'pressed()'), self.onnextItemButtonPressed) def retranslateUi(self): """ @@ -182,6 +220,25 @@ class AdvancedTab(SettingsTab): 'X11')) self.x11BypassCheckBox.setText(translate('OpenLP.AdvancedTab', 'Bypass X11 Window Manager')) + # Slide Limits + self.slideGroupBox.setTitle( + translate('OpenLP.GeneralTab', 'Service Item Slide Limits')) + self.endSlideRadioButton.setText( + translate('OpenLP.GeneralTab', '&End Slide')) + self.endSlideLabel.setText( + translate('OpenLP.GeneralTab', 'Up and down arrow keys ' + 'stop at the top and bottom slides of each Service Item.')) + self.wrapSlideRadioButton.setText( + translate('OpenLP.GeneralTab', '&Wrap Slide')) + self.wrapSlideLabel.setText( + translate('OpenLP.GeneralTab', 'Up and down arrow keys ' + 'wrap around at the top and bottom slides of each Service Item.')) + self.nextItemRadioButton.setText( + translate('OpenLP.GeneralTab', '&Next Item')) + self.nextItemLabel.setText( + translate('OpenLP.GeneralTab', 'Up and down arrow keys ' + 'advance to the the next or previous Service Item from the ' + 'top and bottom slides of each Service Item.')) def load(self): """ @@ -220,6 +277,14 @@ class AdvancedTab(SettingsTab): self.defaultFileEdit.setText(settings.value(u'default image', QtCore.QVariant(u':/graphics/openlp-splash-screen.png'))\ .toString()) + self.slide_limits = settings.value( + u'slide limits', QtCore.QVariant(SlideLimits.End)).toInt()[0] + if self.slide_limits == SlideLimits.End: + self.endSlideRadioButton.setChecked(True) + elif self.slide_limits == SlideLimits.Wrap: + self.wrapSlideRadioButton.setChecked(True) + else: + self.nextItemRadioButton.setChecked(True) settings.endGroup() self.defaultColorButton.setStyleSheet( u'background-color: %s' % self.default_color) @@ -248,10 +313,12 @@ class AdvancedTab(SettingsTab): QtCore.QVariant(self.x11BypassCheckBox.isChecked())) settings.setValue(u'default color', self.default_color) settings.setValue(u'default image', self.defaultFileEdit.text()) + settings.setValue(u'slide limits', QtCore.QVariant(self.slide_limits)) settings.endGroup() if self.display_changed: Receiver.send_message(u'config_screen_changed') self.display_changed = False + Receiver.send_message(u'slidecontroller_update_slide_limits') def onDefaultColorButtonPressed(self): new_color = QtGui.QColorDialog.getColor( @@ -283,3 +350,12 @@ class AdvancedTab(SettingsTab): The state of the check box (boolean). """ self.display_changed = True + + def onEndSlideButtonPressed(self): + self.slide_limits = SlideLimits.End + + def onWrapSlideButtonPressed(self): + self.slide_limits = SlideLimits.Wrap + + def onnextItemButtonPressed(self): + self.slide_limits = SlideLimits.Next diff --git a/openlp/core/ui/generaltab.py b/openlp/core/ui/generaltab.py index d86c122b7..d515fc501 100644 --- a/openlp/core/ui/generaltab.py +++ b/openlp/core/ui/generaltab.py @@ -97,9 +97,6 @@ class GeneralTab(SettingsTab): self.autoPreviewCheckBox = QtGui.QCheckBox(self.settingsGroupBox) self.autoPreviewCheckBox.setObjectName(u'autoPreviewCheckBox') self.settingsLayout.addRow(self.autoPreviewCheckBox) - self.enableLoopCheckBox = QtGui.QCheckBox(self.settingsGroupBox) - self.enableLoopCheckBox.setObjectName(u'enableLoopCheckBox') - self.settingsLayout.addRow(self.enableLoopCheckBox) # Moved here from image tab self.timeoutLabel = QtGui.QLabel(self.settingsGroupBox) self.timeoutLabel.setObjectName(u'timeoutLabel') @@ -231,8 +228,6 @@ class GeneralTab(SettingsTab): 'Unblank display when adding new live item')) self.autoPreviewCheckBox.setText(translate('OpenLP.GeneralTab', 'Automatically preview next item in service')) - self.enableLoopCheckBox.setText(translate('OpenLP.GeneralTab', - 'Enable slide wrap-around')) self.timeoutLabel.setText(translate('OpenLP.GeneralTab', 'Timed slide interval:')) self.timeoutSpinBox.setSuffix(translate('OpenLP.GeneralTab', ' sec')) @@ -289,8 +284,6 @@ class GeneralTab(SettingsTab): QtCore.QVariant(True)).toBool()) self.autoPreviewCheckBox.setChecked(settings.value(u'auto preview', QtCore.QVariant(False)).toBool()) - self.enableLoopCheckBox.setChecked(settings.value(u'enable slide loop', - QtCore.QVariant(True)).toBool()) self.timeoutSpinBox.setValue(settings.value(u'loop delay', QtCore.QVariant(5)).toInt()[0]) self.overrideCheckBox.setChecked(settings.value(u'override position', @@ -311,6 +304,7 @@ class GeneralTab(SettingsTab): self.customHeightValueEdit.setEnabled(self.overrideCheckBox.isChecked()) self.customWidthValueEdit.setEnabled(self.overrideCheckBox.isChecked()) self.display_changed = False + settings.beginGroup(self.settingsSection) def save(self): """ @@ -336,8 +330,6 @@ class GeneralTab(SettingsTab): QtCore.QVariant(self.autoUnblankCheckBox.isChecked())) settings.setValue(u'auto preview', QtCore.QVariant(self.autoPreviewCheckBox.isChecked())) - settings.setValue(u'enable slide loop', - QtCore.QVariant(self.enableLoopCheckBox.isChecked())) settings.setValue(u'loop delay', QtCore.QVariant(self.timeoutSpinBox.value())) settings.setValue(u'ccli number', @@ -358,7 +350,7 @@ class GeneralTab(SettingsTab): QtCore.QVariant(self.overrideCheckBox.isChecked())) settings.setValue(u'audio start paused', QtCore.QVariant(self.startPausedCheckBox.isChecked())) - settings.endGroup() + settings.endGroup() # On save update the screens as well self.postSetUp(True) diff --git a/openlp/core/ui/mainwindow.py b/openlp/core/ui/mainwindow.py index 88368b99d..947c1318d 100644 --- a/openlp/core/ui/mainwindow.py +++ b/openlp/core/ui/mainwindow.py @@ -38,6 +38,7 @@ from openlp.core.lib import Renderer, build_icon, OpenLPDockWidget, \ PluginManager, Receiver, translate, ImageManager, PluginStatus from openlp.core.lib.ui import UiStrings, base_action, checkable_action, \ icon_action, shortcut_action +from openlp.core.lib import SlideLimits from openlp.core.ui import AboutForm, SettingsForm, ServiceManager, \ ThemeManager, SlideController, PluginForm, MediaDockManager, \ ShortcutListForm, FormattingTagForm @@ -1306,6 +1307,19 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): Load the main window settings. """ log.debug(u'Loading QSettings') + # Migrate Wrap Settings to Slide Limits Settings + if QtCore.QSettings().contains(self.generalSettingsSection + + u'/enable slide loop'): + if QtCore.QSettings().value(self.generalSettingsSection + + u'/enable slide loop', QtCore.QVariant(True)).toBool(): + QtCore.QSettings().setValue(self.advancedlSettingsSection + + u'/slide limits', QtCore.QVariant(SlideLimits.Wrap)) + else: + QtCore.QSettings().setValue(self.advancedlSettingsSection + + u'/slide limits', QtCore.QVariant(SlideLimits.End)) + QtCore.QSettings().remove(self.generalSettingsSection + + u'/enable slide loop') + Receiver.send_message(u'slidecontroller_update_slide_limits') settings = QtCore.QSettings() # Remove obsolete entries. settings.remove(u'custom slide') diff --git a/openlp/core/ui/servicemanager.py b/openlp/core/ui/servicemanager.py index e23e68ef5..f2c4a7702 100644 --- a/openlp/core/ui/servicemanager.py +++ b/openlp/core/ui/servicemanager.py @@ -826,7 +826,7 @@ class ServiceManager(QtGui.QWidget): lookFor = 1 serviceIterator += 1 - def previousItem(self): + def previousItem(self, message): """ Called by the SlideController to select the previous service item. """ @@ -834,15 +834,26 @@ class ServiceManager(QtGui.QWidget): return selected = self.serviceManagerList.selectedItems()[0] prevItem = None + prevItemLastSlide = None serviceIterator = QtGui.QTreeWidgetItemIterator(self.serviceManagerList) while serviceIterator.value(): if serviceIterator.value() == selected: - if prevItem: + if message == u'last slide' and prevItemLastSlide: + pos = prevItem.data(0, QtCore.Qt.UserRole).toInt()[0] + check_expanded = self.serviceItems[pos - 1][u'expanded'] + self.serviceManagerList.setCurrentItem(prevItemLastSlide) + if not check_expanded: + self.serviceManagerList.collapseItem(prevItem) + self.makeLive() + self.serviceManagerList.setCurrentItem(prevItem) + elif prevItem: self.serviceManagerList.setCurrentItem(prevItem) self.makeLive() return if serviceIterator.value().parent() is None: prevItem = serviceIterator.value() + if serviceIterator.value().parent() is prevItem: + prevItemLastSlide = serviceIterator.value() serviceIterator += 1 def onSetItem(self, message): diff --git a/openlp/core/ui/slidecontroller.py b/openlp/core/ui/slidecontroller.py index e3329558f..f0fc363b7 100644 --- a/openlp/core/ui/slidecontroller.py +++ b/openlp/core/ui/slidecontroller.py @@ -35,6 +35,7 @@ from PyQt4 import QtCore, QtGui from openlp.core.lib import OpenLPToolbar, Receiver, ItemCapabilities, \ translate, build_icon, ServiceItem, build_html, PluginManager, ServiceItem from openlp.core.lib.ui import UiStrings, shortcut_action +from openlp.core.lib import SlideLimits, ServiceItemAction from openlp.core.ui import HideMode, MainDisplay, Display, ScreenList from openlp.core.utils.actions import ActionList, CategoryOrder @@ -105,6 +106,8 @@ class SlideController(Controller): self.songEdit = False self.selectedRow = 0 self.serviceItem = None + self.slide_limits = None + self.updateSlideLimits() self.panel = QtGui.QWidget(parent.controlSplitter) self.slideList = {} # Layout for holding panel @@ -453,6 +456,9 @@ class SlideController(Controller): QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'slidecontroller_%s_unblank' % self.typePrefix), self.onSlideUnblank) + QtCore.QObject.connect(Receiver.get_receiver(), + QtCore.SIGNAL(u'slidecontroller_update_slide_limits'), + self.updateSlideLimits) def slideShortcutActivated(self): """ @@ -595,14 +601,14 @@ class SlideController(Controller): """ Live event to select the previous service item from the service manager. """ - self.keypress_queue.append(u'previous') + self.keypress_queue.append(ServiceItemAction.Previous) self._process_queue() def serviceNext(self): """ Live event to select the next service item from the service manager. """ - self.keypress_queue.append(u'next') + self.keypress_queue.append(ServiceItemAction.Next) self._process_queue() def _process_queue(self): @@ -613,8 +619,12 @@ class SlideController(Controller): if len(self.keypress_queue): while len(self.keypress_queue) and not self.keypress_loop: self.keypress_loop = True - if self.keypress_queue.popleft() == u'previous': - Receiver.send_message('servicemanager_previous_item') + keypressCommand = self.keypress_queue.popleft() + if keypressCommand == ServiceItemAction.Previous: + Receiver.send_message('servicemanager_previous_item', None) + elif keypressCommand == ServiceItemAction.PreviousLastSlide: + # Go to the last slide of the previous item + Receiver.send_message('servicemanager_previous_item', u'last slide') else: Receiver.send_message('servicemanager_next_item') self.keypress_loop = False @@ -705,6 +715,14 @@ class SlideController(Controller): Adjusts the value of the ``delaySpinBox`` to the given one. """ self.delaySpinBox.setValue(int(value)) + + def updateSlideLimits(self): + """ + Updates the Slide Limits variable from the settings. + """ + self.slide_limits = QtCore.QSettings().value( + self.parent().advancedlSettingsSection + u'/slide limits', + QtCore.QVariant(SlideLimits.End)).toInt()[0] def enableToolBar(self, item): """ @@ -1183,10 +1201,14 @@ class SlideController(Controller): row = self.previewListWidget.currentRow() + 1 if row == self.previewListWidget.rowCount(): if wrap is None: - wrap = QtCore.QSettings().value( - self.parent().generalSettingsSection + - u'/enable slide loop', QtCore.QVariant(True)).toBool() - if wrap: + if self.slide_limits == SlideLimits.Wrap: + row = 0 + elif self.slide_limits == SlideLimits.Next: + self.serviceNext() + return + else: + row = self.previewListWidget.rowCount() - 1 + elif wrap: row = 0 else: row = self.previewListWidget.rowCount() - 1 @@ -1206,9 +1228,12 @@ class SlideController(Controller): else: row = self.previewListWidget.currentRow() - 1 if row == -1: - if QtCore.QSettings().value(self.parent().generalSettingsSection - + u'/enable slide loop', QtCore.QVariant(True)).toBool(): + if self.slide_limits == SlideLimits.Wrap: row = self.previewListWidget.rowCount() - 1 + elif self.slide_limits == SlideLimits.Next: + self.keypress_queue.append(ServiceItemAction.PreviousLastSlide) + self._process_queue() + return else: row = 0 self.__checkUpdateSelectedSlide(row)