openlp-core team mailing list archive
-
openlp-core team
-
Mailing list archive
-
Message #29351
[Merge] lp:~trb143/openlp/refactor26 into lp:openlp
Tim Bentley has proposed merging lp:~trb143/openlp/refactor26 into lp:openlp.
Requested reviews:
OpenLP Core (openlp-core)
For more details, see:
https://code.launchpad.net/~trb143/openlp/refactor26/+merge/292680
Fine refactor merge
lp:~trb143/openlp/refactor26 (revision 2684)
[SUCCESS] https://ci.openlp.io/job/Branch-01-Pull/1480/
[SUCCESS] https://ci.openlp.io/job/Branch-02-Functional-Tests/1391/
[SUCCESS] https://ci.openlp.io/job/Branch-03-Interface-Tests/1329/
[SUCCESS] https://ci.openlp.io/job/Branch-04a-Windows_Functional_Tests/1129/
[SUCCESS] https://ci.openlp.io/job/Branch-04b-Windows_Interface_Tests/720/
[SUCCESS] https://ci.openlp.io/job/Branch-05a-Code_Analysis/787/
[SUCCESS] https://ci.openlp.io/job/Branch-05b-Test_Coverage/655/
--
Your team OpenLP Core is requested to review the proposed merge of lp:~trb143/openlp/refactor26 into lp:openlp.
=== modified file 'openlp/core/lib/__init__.py'
--- openlp/core/lib/__init__.py 2015-12-31 22:46:06 +0000
+++ openlp/core/lib/__init__.py 2016-04-22 19:42:45 +0000
@@ -312,12 +312,9 @@
return translate('OpenLP.core.lib', '%s, %s', 'Locale list separator: start') % (string_list[0], merged)
-from .colorbutton import ColorButton
from .exceptions import ValidationError
from .filedialog import FileDialog
from .screen import ScreenList
-from .listwidgetwithdnd import ListWidgetWithDnD
-from .treewidgetwithdnd import TreeWidgetWithDnD
from .formattingtags import FormattingTags
from .spelltextedit import SpellTextEdit
from .plugin import PluginStatus, StringContent, Plugin
@@ -325,8 +322,6 @@
from .settingstab import SettingsTab
from .serviceitem import ServiceItem, ServiceItemType, ItemCapabilities
from .htmlbuilder import build_html, build_lyrics_format_css, build_lyrics_outline_css
-from .toolbar import OpenLPToolbar
-from .dockwidget import OpenLPDockWidget
from .imagemanager import ImageManager
from .renderer import Renderer
from .mediamanageritem import MediaManagerItem
=== removed file 'openlp/core/lib/colorbutton.py'
--- openlp/core/lib/colorbutton.py 2015-12-31 22:46:06 +0000
+++ openlp/core/lib/colorbutton.py 1970-01-01 00:00:00 +0000
@@ -1,82 +0,0 @@
-# -*- coding: utf-8 -*-
-# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
-
-###############################################################################
-# OpenLP - Open Source Lyrics Projection #
-# --------------------------------------------------------------------------- #
-# Copyright (c) 2008-2016 OpenLP Developers #
-# --------------------------------------------------------------------------- #
-# This program is free software; you can redistribute it and/or modify it #
-# under the terms of the GNU General Public License as published by the Free #
-# Software Foundation; version 2 of the License. #
-# #
-# This program is distributed in the hope that it will be useful, but WITHOUT #
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
-# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
-# more details. #
-# #
-# You should have received a copy of the GNU General Public License along #
-# with this program; if not, write to the Free Software Foundation, Inc., 59 #
-# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
-###############################################################################
-
-"""
-Provide a custom widget based on QPushButton for the selection of colors
-"""
-from PyQt5 import QtCore, QtGui, QtWidgets
-
-from openlp.core.common import translate
-
-
-class ColorButton(QtWidgets.QPushButton):
- """
- Subclasses QPushbutton to create a "Color Chooser" button
- """
-
- colorChanged = QtCore.pyqtSignal(str)
-
- def __init__(self, parent=None):
- """
- Initialise the ColorButton
- """
- super(ColorButton, self).__init__()
- self.parent = parent
- self.change_color('#ffffff')
- self.setToolTip(translate('OpenLP.ColorButton', 'Click to select a color.'))
- self.clicked.connect(self.on_clicked)
-
- def change_color(self, color):
- """
- Sets the _color variable and the background color.
-
- :param color: String representation of a hexidecimal color
- """
- self._color = color
- self.setStyleSheet('background-color: %s' % color)
-
- @property
- def color(self):
- """
- Property method to return the color variable
-
- :return: String representation of a hexidecimal color
- """
- return self._color
-
- @color.setter
- def color(self, color):
- """
- Property setter to change the instance color
-
- :param color: String representation of a hexidecimal color
- """
- self.change_color(color)
-
- def on_clicked(self):
- """
- Handle the PushButton clicked signal, showing the ColorDialog and validating the input
- """
- new_color = QtWidgets.QColorDialog.getColor(QtGui.QColor(self._color), self.parent)
- if new_color.isValid() and self._color != new_color.name():
- self.change_color(new_color.name())
- self.colorChanged.emit(new_color.name())
=== removed file 'openlp/core/lib/dockwidget.py'
--- openlp/core/lib/dockwidget.py 2015-12-31 22:46:06 +0000
+++ openlp/core/lib/dockwidget.py 1970-01-01 00:00:00 +0000
@@ -1,56 +0,0 @@
-# -*- coding: utf-8 -*-
-# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
-
-###############################################################################
-# OpenLP - Open Source Lyrics Projection #
-# --------------------------------------------------------------------------- #
-# Copyright (c) 2008-2016 OpenLP Developers #
-# --------------------------------------------------------------------------- #
-# This program is free software; you can redistribute it and/or modify it #
-# under the terms of the GNU General Public License as published by the Free #
-# Software Foundation; version 2 of the License. #
-# #
-# This program is distributed in the hope that it will be useful, but WITHOUT #
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
-# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
-# more details. #
-# #
-# You should have received a copy of the GNU General Public License along #
-# with this program; if not, write to the Free Software Foundation, Inc., 59 #
-# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
-###############################################################################
-
-"""
-Provide additional functionality required by OpenLP from the inherited QDockWidget.
-"""
-
-import logging
-
-from PyQt5 import QtWidgets
-
-from openlp.core.lib import ScreenList, build_icon
-
-log = logging.getLogger(__name__)
-
-
-class OpenLPDockWidget(QtWidgets.QDockWidget):
- """
- Custom DockWidget class to handle events
- """
- def __init__(self, parent=None, name=None, icon=None):
- """
- Initialise the DockWidget
- """
- log.debug('Initialise the %s widget' % name)
- super(OpenLPDockWidget, self).__init__(parent)
- if name:
- self.setObjectName(name)
- if icon:
- self.setWindowIcon(build_icon(icon))
- # Sort out the minimum width.
- screens = ScreenList()
- main_window_docbars = screens.current['size'].width() // 5
- if main_window_docbars > 300:
- self.setMinimumWidth(300)
- else:
- self.setMinimumWidth(main_window_docbars)
=== removed file 'openlp/core/lib/listwidgetwithdnd.py'
--- openlp/core/lib/listwidgetwithdnd.py 2015-12-31 22:46:06 +0000
+++ openlp/core/lib/listwidgetwithdnd.py 1970-01-01 00:00:00 +0000
@@ -1,107 +0,0 @@
-# -*- coding: utf-8 -*-
-# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
-
-###############################################################################
-# OpenLP - Open Source Lyrics Projection #
-# --------------------------------------------------------------------------- #
-# Copyright (c) 2008-2016 OpenLP Developers #
-# --------------------------------------------------------------------------- #
-# This program is free software; you can redistribute it and/or modify it #
-# under the terms of the GNU General Public License as published by the Free #
-# Software Foundation; version 2 of the License. #
-# #
-# This program is distributed in the hope that it will be useful, but WITHOUT #
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
-# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
-# more details. #
-# #
-# You should have received a copy of the GNU General Public License along #
-# with this program; if not, write to the Free Software Foundation, Inc., 59 #
-# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
-###############################################################################
-"""
-Extend QListWidget to handle drag and drop functionality
-"""
-import os
-
-from PyQt5 import QtCore, QtGui, QtWidgets
-
-from openlp.core.common import Registry
-
-
-class ListWidgetWithDnD(QtWidgets.QListWidget):
- """
- Provide a list widget to store objects and handle drag and drop events
- """
- def __init__(self, parent=None, name=''):
- """
- Initialise the list widget
- """
- super(ListWidgetWithDnD, self).__init__(parent)
- self.mime_data_text = name
-
- def activateDnD(self):
- """
- Activate DnD of widget
- """
- self.setAcceptDrops(True)
- self.setDragDropMode(QtWidgets.QAbstractItemView.DragDrop)
- Registry().register_function(('%s_dnd' % self.mime_data_text), self.parent().load_file)
-
- def mouseMoveEvent(self, event):
- """
- Drag and drop event does not care what data is selected as the recipient will use events to request the data
- move just tell it what plugin to call
- """
- if event.buttons() != QtCore.Qt.LeftButton:
- event.ignore()
- return
- if not self.selectedItems():
- event.ignore()
- return
- drag = QtGui.QDrag(self)
- mime_data = QtCore.QMimeData()
- drag.setMimeData(mime_data)
- mime_data.setText(self.mime_data_text)
- drag.exec(QtCore.Qt.CopyAction)
-
- def dragEnterEvent(self, event):
- """
- When something is dragged into this object, check if you should be able to drop it in here.
- """
- if event.mimeData().hasUrls():
- event.accept()
- else:
- event.ignore()
-
- def dragMoveEvent(self, event):
- """
- Make an object droppable, and set it to copy the contents of the object, not move it.
- """
- if event.mimeData().hasUrls():
- event.setDropAction(QtCore.Qt.CopyAction)
- event.accept()
- else:
- event.ignore()
-
- def dropEvent(self, event):
- """
- Receive drop event check if it is a file and process it if it is.
-
- :param event: Handle of the event pint passed
- """
- if event.mimeData().hasUrls():
- event.setDropAction(QtCore.Qt.CopyAction)
- event.accept()
- files = []
- for url in event.mimeData().urls():
- local_file = os.path.normpath(url.toLocalFile())
- if os.path.isfile(local_file):
- files.append(local_file)
- elif os.path.isdir(local_file):
- listing = os.listdir(local_file)
- for file in listing:
- files.append(os.path.join(local_file, file))
- Registry().execute('%s_dnd' % self.mime_data_text, {'files': files, 'target': self.itemAt(event.pos())})
- else:
- event.ignore()
=== modified file 'openlp/core/lib/mediamanageritem.py'
--- openlp/core/lib/mediamanageritem.py 2016-04-03 19:12:37 +0000
+++ openlp/core/lib/mediamanageritem.py 2016-04-22 19:42:45 +0000
@@ -29,10 +29,11 @@
from PyQt5 import QtCore, QtGui, QtWidgets
from openlp.core.common import Registry, RegistryProperties, Settings, UiStrings, translate
-from openlp.core.lib import FileDialog, OpenLPToolbar, ServiceItem, StringContent, ListWidgetWithDnD, \
- ServiceItemContext
+from openlp.core.lib import FileDialog, ServiceItem, StringContent, ServiceItemContext
from openlp.core.lib.searchedit import SearchEdit
from openlp.core.lib.ui import create_widget_action, critical_error_message_box
+from openlp.core.ui.lib.listwidgetwithdnd import ListWidgetWithDnD
+from openlp.core.ui.lib.toolbar import OpenLPToolbar
log = logging.getLogger(__name__)
=== removed file 'openlp/core/lib/toolbar.py'
--- openlp/core/lib/toolbar.py 2015-12-31 22:46:06 +0000
+++ openlp/core/lib/toolbar.py 1970-01-01 00:00:00 +0000
@@ -1,90 +0,0 @@
-# -*- coding: utf-8 -*-
-# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
-
-###############################################################################
-# OpenLP - Open Source Lyrics Projection #
-# --------------------------------------------------------------------------- #
-# Copyright (c) 2008-2016 OpenLP Developers #
-# --------------------------------------------------------------------------- #
-# This program is free software; you can redistribute it and/or modify it #
-# under the terms of the GNU General Public License as published by the Free #
-# Software Foundation; version 2 of the License. #
-# #
-# This program is distributed in the hope that it will be useful, but WITHOUT #
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
-# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
-# more details. #
-# #
-# You should have received a copy of the GNU General Public License along #
-# with this program; if not, write to the Free Software Foundation, Inc., 59 #
-# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
-###############################################################################
-"""
-Provide common toolbar handling for OpenLP
-"""
-import logging
-
-from PyQt5 import QtCore, QtWidgets
-
-from openlp.core.lib.ui import create_widget_action
-
-log = logging.getLogger(__name__)
-
-
-class OpenLPToolbar(QtWidgets.QToolBar):
- """
- Lots of toolbars around the place, so it makes sense to have a common way to manage them. This is the base toolbar
- class.
- """
- def __init__(self, parent):
- """
- Initialise the toolbar.
- """
- super(OpenLPToolbar, self).__init__(parent)
- # useful to be able to reuse button icons...
- self.setIconSize(QtCore.QSize(20, 20))
- self.actions = {}
- log.debug('Init done for %s' % parent.__class__.__name__)
-
- def add_toolbar_action(self, name, **kwargs):
- """
- A method to help developers easily add a button to the toolbar. A new QAction is created by calling
- ``create_action()``. The action is added to the toolbar and the toolbar is set as parent. For more details
- please look at openlp.core.lib.ui.create_action()
- """
- action = create_widget_action(self, name, **kwargs)
- self.actions[name] = action
- return action
-
- def add_toolbar_widget(self, widget):
- """
- Add a widget and store it's handle under the widgets object name.
- """
- action = self.addWidget(widget)
- self.actions[widget.objectName()] = action
-
- def set_widget_visible(self, widgets, visible=True):
- """
- Set the visibility for a widget or a list of widgets.
-
- :param widgets: A list of string with widget object names.
- :param visible: The new state as bool.
- """
- for handle in widgets:
- if handle in self.actions:
- self.actions[handle].setVisible(visible)
- else:
- log.warning('No handle "%s" in actions list.', str(handle))
-
- def set_widget_enabled(self, widgets, enabled=True):
- """
- Set the enabled state for a widget or a list of widgets.
-
- :param widgets: A list of string with widget object names.
- :param enabled: The new state as bool.
- """
- for handle in widgets:
- if handle in self.actions:
- self.actions[handle].setEnabled(enabled)
- else:
- log.warning('No handle "%s" in actions list.', str(handle))
=== removed file 'openlp/core/lib/treewidgetwithdnd.py'
--- openlp/core/lib/treewidgetwithdnd.py 2015-12-31 22:46:06 +0000
+++ openlp/core/lib/treewidgetwithdnd.py 1970-01-01 00:00:00 +0000
@@ -1,139 +0,0 @@
-# -*- coding: utf-8 -*-
-# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
-
-###############################################################################
-# OpenLP - Open Source Lyrics Projection #
-# --------------------------------------------------------------------------- #
-# Copyright (c) 2008-2016 OpenLP Developers #
-# --------------------------------------------------------------------------- #
-# This program is free software; you can redistribute it and/or modify it #
-# under the terms of the GNU General Public License as published by the Free #
-# Software Foundation; version 2 of the License. #
-# #
-# This program is distributed in the hope that it will be useful, but WITHOUT #
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
-# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
-# more details. #
-# #
-# You should have received a copy of the GNU General Public License along #
-# with this program; if not, write to the Free Software Foundation, Inc., 59 #
-# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
-###############################################################################
-"""
-Extend QTreeWidget to handle drag and drop functionality
-"""
-import os
-
-from PyQt5 import QtCore, QtGui, QtWidgets
-
-from openlp.core.common import Registry
-
-
-class TreeWidgetWithDnD(QtWidgets.QTreeWidget):
- """
- Provide a tree widget to store objects and handle drag and drop events
- """
- def __init__(self, parent=None, name=''):
- """
- Initialise the tree widget
- """
- super(TreeWidgetWithDnD, self).__init__(parent)
- self.mime_data_text = name
- self.allow_internal_dnd = False
- self.header().close()
- self.default_indentation = self.indentation()
- self.setIndentation(0)
- self.setAnimated(True)
-
- def activateDnD(self):
- """
- Activate DnD of widget
- """
- self.setAcceptDrops(True)
- self.setDragDropMode(QtWidgets.QAbstractItemView.DragDrop)
- Registry().register_function(('%s_dnd' % self.mime_data_text), self.parent().load_file)
- Registry().register_function(('%s_dnd_internal' % self.mime_data_text), self.parent().dnd_move_internal)
-
- def mouseMoveEvent(self, event):
- """
- Drag and drop event does not care what data is selected as the recipient will use events to request the data
- move just tell it what plugin to call
-
- :param event: The event that occurred
- """
- if event.buttons() != QtCore.Qt.LeftButton:
- event.ignore()
- return
- if not self.selectedItems():
- event.ignore()
- return
- drag = QtGui.QDrag(self)
- mime_data = QtCore.QMimeData()
- drag.setMimeData(mime_data)
- mime_data.setText(self.mime_data_text)
- drag.exec(QtCore.Qt.CopyAction)
-
- def dragEnterEvent(self, event):
- """
- Receive drag enter event, check if it is a file or internal object and allow it if it is.
-
- :param event: The event that occurred
- """
- if event.mimeData().hasUrls():
- event.accept()
- elif self.allow_internal_dnd:
- event.accept()
- else:
- event.ignore()
-
- def dragMoveEvent(self, event):
- """
- Receive drag move event, check if it is a file or internal object and allow it if it is.
-
- :param event: The event that occurred
- """
- QtWidgets.QTreeWidget.dragMoveEvent(self, event)
- if event.mimeData().hasUrls():
- event.setDropAction(QtCore.Qt.CopyAction)
- event.accept()
- elif self.allow_internal_dnd:
- event.setDropAction(QtCore.Qt.CopyAction)
- event.accept()
- else:
- event.ignore()
-
- def dropEvent(self, event):
- """
- Receive drop event, check if it is a file or internal object and process it if it is.
-
- :param event: Handle of the event pint passed
- """
- if event.mimeData().hasUrls():
- event.setDropAction(QtCore.Qt.CopyAction)
- event.accept()
- files = []
- for url in event.mimeData().urls():
- local_file = url.toLocalFile()
- if os.path.isfile(local_file):
- files.append(local_file)
- elif os.path.isdir(local_file):
- listing = os.listdir(local_file)
- for file_name in listing:
- files.append(os.path.join(local_file, file_name))
- Registry().execute('%s_dnd' % self.mime_data_text, {'files': files, 'target': self.itemAt(event.pos())})
- elif self.allow_internal_dnd:
- event.setDropAction(QtCore.Qt.CopyAction)
- event.accept()
- Registry().execute('%s_dnd_internal' % self.mime_data_text, self.itemAt(event.pos()))
- else:
- event.ignore()
-
- # Convenience methods for emulating a QListWidget. This helps keeping MediaManagerItem simple.
- def addItem(self, item):
- self.addTopLevelItem(item)
-
- def count(self):
- return self.topLevelItemCount()
-
- def item(self, index):
- return self.topLevelItem(index)
=== modified file 'openlp/core/ui/__init__.py'
--- openlp/core/ui/__init__.py 2016-02-16 21:14:38 +0000
+++ openlp/core/ui/__init__.py 2016-04-22 19:42:45 +0000
@@ -113,7 +113,6 @@
from .formattingtagform import FormattingTagForm
from .formattingtagcontroller import FormattingTagController
from .shortcutlistform import ShortcutListForm
-from .mediadockmanager import MediaDockManager
from .servicemanager import ServiceManager
from .thememanager import ThemeManager
from .projector.manager import ProjectorManager
@@ -121,7 +120,7 @@
from .projector.editform import ProjectorEditForm
__all__ = ['SplashScreen', 'AboutForm', 'SettingsForm', 'MainDisplay', 'SlideController', 'ServiceManager', 'ThemeForm',
- 'ThemeManager', 'MediaDockManager', 'ServiceItemEditForm', 'FirstTimeForm', 'FirstTimeLanguageForm',
+ 'ThemeManager', 'ServiceItemEditForm', 'FirstTimeForm', 'FirstTimeLanguageForm',
'Display', 'ServiceNoteForm', 'ThemeLayoutForm', 'FileRenameForm', 'StartTimeForm', 'MainDisplay',
'SlideController', 'DisplayController', 'GeneralTab', 'ThemesTab', 'AdvancedTab', 'PluginForm',
'FormattingTagForm', 'ShortcutListForm', 'FormattingTagController', 'SingleColumnTableWidget',
=== modified file 'openlp/core/ui/generaltab.py'
--- openlp/core/ui/generaltab.py 2016-04-13 15:50:04 +0000
+++ openlp/core/ui/generaltab.py 2016-04-22 19:42:45 +0000
@@ -27,7 +27,8 @@
from PyQt5 import QtCore, QtGui, QtWidgets
from openlp.core.common import Registry, Settings, UiStrings, translate, get_images_filter
-from openlp.core.lib import SettingsTab, ScreenList, ColorButton, build_icon
+from openlp.core.lib import SettingsTab, ScreenList, build_icon
+from openlp.core.ui.lib.colorbutton import ColorButton
log = logging.getLogger(__name__)
=== modified file 'openlp/core/ui/lib/__init__.py'
--- openlp/core/ui/lib/__init__.py 2016-04-01 17:09:47 +0000
+++ openlp/core/ui/lib/__init__.py 2016-04-22 19:42:45 +0000
@@ -19,3 +19,15 @@
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
+
+from .colorbutton import ColorButton
+from .listwidgetwithdnd import ListWidgetWithDnD
+from .treewidgetwithdnd import TreeWidgetWithDnD
+from .toolbar import OpenLPToolbar
+from .dockwidget import OpenLPDockWidget
+from .wizard import OpenLPWizard, WizardStrings
+from .mediadockmanager import MediaDockManager
+from .listpreviewwidget import ListPreviewWidget
+
+__all__ = ['ColorButton', 'ListPreviewWidget', 'ListWidgetWithDnD', 'OpenLPToolbar', 'OpenLPDockWidget',
+ 'OpenLPWizard', 'WizardStrings', 'MediaDockManager', 'ListPreviewWidget']
=== added file 'openlp/core/ui/lib/colorbutton.py'
--- openlp/core/ui/lib/colorbutton.py 1970-01-01 00:00:00 +0000
+++ openlp/core/ui/lib/colorbutton.py 2016-04-22 19:42:45 +0000
@@ -0,0 +1,82 @@
+# -*- coding: utf-8 -*-
+# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
+
+###############################################################################
+# OpenLP - Open Source Lyrics Projection #
+# --------------------------------------------------------------------------- #
+# Copyright (c) 2008-2016 OpenLP Developers #
+# --------------------------------------------------------------------------- #
+# This program is free software; you can redistribute it and/or modify it #
+# under the terms of the GNU General Public License as published by the Free #
+# Software Foundation; version 2 of the License. #
+# #
+# This program is distributed in the hope that it will be useful, but WITHOUT #
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
+# more details. #
+# #
+# You should have received a copy of the GNU General Public License along #
+# with this program; if not, write to the Free Software Foundation, Inc., 59 #
+# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
+###############################################################################
+
+"""
+Provide a custom widget based on QPushButton for the selection of colors
+"""
+from PyQt5 import QtCore, QtGui, QtWidgets
+
+from openlp.core.common import translate
+
+
+class ColorButton(QtWidgets.QPushButton):
+ """
+ Subclasses QPushbutton to create a "Color Chooser" button
+ """
+
+ colorChanged = QtCore.pyqtSignal(str)
+
+ def __init__(self, parent=None):
+ """
+ Initialise the ColorButton
+ """
+ super(ColorButton, self).__init__()
+ self.parent = parent
+ self.change_color('#ffffff')
+ self.setToolTip(translate('OpenLP.ColorButton', 'Click to select a color.'))
+ self.clicked.connect(self.on_clicked)
+
+ def change_color(self, color):
+ """
+ Sets the _color variable and the background color.
+
+ :param color: String representation of a hexidecimal color
+ """
+ self._color = color
+ self.setStyleSheet('background-color: %s' % color)
+
+ @property
+ def color(self):
+ """
+ Property method to return the color variable
+
+ :return: String representation of a hexidecimal color
+ """
+ return self._color
+
+ @color.setter
+ def color(self, color):
+ """
+ Property setter to change the instance color
+
+ :param color: String representation of a hexidecimal color
+ """
+ self.change_color(color)
+
+ def on_clicked(self):
+ """
+ Handle the PushButton clicked signal, showing the ColorDialog and validating the input
+ """
+ new_color = QtWidgets.QColorDialog.getColor(QtGui.QColor(self._color), self.parent)
+ if new_color.isValid() and self._color != new_color.name():
+ self.change_color(new_color.name())
+ self.colorChanged.emit(new_color.name())
=== added file 'openlp/core/ui/lib/dockwidget.py'
--- openlp/core/ui/lib/dockwidget.py 1970-01-01 00:00:00 +0000
+++ openlp/core/ui/lib/dockwidget.py 2016-04-22 19:42:45 +0000
@@ -0,0 +1,56 @@
+# -*- coding: utf-8 -*-
+# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
+
+###############################################################################
+# OpenLP - Open Source Lyrics Projection #
+# --------------------------------------------------------------------------- #
+# Copyright (c) 2008-2016 OpenLP Developers #
+# --------------------------------------------------------------------------- #
+# This program is free software; you can redistribute it and/or modify it #
+# under the terms of the GNU General Public License as published by the Free #
+# Software Foundation; version 2 of the License. #
+# #
+# This program is distributed in the hope that it will be useful, but WITHOUT #
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
+# more details. #
+# #
+# You should have received a copy of the GNU General Public License along #
+# with this program; if not, write to the Free Software Foundation, Inc., 59 #
+# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
+###############################################################################
+
+"""
+Provide additional functionality required by OpenLP from the inherited QDockWidget.
+"""
+
+import logging
+
+from PyQt5 import QtWidgets
+
+from openlp.core.lib import ScreenList, build_icon
+
+log = logging.getLogger(__name__)
+
+
+class OpenLPDockWidget(QtWidgets.QDockWidget):
+ """
+ Custom DockWidget class to handle events
+ """
+ def __init__(self, parent=None, name=None, icon=None):
+ """
+ Initialise the DockWidget
+ """
+ log.debug('Initialise the %s widget' % name)
+ super(OpenLPDockWidget, self).__init__(parent)
+ if name:
+ self.setObjectName(name)
+ if icon:
+ self.setWindowIcon(build_icon(icon))
+ # Sort out the minimum width.
+ screens = ScreenList()
+ main_window_docbars = screens.current['size'].width() // 5
+ if main_window_docbars > 300:
+ self.setMinimumWidth(300)
+ else:
+ self.setMinimumWidth(main_window_docbars)
=== added file 'openlp/core/ui/lib/listpreviewwidget.py'
--- openlp/core/ui/lib/listpreviewwidget.py 1970-01-01 00:00:00 +0000
+++ openlp/core/ui/lib/listpreviewwidget.py 2016-04-22 19:42:45 +0000
@@ -0,0 +1,226 @@
+# -*- coding: utf-8 -*-
+# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
+
+###############################################################################
+# OpenLP - Open Source Lyrics Projection #
+# --------------------------------------------------------------------------- #
+# Copyright (c) 2008-2016 OpenLP Developers #
+# --------------------------------------------------------------------------- #
+# This program is free software; you can redistribute it and/or modify it #
+# under the terms of the GNU General Public License as published by the Free #
+# Software Foundation; version 2 of the License. #
+# #
+# This program is distributed in the hope that it will be useful, but WITHOUT #
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
+# more details. #
+# #
+# You should have received a copy of the GNU General Public License along #
+# with this program; if not, write to the Free Software Foundation, Inc., 59 #
+# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
+###############################################################################
+"""
+The :mod:`listpreviewwidget` is a widget that lists the slides in the slide controller.
+It is based on a QTableWidget but represents its contents in list form.
+"""
+
+from PyQt5 import QtCore, QtGui, QtWidgets
+
+from openlp.core.common import RegistryProperties, Settings
+from openlp.core.lib import ImageSource, ServiceItem
+
+
+class ListPreviewWidget(QtWidgets.QTableWidget, RegistryProperties):
+ """
+ A special type of QTableWidget which lists the slides in the slide controller
+
+ :param parent:
+ :param screen_ratio:
+ """
+
+ def __init__(self, parent, screen_ratio):
+ """
+ Initializes the widget to default state.
+
+ An empty ``ServiceItem`` is used by default. replace_service_manager_item() needs to be called to make this
+ widget display something.
+ """
+ super(QtWidgets.QTableWidget, self).__init__(parent)
+ self._setup(screen_ratio)
+
+ def _setup(self, screen_ratio):
+ """
+ Set up the widget
+ """
+ self.setColumnCount(1)
+ self.horizontalHeader().setVisible(False)
+ self.setColumnWidth(0, self.parent().width())
+ self.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
+ self.setSelectionMode(QtWidgets.QAbstractItemView.SingleSelection)
+ self.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers)
+ self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
+ self.setAlternatingRowColors(True)
+ # Initialize variables.
+ self.service_item = ServiceItem()
+ self.screen_ratio = screen_ratio
+ # Connect signals
+ self.verticalHeader().sectionResized.connect(self.row_resized)
+
+ def resizeEvent(self, event):
+ """
+ Overloaded method from QTableWidget. Will recalculate the layout.
+ """
+ self.__recalculate_layout()
+
+ def __recalculate_layout(self):
+ """
+ Recalculates the layout of the table widget. It will set height and width
+ of the table cells. QTableWidget does not adapt the cells to the widget size on its own.
+ """
+ self.setColumnWidth(0, self.viewport().width())
+ if self.service_item:
+ # Sort out songs, bibles, etc.
+ if self.service_item.is_text():
+ self.resizeRowsToContents()
+ # Sort out image heights.
+ else:
+ height = self.viewport().width() // self.screen_ratio
+ max_img_row_height = Settings().value('advanced/slide max height')
+ # Adjust for row height cap if in use.
+ if isinstance(max_img_row_height, int) and max_img_row_height > 0 and height > max_img_row_height:
+ height = max_img_row_height
+ # Apply new height to slides
+ for frame_number in range(len(self.service_item.get_frames())):
+ self.setRowHeight(frame_number, height)
+
+ def row_resized(self, row, old_height, new_height):
+ """
+ Will scale non-image slides.
+ """
+ # Only for non-text slides when row height cap in use
+ max_img_row_height = Settings().value('advanced/slide max height')
+ if self.service_item.is_text() or not isinstance(max_img_row_height, int) or max_img_row_height <= 0:
+ return
+ # Get and validate label widget containing slide & adjust max width
+ try:
+ self.cellWidget(row, 0).children()[1].setMaximumWidth(new_height * self.screen_ratio)
+ except:
+ return
+
+ def screen_size_changed(self, screen_ratio):
+ """
+ This method is called whenever the live screen size changes, which then makes a layout recalculation necessary
+
+ :param screen_ratio: The new screen ratio
+ """
+ self.screen_ratio = screen_ratio
+ self.__recalculate_layout()
+
+ def replace_service_item(self, service_item, width, slide_number):
+ """
+ Replace the current preview items with the ones in service_item and display the given slide
+
+ :param service_item: The service item to insert
+ :param width: The width of the column
+ :param slide_number: The slide number to pre-select
+ """
+ self.service_item = service_item
+ self.setRowCount(0)
+ self.clear()
+ self.setColumnWidth(0, width)
+ row = 0
+ text = []
+ for frame_number, frame in enumerate(self.service_item.get_frames()):
+ self.setRowCount(self.slide_count() + 1)
+ item = QtWidgets.QTableWidgetItem()
+ slide_height = 0
+ if self.service_item.is_text():
+ if frame['verseTag']:
+ # These tags are already translated.
+ verse_def = frame['verseTag']
+ verse_def = '%s%s' % (verse_def[0], verse_def[1:])
+ two_line_def = '%s\n%s' % (verse_def[0], verse_def[1:])
+ row = two_line_def
+ else:
+ row += 1
+ item.setText(frame['text'])
+ else:
+ label = QtWidgets.QLabel()
+ label.setContentsMargins(4, 4, 4, 4)
+ if self.service_item.is_media():
+ label.setAlignment(QtCore.Qt.AlignHCenter | QtCore.Qt.AlignVCenter)
+ else:
+ label.setScaledContents(True)
+ if self.service_item.is_command():
+ pixmap = QtGui.QPixmap(frame['image'])
+ pixmap.setDevicePixelRatio(label.devicePixelRatio())
+ label.setPixmap(pixmap)
+ else:
+ image = self.image_manager.get_image(frame['path'], ImageSource.ImagePlugin)
+ pixmap = QtGui.QPixmap.fromImage(image)
+ pixmap.setDevicePixelRatio(label.devicePixelRatio())
+ label.setPixmap(pixmap)
+ slide_height = width // self.screen_ratio
+ # Setup and validate row height cap if in use.
+ max_img_row_height = Settings().value('advanced/slide max height')
+ if isinstance(max_img_row_height, int) and max_img_row_height > 0:
+ if slide_height > max_img_row_height:
+ slide_height = max_img_row_height
+ label.setMaximumWidth(max_img_row_height * self.screen_ratio)
+ label.resize(max_img_row_height * self.screen_ratio, max_img_row_height)
+ # Build widget with stretch padding
+ container = QtWidgets.QWidget()
+ hbox = QtWidgets.QHBoxLayout()
+ hbox.setContentsMargins(0, 0, 0, 0)
+ hbox.addWidget(label, stretch=1)
+ hbox.addStretch(0)
+ container.setLayout(hbox)
+ # Add to table
+ self.setCellWidget(frame_number, 0, container)
+ else:
+ # Add to table
+ self.setCellWidget(frame_number, 0, label)
+ row += 1
+ text.append(str(row))
+ self.setItem(frame_number, 0, item)
+ if slide_height:
+ self.setRowHeight(frame_number, slide_height)
+ self.setVerticalHeaderLabels(text)
+ if self.service_item.is_text():
+ self.resizeRowsToContents()
+ self.setColumnWidth(0, self.viewport().width())
+ self.change_slide(slide_number)
+
+ def change_slide(self, slide):
+ """
+ Switches to the given row.
+ """
+ # Retrieve setting
+ autoscrolling = Settings().value('advanced/autoscrolling')
+ # Check if auto-scroll disabled (None) and validate value as dict containing 'dist' and 'pos'
+ # 'dist' represents the slide to scroll to relative to the new slide (-1 = previous, 0 = current, 1 = next)
+ # 'pos' represents the vert position of of the slide (0 = in view, 1 = top, 2 = middle, 3 = bottom)
+ if not (isinstance(autoscrolling, dict) and 'dist' in autoscrolling and 'pos' in autoscrolling and
+ isinstance(autoscrolling['dist'], int) and isinstance(autoscrolling['pos'], int)):
+ return
+ # prevent scrolling past list bounds
+ scroll_to_slide = slide + autoscrolling['dist']
+ if scroll_to_slide < 0:
+ scroll_to_slide = 0
+ if scroll_to_slide >= self.slide_count():
+ scroll_to_slide = self.slide_count() - 1
+ # Scroll to item if possible.
+ self.scrollToItem(self.item(scroll_to_slide, 0), autoscrolling['pos'])
+ self.selectRow(slide)
+
+ def current_slide_number(self):
+ """
+ Returns the position of the currently active item. Will return -1 if the widget is empty.
+ """
+ return super(ListPreviewWidget, self).currentRow()
+
+ def slide_count(self):
+ """
+ Returns the number of slides this widget holds.
+ """
+ return super(ListPreviewWidget, self).rowCount()
=== added file 'openlp/core/ui/lib/listwidgetwithdnd.py'
--- openlp/core/ui/lib/listwidgetwithdnd.py 1970-01-01 00:00:00 +0000
+++ openlp/core/ui/lib/listwidgetwithdnd.py 2016-04-22 19:42:45 +0000
@@ -0,0 +1,107 @@
+# -*- coding: utf-8 -*-
+# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
+
+###############################################################################
+# OpenLP - Open Source Lyrics Projection #
+# --------------------------------------------------------------------------- #
+# Copyright (c) 2008-2016 OpenLP Developers #
+# --------------------------------------------------------------------------- #
+# This program is free software; you can redistribute it and/or modify it #
+# under the terms of the GNU General Public License as published by the Free #
+# Software Foundation; version 2 of the License. #
+# #
+# This program is distributed in the hope that it will be useful, but WITHOUT #
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
+# more details. #
+# #
+# You should have received a copy of the GNU General Public License along #
+# with this program; if not, write to the Free Software Foundation, Inc., 59 #
+# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
+###############################################################################
+"""
+Extend QListWidget to handle drag and drop functionality
+"""
+import os
+
+from PyQt5 import QtCore, QtGui, QtWidgets
+
+from openlp.core.common import Registry
+
+
+class ListWidgetWithDnD(QtWidgets.QListWidget):
+ """
+ Provide a list widget to store objects and handle drag and drop events
+ """
+ def __init__(self, parent=None, name=''):
+ """
+ Initialise the list widget
+ """
+ super(ListWidgetWithDnD, self).__init__(parent)
+ self.mime_data_text = name
+
+ def activateDnD(self):
+ """
+ Activate DnD of widget
+ """
+ self.setAcceptDrops(True)
+ self.setDragDropMode(QtWidgets.QAbstractItemView.DragDrop)
+ Registry().register_function(('%s_dnd' % self.mime_data_text), self.parent().load_file)
+
+ def mouseMoveEvent(self, event):
+ """
+ Drag and drop event does not care what data is selected as the recipient will use events to request the data
+ move just tell it what plugin to call
+ """
+ if event.buttons() != QtCore.Qt.LeftButton:
+ event.ignore()
+ return
+ if not self.selectedItems():
+ event.ignore()
+ return
+ drag = QtGui.QDrag(self)
+ mime_data = QtCore.QMimeData()
+ drag.setMimeData(mime_data)
+ mime_data.setText(self.mime_data_text)
+ drag.exec(QtCore.Qt.CopyAction)
+
+ def dragEnterEvent(self, event):
+ """
+ When something is dragged into this object, check if you should be able to drop it in here.
+ """
+ if event.mimeData().hasUrls():
+ event.accept()
+ else:
+ event.ignore()
+
+ def dragMoveEvent(self, event):
+ """
+ Make an object droppable, and set it to copy the contents of the object, not move it.
+ """
+ if event.mimeData().hasUrls():
+ event.setDropAction(QtCore.Qt.CopyAction)
+ event.accept()
+ else:
+ event.ignore()
+
+ def dropEvent(self, event):
+ """
+ Receive drop event check if it is a file and process it if it is.
+
+ :param event: Handle of the event pint passed
+ """
+ if event.mimeData().hasUrls():
+ event.setDropAction(QtCore.Qt.CopyAction)
+ event.accept()
+ files = []
+ for url in event.mimeData().urls():
+ local_file = os.path.normpath(url.toLocalFile())
+ if os.path.isfile(local_file):
+ files.append(local_file)
+ elif os.path.isdir(local_file):
+ listing = os.listdir(local_file)
+ for file in listing:
+ files.append(os.path.join(local_file, file))
+ Registry().execute('%s_dnd' % self.mime_data_text, {'files': files, 'target': self.itemAt(event.pos())})
+ else:
+ event.ignore()
=== added file 'openlp/core/ui/lib/mediadockmanager.py'
--- openlp/core/ui/lib/mediadockmanager.py 1970-01-01 00:00:00 +0000
+++ openlp/core/ui/lib/mediadockmanager.py 2016-04-22 19:42:45 +0000
@@ -0,0 +1,71 @@
+# -*- coding: utf-8 -*-
+# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
+
+###############################################################################
+# OpenLP - Open Source Lyrics Projection #
+# --------------------------------------------------------------------------- #
+# Copyright (c) 2008-2016 OpenLP Developers #
+# --------------------------------------------------------------------------- #
+# This program is free software; you can redistribute it and/or modify it #
+# under the terms of the GNU General Public License as published by the Free #
+# Software Foundation; version 2 of the License. #
+# #
+# This program is distributed in the hope that it will be useful, but WITHOUT #
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
+# more details. #
+# #
+# You should have received a copy of the GNU General Public License along #
+# with this program; if not, write to the Free Software Foundation, Inc., 59 #
+# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
+###############################################################################
+"""
+The media manager dock.
+"""
+import logging
+
+from openlp.core.lib import StringContent
+
+log = logging.getLogger(__name__)
+
+
+class MediaDockManager(object):
+ """
+ Provide a repository for MediaManagerItems
+ """
+ def __init__(self, media_dock):
+ """
+ Initialise the media dock
+ """
+ self.media_dock = media_dock
+
+ def add_item_to_dock(self, media_item):
+ """
+ Add a MediaManagerItem to the dock
+ If the item has been added before, it's silently skipped
+
+ :param media_item: The item to add to the dock
+ """
+ visible_title = media_item.plugin.get_string(StringContent.VisibleName)
+ log.debug('Inserting %s dock' % visible_title['title'])
+ match = False
+ for dock_index in range(self.media_dock.count()):
+ if self.media_dock.widget(dock_index).settings_section == media_item.plugin.name:
+ match = True
+ break
+ if not match:
+ self.media_dock.addItem(media_item, visible_title['title'])
+
+ def remove_dock(self, media_item):
+ """
+ Removes a MediaManagerItem from the dock
+
+ :param media_item: The item to add to the dock
+ """
+ visible_title = media_item.plugin.get_string(StringContent.VisibleName)
+ log.debug('remove %s dock' % visible_title['title'])
+ for dock_index in range(self.media_dock.count()):
+ if self.media_dock.widget(dock_index):
+ if self.media_dock.widget(dock_index).settings_section == media_item.plugin.name:
+ self.media_dock.widget(dock_index).setVisible(False)
+ self.media_dock.removeItem(dock_index)
=== added file 'openlp/core/ui/lib/toolbar.py'
--- openlp/core/ui/lib/toolbar.py 1970-01-01 00:00:00 +0000
+++ openlp/core/ui/lib/toolbar.py 2016-04-22 19:42:45 +0000
@@ -0,0 +1,90 @@
+# -*- coding: utf-8 -*-
+# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
+
+###############################################################################
+# OpenLP - Open Source Lyrics Projection #
+# --------------------------------------------------------------------------- #
+# Copyright (c) 2008-2016 OpenLP Developers #
+# --------------------------------------------------------------------------- #
+# This program is free software; you can redistribute it and/or modify it #
+# under the terms of the GNU General Public License as published by the Free #
+# Software Foundation; version 2 of the License. #
+# #
+# This program is distributed in the hope that it will be useful, but WITHOUT #
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
+# more details. #
+# #
+# You should have received a copy of the GNU General Public License along #
+# with this program; if not, write to the Free Software Foundation, Inc., 59 #
+# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
+###############################################################################
+"""
+Provide common toolbar handling for OpenLP
+"""
+import logging
+
+from PyQt5 import QtCore, QtWidgets
+
+from openlp.core.lib.ui import create_widget_action
+
+log = logging.getLogger(__name__)
+
+
+class OpenLPToolbar(QtWidgets.QToolBar):
+ """
+ Lots of toolbars around the place, so it makes sense to have a common way to manage them. This is the base toolbar
+ class.
+ """
+ def __init__(self, parent):
+ """
+ Initialise the toolbar.
+ """
+ super(OpenLPToolbar, self).__init__(parent)
+ # useful to be able to reuse button icons...
+ self.setIconSize(QtCore.QSize(20, 20))
+ self.actions = {}
+ log.debug('Init done for %s' % parent.__class__.__name__)
+
+ def add_toolbar_action(self, name, **kwargs):
+ """
+ A method to help developers easily add a button to the toolbar. A new QAction is created by calling
+ ``create_action()``. The action is added to the toolbar and the toolbar is set as parent. For more details
+ please look at openlp.core.lib.ui.create_action()
+ """
+ action = create_widget_action(self, name, **kwargs)
+ self.actions[name] = action
+ return action
+
+ def add_toolbar_widget(self, widget):
+ """
+ Add a widget and store it's handle under the widgets object name.
+ """
+ action = self.addWidget(widget)
+ self.actions[widget.objectName()] = action
+
+ def set_widget_visible(self, widgets, visible=True):
+ """
+ Set the visibility for a widget or a list of widgets.
+
+ :param widgets: A list of string with widget object names.
+ :param visible: The new state as bool.
+ """
+ for handle in widgets:
+ if handle in self.actions:
+ self.actions[handle].setVisible(visible)
+ else:
+ log.warning('No handle "%s" in actions list.', str(handle))
+
+ def set_widget_enabled(self, widgets, enabled=True):
+ """
+ Set the enabled state for a widget or a list of widgets.
+
+ :param widgets: A list of string with widget object names.
+ :param enabled: The new state as bool.
+ """
+ for handle in widgets:
+ if handle in self.actions:
+ self.actions[handle].setEnabled(enabled)
+ else:
+ log.warning('No handle "%s" in actions list.', str(handle))
=== added file 'openlp/core/ui/lib/treewidgetwithdnd.py'
--- openlp/core/ui/lib/treewidgetwithdnd.py 1970-01-01 00:00:00 +0000
+++ openlp/core/ui/lib/treewidgetwithdnd.py 2016-04-22 19:42:45 +0000
@@ -0,0 +1,139 @@
+# -*- coding: utf-8 -*-
+# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
+
+###############################################################################
+# OpenLP - Open Source Lyrics Projection #
+# --------------------------------------------------------------------------- #
+# Copyright (c) 2008-2016 OpenLP Developers #
+# --------------------------------------------------------------------------- #
+# This program is free software; you can redistribute it and/or modify it #
+# under the terms of the GNU General Public License as published by the Free #
+# Software Foundation; version 2 of the License. #
+# #
+# This program is distributed in the hope that it will be useful, but WITHOUT #
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
+# more details. #
+# #
+# You should have received a copy of the GNU General Public License along #
+# with this program; if not, write to the Free Software Foundation, Inc., 59 #
+# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
+###############################################################################
+"""
+Extend QTreeWidget to handle drag and drop functionality
+"""
+import os
+
+from PyQt5 import QtCore, QtGui, QtWidgets
+
+from openlp.core.common import Registry
+
+
+class TreeWidgetWithDnD(QtWidgets.QTreeWidget):
+ """
+ Provide a tree widget to store objects and handle drag and drop events
+ """
+ def __init__(self, parent=None, name=''):
+ """
+ Initialise the tree widget
+ """
+ super(TreeWidgetWithDnD, self).__init__(parent)
+ self.mime_data_text = name
+ self.allow_internal_dnd = False
+ self.header().close()
+ self.default_indentation = self.indentation()
+ self.setIndentation(0)
+ self.setAnimated(True)
+
+ def activateDnD(self):
+ """
+ Activate DnD of widget
+ """
+ self.setAcceptDrops(True)
+ self.setDragDropMode(QtWidgets.QAbstractItemView.DragDrop)
+ Registry().register_function(('%s_dnd' % self.mime_data_text), self.parent().load_file)
+ Registry().register_function(('%s_dnd_internal' % self.mime_data_text), self.parent().dnd_move_internal)
+
+ def mouseMoveEvent(self, event):
+ """
+ Drag and drop event does not care what data is selected as the recipient will use events to request the data
+ move just tell it what plugin to call
+
+ :param event: The event that occurred
+ """
+ if event.buttons() != QtCore.Qt.LeftButton:
+ event.ignore()
+ return
+ if not self.selectedItems():
+ event.ignore()
+ return
+ drag = QtGui.QDrag(self)
+ mime_data = QtCore.QMimeData()
+ drag.setMimeData(mime_data)
+ mime_data.setText(self.mime_data_text)
+ drag.exec(QtCore.Qt.CopyAction)
+
+ def dragEnterEvent(self, event):
+ """
+ Receive drag enter event, check if it is a file or internal object and allow it if it is.
+
+ :param event: The event that occurred
+ """
+ if event.mimeData().hasUrls():
+ event.accept()
+ elif self.allow_internal_dnd:
+ event.accept()
+ else:
+ event.ignore()
+
+ def dragMoveEvent(self, event):
+ """
+ Receive drag move event, check if it is a file or internal object and allow it if it is.
+
+ :param event: The event that occurred
+ """
+ QtWidgets.QTreeWidget.dragMoveEvent(self, event)
+ if event.mimeData().hasUrls():
+ event.setDropAction(QtCore.Qt.CopyAction)
+ event.accept()
+ elif self.allow_internal_dnd:
+ event.setDropAction(QtCore.Qt.CopyAction)
+ event.accept()
+ else:
+ event.ignore()
+
+ def dropEvent(self, event):
+ """
+ Receive drop event, check if it is a file or internal object and process it if it is.
+
+ :param event: Handle of the event pint passed
+ """
+ if event.mimeData().hasUrls():
+ event.setDropAction(QtCore.Qt.CopyAction)
+ event.accept()
+ files = []
+ for url in event.mimeData().urls():
+ local_file = url.toLocalFile()
+ if os.path.isfile(local_file):
+ files.append(local_file)
+ elif os.path.isdir(local_file):
+ listing = os.listdir(local_file)
+ for file_name in listing:
+ files.append(os.path.join(local_file, file_name))
+ Registry().execute('%s_dnd' % self.mime_data_text, {'files': files, 'target': self.itemAt(event.pos())})
+ elif self.allow_internal_dnd:
+ event.setDropAction(QtCore.Qt.CopyAction)
+ event.accept()
+ Registry().execute('%s_dnd_internal' % self.mime_data_text, self.itemAt(event.pos()))
+ else:
+ event.ignore()
+
+ # Convenience methods for emulating a QListWidget. This helps keeping MediaManagerItem simple.
+ def addItem(self, item):
+ self.addTopLevelItem(item)
+
+ def count(self):
+ return self.topLevelItemCount()
+
+ def item(self, index):
+ return self.topLevelItem(index)
=== added file 'openlp/core/ui/lib/wizard.py'
--- openlp/core/ui/lib/wizard.py 1970-01-01 00:00:00 +0000
+++ openlp/core/ui/lib/wizard.py 2016-04-22 19:42:45 +0000
@@ -0,0 +1,308 @@
+# -*- coding: utf-8 -*-
+# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
+
+###############################################################################
+# OpenLP - Open Source Lyrics Projection #
+# --------------------------------------------------------------------------- #
+# Copyright (c) 2008-2016 OpenLP Developers #
+# --------------------------------------------------------------------------- #
+# This program is free software; you can redistribute it and/or modify it #
+# under the terms of the GNU General Public License as published by the Free #
+# Software Foundation; version 2 of the License. #
+# #
+# This program is distributed in the hope that it will be useful, but WITHOUT #
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
+# more details. #
+# #
+# You should have received a copy of the GNU General Public License along #
+# with this program; if not, write to the Free Software Foundation, Inc., 59 #
+# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
+###############################################################################
+"""
+The :mod:``wizard`` module provides generic wizard tools for OpenLP.
+"""
+import logging
+import os
+
+from PyQt5 import QtGui, QtWidgets
+
+from openlp.core.common import Registry, RegistryProperties, Settings, UiStrings, translate, is_macosx
+from openlp.core.lib import build_icon
+from openlp.core.lib.ui import add_welcome_page
+
+log = logging.getLogger(__name__)
+
+
+class WizardStrings(object):
+ """
+ Provide standard strings for wizards to use.
+ """
+ # Applications/Formats we import from or export to. These get used in
+ # multiple places but do not need translating unless you find evidence of
+ # the writers translating their own product name.
+ CSV = 'CSV'
+ OS = 'OpenSong'
+ OSIS = 'OSIS'
+ ZEF = 'Zefania'
+ # These strings should need a good reason to be retranslated elsewhere.
+ FinishedImport = translate('OpenLP.Ui', 'Finished import.')
+ FormatLabel = translate('OpenLP.Ui', 'Format:')
+ HeaderStyle = '<span style="font-size:14pt; font-weight:600;">%s</span>'
+ Importing = translate('OpenLP.Ui', 'Importing')
+ ImportingType = translate('OpenLP.Ui', 'Importing "%s"...')
+ ImportSelect = translate('OpenLP.Ui', 'Select Import Source')
+ ImportSelectLong = translate('OpenLP.Ui', 'Select the import format and the location to import from.')
+ OpenTypeFile = translate('OpenLP.Ui', 'Open %s File')
+ OpenTypeFolder = translate('OpenLP.Ui', 'Open %s Folder')
+ PercentSymbolFormat = translate('OpenLP.Ui', '%p%')
+ Ready = translate('OpenLP.Ui', 'Ready.')
+ StartingImport = translate('OpenLP.Ui', 'Starting import...')
+ YouSpecifyFile = translate('OpenLP.Ui', 'You need to specify one %s file to import from.',
+ 'A file type e.g. OpenSong')
+ YouSpecifyFiles = translate('OpenLP.Ui', 'You need to specify at least one %s file to import from.',
+ 'A file type e.g. OpenSong')
+ YouSpecifyFolder = translate('OpenLP.Ui', 'You need to specify one %s folder to import from.',
+ 'A song format e.g. PowerSong')
+
+
+class OpenLPWizard(QtWidgets.QWizard, RegistryProperties):
+ """
+ Generic OpenLP wizard to provide generic functionality and a unified look
+ and feel.
+
+ ``parent``
+ The QWidget-derived parent of the wizard.
+
+ ``plugin``
+ Plugin this wizard is part of. The plugin will be saved in the "plugin" variable.
+ The plugin will also be used as basis for the file dialog methods this class provides.
+
+ ``name``
+ The object name this wizard should have.
+
+ ``image``
+ The image to display on the "welcome" page of the wizard. Should be 163x350.
+
+ ``add_progress_page``
+ Whether to add a progress page with a progressbar at the end of the wizard.
+ """
+ def __init__(self, parent, plugin, name, image, add_progress_page=True):
+ """
+ Constructor
+ """
+ super(OpenLPWizard, self).__init__(parent)
+ self.plugin = plugin
+ self.with_progress_page = add_progress_page
+ self.setObjectName(name)
+ self.open_icon = build_icon(':/general/general_open.png')
+ self.delete_icon = build_icon(':/general/general_delete.png')
+ self.finish_button = self.button(QtWidgets.QWizard.FinishButton)
+ self.cancel_button = self.button(QtWidgets.QWizard.CancelButton)
+ self.setupUi(image)
+ self.register_fields()
+ self.custom_init()
+ self.custom_signals()
+ self.currentIdChanged.connect(self.on_current_id_changed)
+ if self.with_progress_page:
+ self.error_copy_to_button.clicked.connect(self.on_error_copy_to_button_clicked)
+ self.error_save_to_button.clicked.connect(self.on_error_save_to_button_clicked)
+
+ def setupUi(self, image):
+ """
+ Set up the wizard UI.
+ :param image: path to start up image
+ """
+ self.setWindowIcon(build_icon(u':/icon/openlp-logo.svg'))
+ self.setModal(True)
+ self.setOptions(QtWidgets.QWizard.IndependentPages |
+ QtWidgets.QWizard.NoBackButtonOnStartPage | QtWidgets.QWizard.NoBackButtonOnLastPage)
+ if is_macosx():
+ self.setPixmap(QtWidgets.QWizard.BackgroundPixmap, QtGui.QPixmap(':/wizards/openlp-osx-wizard.png'))
+ else:
+ self.setWizardStyle(QtWidgets.QWizard.ModernStyle)
+ add_welcome_page(self, image)
+ self.add_custom_pages()
+ if self.with_progress_page:
+ self.add_progress_page()
+ self.retranslateUi()
+
+ def register_fields(self):
+ """
+ Hook method for wizards to register any fields they need.
+ """
+ pass
+
+ def custom_init(self):
+ """
+ Hook method for custom initialisation
+ """
+ pass
+
+ def custom_signals(self):
+ """
+ Hook method for adding custom signals
+ """
+ pass
+
+ def add_custom_pages(self):
+ """
+ Hook method for wizards to add extra pages
+ """
+ pass
+
+ def add_progress_page(self):
+ """
+ Add the progress page for the wizard. This page informs the user how
+ the wizard is progressing with its task.
+ """
+ self.progress_page = QtWidgets.QWizardPage()
+ self.progress_page.setObjectName('progress_page')
+ self.progress_layout = QtWidgets.QVBoxLayout(self.progress_page)
+ self.progress_layout.setContentsMargins(48, 48, 48, 48)
+ self.progress_layout.setObjectName('progress_layout')
+ self.progress_label = QtWidgets.QLabel(self.progress_page)
+ self.progress_label.setObjectName('progress_label')
+ self.progress_label.setWordWrap(True)
+ self.progress_layout.addWidget(self.progress_label)
+ self.progress_bar = QtWidgets.QProgressBar(self.progress_page)
+ self.progress_bar.setObjectName('progress_bar')
+ self.progress_layout.addWidget(self.progress_bar)
+ # Add a QTextEdit and a copy to file and copy to clipboard button to be
+ # able to provide feedback to the user. Hidden by default.
+ self.error_report_text_edit = QtWidgets.QTextEdit(self.progress_page)
+ self.error_report_text_edit.setObjectName('error_report_text_edit')
+ self.error_report_text_edit.setHidden(True)
+ self.error_report_text_edit.setReadOnly(True)
+ self.progress_layout.addWidget(self.error_report_text_edit)
+ self.error_button_layout = QtWidgets.QHBoxLayout()
+ self.error_button_layout.setObjectName('error_button_layout')
+ spacer = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
+ self.error_button_layout.addItem(spacer)
+ self.error_copy_to_button = QtWidgets.QPushButton(self.progress_page)
+ self.error_copy_to_button.setObjectName('error_copy_to_button')
+ self.error_copy_to_button.setHidden(True)
+ self.error_copy_to_button.setIcon(build_icon(':/system/system_edit_copy.png'))
+ self.error_button_layout.addWidget(self.error_copy_to_button)
+ self.error_save_to_button = QtWidgets.QPushButton(self.progress_page)
+ self.error_save_to_button.setObjectName('error_save_to_button')
+ self.error_save_to_button.setHidden(True)
+ self.error_save_to_button.setIcon(build_icon(':/general/general_save.png'))
+ self.error_button_layout.addWidget(self.error_save_to_button)
+ self.progress_layout.addLayout(self.error_button_layout)
+ self.addPage(self.progress_page)
+
+ def exec(self):
+ """
+ Run the wizard.
+ """
+ self.set_defaults()
+ return QtWidgets.QWizard.exec(self)
+
+ def reject(self):
+ """
+ Stop the wizard on cancel button, close button or ESC key.
+ """
+ log.debug('Wizard cancelled by user.')
+ if self.with_progress_page and self.currentPage() == self.progress_page:
+ Registry().execute('openlp_stop_wizard')
+ self.done(QtWidgets.QDialog.Rejected)
+
+ def on_current_id_changed(self, page_id):
+ """
+ Perform necessary functions depending on which wizard page is active.
+ :param page_id: current page number
+ """
+ if self.with_progress_page and self.page(page_id) == self.progress_page:
+ self.pre_wizard()
+ self.perform_wizard()
+ self.post_wizard()
+ else:
+ self.custom_page_changed(page_id)
+
+ def custom_page_changed(self, page_id):
+ """
+ Called when changing to a page other than the progress page
+ :param page_id: current page number
+ """
+ pass
+
+ def on_error_copy_to_button_clicked(self):
+ """
+ Called when the ``error_copy_to_button`` has been clicked.
+ """
+ pass
+
+ def on_error_save_to_button_clicked(self):
+ """
+ Called when the ``error_save_to_button`` has been clicked.
+ """
+ pass
+
+ def increment_progress_bar(self, status_text, increment=1):
+ """
+ Update the wizard progress page.
+
+ :param status_text: Current status information to display.
+ :param increment: The value to increment the progress bar by.
+ """
+ log.debug('IncrementBar %s', status_text)
+ self.progress_label.setText(status_text)
+ if increment > 0:
+ self.progress_bar.setValue(self.progress_bar.value() + increment)
+ self.application.process_events()
+
+ def pre_wizard(self):
+ """
+ Prepare the UI for the import.
+ """
+ self.finish_button.setVisible(False)
+ self.progress_bar.setMinimum(0)
+ self.progress_bar.setMaximum(1188)
+ self.progress_bar.setValue(0)
+
+ def post_wizard(self):
+ """
+ Clean up the UI after the import has finished.
+ """
+ self.progress_bar.setValue(self.progress_bar.maximum())
+ self.finish_button.setVisible(True)
+ self.cancel_button.setVisible(False)
+ self.application.process_events()
+
+ def get_file_name(self, title, editbox, setting_name, filters=''):
+ """
+ Opens a QFileDialog and saves the filename to the given editbox.
+
+ :param title: The title of the dialog (unicode).
+ :param editbox: An editbox (QLineEdit).
+ :param setting_name: The place where to save the last opened directory.
+ :param filters: The file extension filters. It should contain the file description
+ as well as the file extension. For example::
+
+ 'OpenLP 2 Databases (*.sqlite)'
+ """
+ if filters:
+ filters += ';;'
+ filters += '%s (*)' % UiStrings().AllFiles
+ filename, filter_used = QtWidgets.QFileDialog.getOpenFileName(
+ self, title, os.path.dirname(Settings().value(self.plugin.settings_section + '/' + setting_name)),
+ filters)
+ if filename:
+ editbox.setText(filename)
+ Settings().setValue(self.plugin.settings_section + '/' + setting_name, filename)
+
+ def get_folder(self, title, editbox, setting_name):
+ """
+ Opens a QFileDialog and saves the selected folder to the given editbox.
+
+ :param title: The title of the dialog (unicode).
+ :param editbox: An editbox (QLineEdit).
+ :param setting_name: The place where to save the last opened directory.
+ """
+ folder = QtWidgets.QFileDialog.getExistingDirectory(
+ self, title, Settings().value(self.plugin.settings_section + '/' + setting_name),
+ QtWidgets.QFileDialog.ShowDirsOnly)
+ if folder:
+ editbox.setText(folder)
+ Settings().setValue(self.plugin.settings_section + '/' + setting_name, folder)
=== removed file 'openlp/core/ui/listpreviewwidget.py'
--- openlp/core/ui/listpreviewwidget.py 2016-04-16 16:35:08 +0000
+++ openlp/core/ui/listpreviewwidget.py 1970-01-01 00:00:00 +0000
@@ -1,226 +0,0 @@
-# -*- coding: utf-8 -*-
-# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
-
-###############################################################################
-# OpenLP - Open Source Lyrics Projection #
-# --------------------------------------------------------------------------- #
-# Copyright (c) 2008-2016 OpenLP Developers #
-# --------------------------------------------------------------------------- #
-# This program is free software; you can redistribute it and/or modify it #
-# under the terms of the GNU General Public License as published by the Free #
-# Software Foundation; version 2 of the License. #
-# #
-# This program is distributed in the hope that it will be useful, but WITHOUT #
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
-# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
-# more details. #
-# #
-# You should have received a copy of the GNU General Public License along #
-# with this program; if not, write to the Free Software Foundation, Inc., 59 #
-# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
-###############################################################################
-"""
-The :mod:`listpreviewwidget` is a widget that lists the slides in the slide controller.
-It is based on a QTableWidget but represents its contents in list form.
-"""
-
-from PyQt5 import QtCore, QtGui, QtWidgets
-
-from openlp.core.common import RegistryProperties, Settings
-from openlp.core.lib import ImageSource, ServiceItem
-
-
-class ListPreviewWidget(QtWidgets.QTableWidget, RegistryProperties):
- """
- A special type of QTableWidget which lists the slides in the slide controller
-
- :param parent:
- :param screen_ratio:
- """
-
- def __init__(self, parent, screen_ratio):
- """
- Initializes the widget to default state.
-
- An empty ``ServiceItem`` is used by default. replace_service_manager_item() needs to be called to make this
- widget display something.
- """
- super(QtWidgets.QTableWidget, self).__init__(parent)
- self._setup(screen_ratio)
-
- def _setup(self, screen_ratio):
- """
- Set up the widget
- """
- self.setColumnCount(1)
- self.horizontalHeader().setVisible(False)
- self.setColumnWidth(0, self.parent().width())
- self.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
- self.setSelectionMode(QtWidgets.QAbstractItemView.SingleSelection)
- self.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers)
- self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
- self.setAlternatingRowColors(True)
- # Initialize variables.
- self.service_item = ServiceItem()
- self.screen_ratio = screen_ratio
- # Connect signals
- self.verticalHeader().sectionResized.connect(self.row_resized)
-
- def resizeEvent(self, event):
- """
- Overloaded method from QTableWidget. Will recalculate the layout.
- """
- self.__recalculate_layout()
-
- def __recalculate_layout(self):
- """
- Recalculates the layout of the table widget. It will set height and width
- of the table cells. QTableWidget does not adapt the cells to the widget size on its own.
- """
- self.setColumnWidth(0, self.viewport().width())
- if self.service_item:
- # Sort out songs, bibles, etc.
- if self.service_item.is_text():
- self.resizeRowsToContents()
- # Sort out image heights.
- else:
- height = self.viewport().width() // self.screen_ratio
- max_img_row_height = Settings().value('advanced/slide max height')
- # Adjust for row height cap if in use.
- if isinstance(max_img_row_height, int) and max_img_row_height > 0 and height > max_img_row_height:
- height = max_img_row_height
- # Apply new height to slides
- for frame_number in range(len(self.service_item.get_frames())):
- self.setRowHeight(frame_number, height)
-
- def row_resized(self, row, old_height, new_height):
- """
- Will scale non-image slides.
- """
- # Only for non-text slides when row height cap in use
- max_img_row_height = Settings().value('advanced/slide max height')
- if self.service_item.is_text() or not isinstance(max_img_row_height, int) or max_img_row_height <= 0:
- return
- # Get and validate label widget containing slide & adjust max width
- try:
- self.cellWidget(row, 0).children()[1].setMaximumWidth(new_height * self.screen_ratio)
- except:
- return
-
- def screen_size_changed(self, screen_ratio):
- """
- This method is called whenever the live screen size changes, which then makes a layout recalculation necessary
-
- :param screen_ratio: The new screen ratio
- """
- self.screen_ratio = screen_ratio
- self.__recalculate_layout()
-
- def replace_service_item(self, service_item, width, slide_number):
- """
- Replace the current preview items with the ones in service_item and display the given slide
-
- :param service_item: The service item to insert
- :param width: The width of the column
- :param slide_number: The slide number to pre-select
- """
- self.service_item = service_item
- self.setRowCount(0)
- self.clear()
- self.setColumnWidth(0, width)
- row = 0
- text = []
- for frame_number, frame in enumerate(self.service_item.get_frames()):
- self.setRowCount(self.slide_count() + 1)
- item = QtWidgets.QTableWidgetItem()
- slide_height = 0
- if self.service_item.is_text():
- if frame['verseTag']:
- # These tags are already translated.
- verse_def = frame['verseTag']
- verse_def = '%s%s' % (verse_def[0], verse_def[1:])
- two_line_def = '%s\n%s' % (verse_def[0], verse_def[1:])
- row = two_line_def
- else:
- row += 1
- item.setText(frame['text'])
- else:
- label = QtWidgets.QLabel()
- label.setContentsMargins(4, 4, 4, 4)
- if self.service_item.is_media():
- label.setAlignment(QtCore.Qt.AlignHCenter | QtCore.Qt.AlignVCenter)
- else:
- label.setScaledContents(True)
- if self.service_item.is_command():
- pixmap = QtGui.QPixmap(frame['image'])
- pixmap.setDevicePixelRatio(label.devicePixelRatio())
- label.setPixmap(pixmap)
- else:
- image = self.image_manager.get_image(frame['path'], ImageSource.ImagePlugin)
- pixmap = QtGui.QPixmap.fromImage(image)
- pixmap.setDevicePixelRatio(label.devicePixelRatio())
- label.setPixmap(pixmap)
- slide_height = width // self.screen_ratio
- # Setup and validate row height cap if in use.
- max_img_row_height = Settings().value('advanced/slide max height')
- if isinstance(max_img_row_height, int) and max_img_row_height > 0:
- if slide_height > max_img_row_height:
- slide_height = max_img_row_height
- label.setMaximumWidth(max_img_row_height * self.screen_ratio)
- label.resize(max_img_row_height * self.screen_ratio, max_img_row_height)
- # Build widget with stretch padding
- container = QtWidgets.QWidget()
- hbox = QtWidgets.QHBoxLayout()
- hbox.setContentsMargins(0, 0, 0, 0)
- hbox.addWidget(label, stretch=1)
- hbox.addStretch(0)
- container.setLayout(hbox)
- # Add to table
- self.setCellWidget(frame_number, 0, container)
- else:
- # Add to table
- self.setCellWidget(frame_number, 0, label)
- row += 1
- text.append(str(row))
- self.setItem(frame_number, 0, item)
- if slide_height:
- self.setRowHeight(frame_number, slide_height)
- self.setVerticalHeaderLabels(text)
- if self.service_item.is_text():
- self.resizeRowsToContents()
- self.setColumnWidth(0, self.viewport().width())
- self.change_slide(slide_number)
-
- def change_slide(self, slide):
- """
- Switches to the given row.
- """
- # Retrieve setting
- autoscrolling = Settings().value('advanced/autoscrolling')
- # Check if auto-scroll disabled (None) and validate value as dict containing 'dist' and 'pos'
- # 'dist' represents the slide to scroll to relative to the new slide (-1 = previous, 0 = current, 1 = next)
- # 'pos' represents the vert position of of the slide (0 = in view, 1 = top, 2 = middle, 3 = bottom)
- if not (isinstance(autoscrolling, dict) and 'dist' in autoscrolling and 'pos' in autoscrolling and
- isinstance(autoscrolling['dist'], int) and isinstance(autoscrolling['pos'], int)):
- return
- # prevent scrolling past list bounds
- scroll_to_slide = slide + autoscrolling['dist']
- if scroll_to_slide < 0:
- scroll_to_slide = 0
- if scroll_to_slide >= self.slide_count():
- scroll_to_slide = self.slide_count() - 1
- # Scroll to item if possible.
- self.scrollToItem(self.item(scroll_to_slide, 0), autoscrolling['pos'])
- self.selectRow(slide)
-
- def current_slide_number(self):
- """
- Returns the position of the currently active item. Will return -1 if the widget is empty.
- """
- return super(ListPreviewWidget, self).currentRow()
-
- def slide_count(self):
- """
- Returns the number of slides this widget holds.
- """
- return super(ListPreviewWidget, self).rowCount()
=== modified file 'openlp/core/ui/mainwindow.py'
--- openlp/core/ui/mainwindow.py 2016-04-16 13:58:28 +0000
+++ openlp/core/ui/mainwindow.py 2016-04-22 19:42:45 +0000
@@ -38,15 +38,17 @@
check_directory_exists, translate, is_win, is_macosx, add_actions
from openlp.core.common.actions import ActionList, CategoryOrder
from openlp.core.common.versionchecker import get_application_version
-from openlp.core.lib import Renderer, OpenLPDockWidget, PluginManager, ImageManager, PluginStatus, ScreenList, \
- build_icon
+from openlp.core.lib import Renderer, PluginManager, ImageManager, PluginStatus, ScreenList, build_icon
from openlp.core.lib.ui import UiStrings, create_action
from openlp.core.ui import AboutForm, SettingsForm, ServiceManager, ThemeManager, LiveController, PluginForm, \
- MediaDockManager, ShortcutListForm, FormattingTagForm, PreviewController
+ ShortcutListForm, FormattingTagForm, PreviewController
from openlp.core.ui.firsttimeform import FirstTimeForm
from openlp.core.ui.media import MediaController
from openlp.core.ui.printserviceform import PrintServiceForm
from openlp.core.ui.projector.manager import ProjectorManager
+from openlp.core.ui.lib.toolbar import OpenLPToolbar
+from openlp.core.ui.lib.dockwidget import OpenLPDockWidget
+from openlp.core.ui.lib.mediadockmanager import MediaDockManager
log = logging.getLogger(__name__)
=== modified file 'openlp/core/ui/media/mediacontroller.py'
--- openlp/core/ui/media/mediacontroller.py 2016-04-13 18:38:49 +0000
+++ openlp/core/ui/media/mediacontroller.py 2016-04-22 19:42:45 +0000
@@ -29,14 +29,16 @@
from PyQt5 import QtCore, QtWidgets
from openlp.core.common import OpenLPMixin, Registry, RegistryMixin, RegistryProperties, Settings, UiStrings, translate
-from openlp.core.lib import OpenLPToolbar, ItemCapabilities
+from openlp.core.lib import ItemCapabilities
from openlp.core.lib.ui import critical_error_message_box
+from openlp.core.common import AppLocation
+from openlp.core.ui import DisplayControllerType
+from openlp.core.ui.media.vendor.mediainfoWrapper import MediaInfoWrapper
+from openlp.core.ui.media.mediaplayer import MediaPlayer
from openlp.core.ui.media import MediaState, MediaInfo, MediaType, get_media_players, set_media_players,\
parse_optical_path
-from openlp.core.ui.media.vendor.mediainfoWrapper import MediaInfoWrapper
-from openlp.core.ui.media.mediaplayer import MediaPlayer
-from openlp.core.common import AppLocation
-from openlp.core.ui import DisplayControllerType
+from openlp.core.ui.lib.toolbar import OpenLPToolbar
+from openlp.core.ui.lib.dockwidget import OpenLPDockWidget
log = logging.getLogger(__name__)
=== modified file 'openlp/core/ui/media/playertab.py'
--- openlp/core/ui/media/playertab.py 2016-02-21 09:23:09 +0000
+++ openlp/core/ui/media/playertab.py 2016-04-22 19:42:45 +0000
@@ -26,9 +26,10 @@
from PyQt5 import QtCore, QtWidgets
from openlp.core.common import Registry, Settings, UiStrings, translate
-from openlp.core.lib import ColorButton, SettingsTab
+from openlp.core.lib import SettingsTab
from openlp.core.lib.ui import create_button
from openlp.core.ui.media import get_media_players, set_media_players
+from openlp.core.ui.lib.colorbutton import ColorButton
class MediaQCheckBox(QtWidgets.QCheckBox):
=== removed file 'openlp/core/ui/mediadockmanager.py'
--- openlp/core/ui/mediadockmanager.py 2016-01-10 18:01:36 +0000
+++ openlp/core/ui/mediadockmanager.py 1970-01-01 00:00:00 +0000
@@ -1,71 +0,0 @@
-# -*- coding: utf-8 -*-
-# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
-
-###############################################################################
-# OpenLP - Open Source Lyrics Projection #
-# --------------------------------------------------------------------------- #
-# Copyright (c) 2008-2016 OpenLP Developers #
-# --------------------------------------------------------------------------- #
-# This program is free software; you can redistribute it and/or modify it #
-# under the terms of the GNU General Public License as published by the Free #
-# Software Foundation; version 2 of the License. #
-# #
-# This program is distributed in the hope that it will be useful, but WITHOUT #
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
-# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
-# more details. #
-# #
-# You should have received a copy of the GNU General Public License along #
-# with this program; if not, write to the Free Software Foundation, Inc., 59 #
-# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
-###############################################################################
-"""
-The media manager dock.
-"""
-import logging
-
-from openlp.core.lib import StringContent
-
-log = logging.getLogger(__name__)
-
-
-class MediaDockManager(object):
- """
- Provide a repository for MediaManagerItems
- """
- def __init__(self, media_dock):
- """
- Initialise the media dock
- """
- self.media_dock = media_dock
-
- def add_item_to_dock(self, media_item):
- """
- Add a MediaManagerItem to the dock
- If the item has been added before, it's silently skipped
-
- :param media_item: The item to add to the dock
- """
- visible_title = media_item.plugin.get_string(StringContent.VisibleName)
- log.debug('Inserting %s dock' % visible_title['title'])
- match = False
- for dock_index in range(self.media_dock.count()):
- if self.media_dock.widget(dock_index).settings_section == media_item.plugin.name:
- match = True
- break
- if not match:
- self.media_dock.addItem(media_item, visible_title['title'])
-
- def remove_dock(self, media_item):
- """
- Removes a MediaManagerItem from the dock
-
- :param media_item: The item to add to the dock
- """
- visible_title = media_item.plugin.get_string(StringContent.VisibleName)
- log.debug('remove %s dock' % visible_title['title'])
- for dock_index in range(self.media_dock.count()):
- if self.media_dock.widget(dock_index):
- if self.media_dock.widget(dock_index).settings_section == media_item.plugin.name:
- self.media_dock.widget(dock_index).setVisible(False)
- self.media_dock.removeItem(dock_index)
=== modified file 'openlp/core/ui/projector/manager.py'
--- openlp/core/ui/projector/manager.py 2016-03-03 17:53:29 +0000
+++ openlp/core/ui/projector/manager.py 2016-04-22 19:42:45 +0000
@@ -35,7 +35,7 @@
from openlp.core.common import RegistryProperties, Settings, OpenLPMixin, \
RegistryMixin, translate
-from openlp.core.lib import OpenLPToolbar
+from openlp.core.ui.lib import OpenLPToolbar
from openlp.core.lib.ui import create_widget_action
from openlp.core.lib.projector import DialogSourceStyle
from openlp.core.lib.projector.constants import *
=== modified file 'openlp/core/ui/servicemanager.py'
--- openlp/core/ui/servicemanager.py 2016-04-05 17:10:51 +0000
+++ openlp/core/ui/servicemanager.py 2016-04-22 19:42:45 +0000
@@ -35,9 +35,10 @@
from openlp.core.common import Registry, RegistryProperties, AppLocation, Settings, ThemeLevel, OpenLPMixin, \
RegistryMixin, check_directory_exists, UiStrings, translate, split_filename, delete_file
from openlp.core.common.actions import ActionList, CategoryOrder
-from openlp.core.lib import OpenLPToolbar, ServiceItem, ItemCapabilities, PluginStatus, build_icon
+from openlp.core.lib import ServiceItem, ItemCapabilities, PluginStatus, build_icon
from openlp.core.lib.ui import critical_error_message_box, create_widget_action, find_and_set_in_combo_box
from openlp.core.ui import ServiceNoteForm, ServiceItemEditForm, StartTimeForm
+from openlp.core.ui.lib import OpenLPToolbar
from openlp.core.common.languagemanager import format_time
=== modified file 'openlp/core/ui/slidecontroller.py'
--- openlp/core/ui/slidecontroller.py 2016-04-06 05:08:44 +0000
+++ openlp/core/ui/slidecontroller.py 2016-04-22 19:42:45 +0000
@@ -33,11 +33,14 @@
from openlp.core.common import Registry, RegistryProperties, Settings, SlideLimits, UiStrings, translate, \
RegistryMixin, OpenLPMixin
from openlp.core.common.actions import ActionList, CategoryOrder
-from openlp.core.lib import OpenLPToolbar, ItemCapabilities, ServiceItem, ImageSource, ServiceItemAction, \
- ScreenList, build_icon, build_html
+from openlp.core.lib import ItemCapabilities, ServiceItem, ImageSource, ServiceItemAction, ScreenList, build_icon, \
+ build_html
from openlp.core.lib.ui import create_action
+from openlp.core.ui.lib.toolbar import OpenLPToolbar
+from openlp.core.ui.lib.dockwidget import OpenLPDockWidget
+from openlp.core.ui.lib.listpreviewwidget import ListPreviewWidget
from openlp.core.ui import HideMode, MainDisplay, Display, DisplayControllerType
-from openlp.core.ui.listpreviewwidget import ListPreviewWidget
+
# Threshold which has to be trespassed to toggle.
HIDE_MENU_THRESHOLD = 27
=== modified file 'openlp/core/ui/themeform.py'
--- openlp/core/ui/themeform.py 2016-04-06 05:08:44 +0000
+++ openlp/core/ui/themeform.py 2016-04-22 19:42:45 +0000
@@ -31,6 +31,7 @@
from openlp.core.lib.theme import BackgroundType, BackgroundGradientType
from openlp.core.lib.ui import critical_error_message_box
from openlp.core.ui import ThemeLayoutForm
+from openlp.core.ui.lib.colorbutton import ColorButton
from .themewizard import Ui_ThemeWizard
log = logging.getLogger(__name__)
=== modified file 'openlp/core/ui/thememanager.py'
--- openlp/core/ui/thememanager.py 2016-04-10 20:24:07 +0000
+++ openlp/core/ui/thememanager.py 2016-04-22 19:42:45 +0000
@@ -31,11 +31,12 @@
from openlp.core.common import Registry, RegistryProperties, AppLocation, Settings, OpenLPMixin, RegistryMixin, \
check_directory_exists, UiStrings, translate, is_win, get_filesystem_encoding, delete_file
-from openlp.core.lib import FileDialog, ImageSource, OpenLPToolbar, ValidationError, get_text_file_string, build_icon, \
+from openlp.core.lib import FileDialog, ImageSource, ValidationError, get_text_file_string, build_icon, \
check_item_selected, create_thumb, validate_thumb
from openlp.core.lib.theme import ThemeXML, BackgroundType
from openlp.core.lib.ui import critical_error_message_box, create_widget_action
from openlp.core.ui import FileRenameForm, ThemeForm
+from openlp.core.ui.lib import OpenLPToolbar
from openlp.core.common.languagemanager import get_locale_key
=== modified file 'openlp/core/ui/themewizard.py'
--- openlp/core/ui/themewizard.py 2015-12-31 22:46:06 +0000
+++ openlp/core/ui/themewizard.py 2016-04-22 19:42:45 +0000
@@ -25,9 +25,10 @@
from PyQt5 import QtCore, QtGui, QtWidgets
from openlp.core.common import UiStrings, translate, is_macosx
-from openlp.core.lib import build_icon, ColorButton
+from openlp.core.lib import build_icon
from openlp.core.lib.theme import HorizontalType, BackgroundType, BackgroundGradientType
from openlp.core.lib.ui import add_welcome_page, create_valign_selection_widgets
+from openlp.core.ui.lib.colorbutton import ColorButton
class Ui_ThemeWizard(object):
=== removed file 'openlp/core/ui/wizard.py'
--- openlp/core/ui/wizard.py 2016-02-27 14:03:52 +0000
+++ openlp/core/ui/wizard.py 1970-01-01 00:00:00 +0000
@@ -1,308 +0,0 @@
-# -*- coding: utf-8 -*-
-# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
-
-###############################################################################
-# OpenLP - Open Source Lyrics Projection #
-# --------------------------------------------------------------------------- #
-# Copyright (c) 2008-2016 OpenLP Developers #
-# --------------------------------------------------------------------------- #
-# This program is free software; you can redistribute it and/or modify it #
-# under the terms of the GNU General Public License as published by the Free #
-# Software Foundation; version 2 of the License. #
-# #
-# This program is distributed in the hope that it will be useful, but WITHOUT #
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
-# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
-# more details. #
-# #
-# You should have received a copy of the GNU General Public License along #
-# with this program; if not, write to the Free Software Foundation, Inc., 59 #
-# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
-###############################################################################
-"""
-The :mod:``wizard`` module provides generic wizard tools for OpenLP.
-"""
-import logging
-import os
-
-from PyQt5 import QtGui, QtWidgets
-
-from openlp.core.common import Registry, RegistryProperties, Settings, UiStrings, translate, is_macosx
-from openlp.core.lib import build_icon
-from openlp.core.lib.ui import add_welcome_page
-
-log = logging.getLogger(__name__)
-
-
-class WizardStrings(object):
- """
- Provide standard strings for wizards to use.
- """
- # Applications/Formats we import from or export to. These get used in
- # multiple places but do not need translating unless you find evidence of
- # the writers translating their own product name.
- CSV = 'CSV'
- OS = 'OpenSong'
- OSIS = 'OSIS'
- ZEF = 'Zefania'
- # These strings should need a good reason to be retranslated elsewhere.
- FinishedImport = translate('OpenLP.Ui', 'Finished import.')
- FormatLabel = translate('OpenLP.Ui', 'Format:')
- HeaderStyle = '<span style="font-size:14pt; font-weight:600;">%s</span>'
- Importing = translate('OpenLP.Ui', 'Importing')
- ImportingType = translate('OpenLP.Ui', 'Importing "%s"...')
- ImportSelect = translate('OpenLP.Ui', 'Select Import Source')
- ImportSelectLong = translate('OpenLP.Ui', 'Select the import format and the location to import from.')
- OpenTypeFile = translate('OpenLP.Ui', 'Open %s File')
- OpenTypeFolder = translate('OpenLP.Ui', 'Open %s Folder')
- PercentSymbolFormat = translate('OpenLP.Ui', '%p%')
- Ready = translate('OpenLP.Ui', 'Ready.')
- StartingImport = translate('OpenLP.Ui', 'Starting import...')
- YouSpecifyFile = translate('OpenLP.Ui', 'You need to specify one %s file to import from.',
- 'A file type e.g. OpenSong')
- YouSpecifyFiles = translate('OpenLP.Ui', 'You need to specify at least one %s file to import from.',
- 'A file type e.g. OpenSong')
- YouSpecifyFolder = translate('OpenLP.Ui', 'You need to specify one %s folder to import from.',
- 'A song format e.g. PowerSong')
-
-
-class OpenLPWizard(QtWidgets.QWizard, RegistryProperties):
- """
- Generic OpenLP wizard to provide generic functionality and a unified look
- and feel.
-
- ``parent``
- The QWidget-derived parent of the wizard.
-
- ``plugin``
- Plugin this wizard is part of. The plugin will be saved in the "plugin" variable.
- The plugin will also be used as basis for the file dialog methods this class provides.
-
- ``name``
- The object name this wizard should have.
-
- ``image``
- The image to display on the "welcome" page of the wizard. Should be 163x350.
-
- ``add_progress_page``
- Whether to add a progress page with a progressbar at the end of the wizard.
- """
- def __init__(self, parent, plugin, name, image, add_progress_page=True):
- """
- Constructor
- """
- super(OpenLPWizard, self).__init__(parent)
- self.plugin = plugin
- self.with_progress_page = add_progress_page
- self.setObjectName(name)
- self.open_icon = build_icon(':/general/general_open.png')
- self.delete_icon = build_icon(':/general/general_delete.png')
- self.finish_button = self.button(QtWidgets.QWizard.FinishButton)
- self.cancel_button = self.button(QtWidgets.QWizard.CancelButton)
- self.setupUi(image)
- self.register_fields()
- self.custom_init()
- self.custom_signals()
- self.currentIdChanged.connect(self.on_current_id_changed)
- if self.with_progress_page:
- self.error_copy_to_button.clicked.connect(self.on_error_copy_to_button_clicked)
- self.error_save_to_button.clicked.connect(self.on_error_save_to_button_clicked)
-
- def setupUi(self, image):
- """
- Set up the wizard UI.
- :param image: path to start up image
- """
- self.setWindowIcon(build_icon(u':/icon/openlp-logo.svg'))
- self.setModal(True)
- self.setOptions(QtWidgets.QWizard.IndependentPages |
- QtWidgets.QWizard.NoBackButtonOnStartPage | QtWidgets.QWizard.NoBackButtonOnLastPage)
- if is_macosx():
- self.setPixmap(QtWidgets.QWizard.BackgroundPixmap, QtGui.QPixmap(':/wizards/openlp-osx-wizard.png'))
- else:
- self.setWizardStyle(QtWidgets.QWizard.ModernStyle)
- add_welcome_page(self, image)
- self.add_custom_pages()
- if self.with_progress_page:
- self.add_progress_page()
- self.retranslateUi()
-
- def register_fields(self):
- """
- Hook method for wizards to register any fields they need.
- """
- pass
-
- def custom_init(self):
- """
- Hook method for custom initialisation
- """
- pass
-
- def custom_signals(self):
- """
- Hook method for adding custom signals
- """
- pass
-
- def add_custom_pages(self):
- """
- Hook method for wizards to add extra pages
- """
- pass
-
- def add_progress_page(self):
- """
- Add the progress page for the wizard. This page informs the user how
- the wizard is progressing with its task.
- """
- self.progress_page = QtWidgets.QWizardPage()
- self.progress_page.setObjectName('progress_page')
- self.progress_layout = QtWidgets.QVBoxLayout(self.progress_page)
- self.progress_layout.setContentsMargins(48, 48, 48, 48)
- self.progress_layout.setObjectName('progress_layout')
- self.progress_label = QtWidgets.QLabel(self.progress_page)
- self.progress_label.setObjectName('progress_label')
- self.progress_label.setWordWrap(True)
- self.progress_layout.addWidget(self.progress_label)
- self.progress_bar = QtWidgets.QProgressBar(self.progress_page)
- self.progress_bar.setObjectName('progress_bar')
- self.progress_layout.addWidget(self.progress_bar)
- # Add a QTextEdit and a copy to file and copy to clipboard button to be
- # able to provide feedback to the user. Hidden by default.
- self.error_report_text_edit = QtWidgets.QTextEdit(self.progress_page)
- self.error_report_text_edit.setObjectName('error_report_text_edit')
- self.error_report_text_edit.setHidden(True)
- self.error_report_text_edit.setReadOnly(True)
- self.progress_layout.addWidget(self.error_report_text_edit)
- self.error_button_layout = QtWidgets.QHBoxLayout()
- self.error_button_layout.setObjectName('error_button_layout')
- spacer = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
- self.error_button_layout.addItem(spacer)
- self.error_copy_to_button = QtWidgets.QPushButton(self.progress_page)
- self.error_copy_to_button.setObjectName('error_copy_to_button')
- self.error_copy_to_button.setHidden(True)
- self.error_copy_to_button.setIcon(build_icon(':/system/system_edit_copy.png'))
- self.error_button_layout.addWidget(self.error_copy_to_button)
- self.error_save_to_button = QtWidgets.QPushButton(self.progress_page)
- self.error_save_to_button.setObjectName('error_save_to_button')
- self.error_save_to_button.setHidden(True)
- self.error_save_to_button.setIcon(build_icon(':/general/general_save.png'))
- self.error_button_layout.addWidget(self.error_save_to_button)
- self.progress_layout.addLayout(self.error_button_layout)
- self.addPage(self.progress_page)
-
- def exec(self):
- """
- Run the wizard.
- """
- self.set_defaults()
- return QtWidgets.QWizard.exec(self)
-
- def reject(self):
- """
- Stop the wizard on cancel button, close button or ESC key.
- """
- log.debug('Wizard cancelled by user.')
- if self.with_progress_page and self.currentPage() == self.progress_page:
- Registry().execute('openlp_stop_wizard')
- self.done(QtWidgets.QDialog.Rejected)
-
- def on_current_id_changed(self, page_id):
- """
- Perform necessary functions depending on which wizard page is active.
- :param page_id: current page number
- """
- if self.with_progress_page and self.page(page_id) == self.progress_page:
- self.pre_wizard()
- self.perform_wizard()
- self.post_wizard()
- else:
- self.custom_page_changed(page_id)
-
- def custom_page_changed(self, page_id):
- """
- Called when changing to a page other than the progress page
- :param page_id: current page number
- """
- pass
-
- def on_error_copy_to_button_clicked(self):
- """
- Called when the ``error_copy_to_button`` has been clicked.
- """
- pass
-
- def on_error_save_to_button_clicked(self):
- """
- Called when the ``error_save_to_button`` has been clicked.
- """
- pass
-
- def increment_progress_bar(self, status_text, increment=1):
- """
- Update the wizard progress page.
-
- :param status_text: Current status information to display.
- :param increment: The value to increment the progress bar by.
- """
- log.debug('IncrementBar %s', status_text)
- self.progress_label.setText(status_text)
- if increment > 0:
- self.progress_bar.setValue(self.progress_bar.value() + increment)
- self.application.process_events()
-
- def pre_wizard(self):
- """
- Prepare the UI for the import.
- """
- self.finish_button.setVisible(False)
- self.progress_bar.setMinimum(0)
- self.progress_bar.setMaximum(1188)
- self.progress_bar.setValue(0)
-
- def post_wizard(self):
- """
- Clean up the UI after the import has finished.
- """
- self.progress_bar.setValue(self.progress_bar.maximum())
- self.finish_button.setVisible(True)
- self.cancel_button.setVisible(False)
- self.application.process_events()
-
- def get_file_name(self, title, editbox, setting_name, filters=''):
- """
- Opens a QFileDialog and saves the filename to the given editbox.
-
- :param title: The title of the dialog (unicode).
- :param editbox: An editbox (QLineEdit).
- :param setting_name: The place where to save the last opened directory.
- :param filters: The file extension filters. It should contain the file description
- as well as the file extension. For example::
-
- 'OpenLP 2 Databases (*.sqlite)'
- """
- if filters:
- filters += ';;'
- filters += '%s (*)' % UiStrings().AllFiles
- filename, filter_used = QtWidgets.QFileDialog.getOpenFileName(
- self, title, os.path.dirname(Settings().value(self.plugin.settings_section + '/' + setting_name)),
- filters)
- if filename:
- editbox.setText(filename)
- Settings().setValue(self.plugin.settings_section + '/' + setting_name, filename)
-
- def get_folder(self, title, editbox, setting_name):
- """
- Opens a QFileDialog and saves the selected folder to the given editbox.
-
- :param title: The title of the dialog (unicode).
- :param editbox: An editbox (QLineEdit).
- :param setting_name: The place where to save the last opened directory.
- """
- folder = QtWidgets.QFileDialog.getExistingDirectory(
- self, title, Settings().value(self.plugin.settings_section + '/' + setting_name),
- QtWidgets.QFileDialog.ShowDirsOnly)
- if folder:
- editbox.setText(folder)
- Settings().setValue(self.plugin.settings_section + '/' + setting_name, folder)
=== modified file 'openlp/plugins/alerts/lib/alertstab.py'
--- openlp/plugins/alerts/lib/alertstab.py 2015-12-31 22:46:06 +0000
+++ openlp/plugins/alerts/lib/alertstab.py 2016-04-22 19:42:45 +0000
@@ -23,8 +23,9 @@
from PyQt5 import QtGui, QtWidgets
from openlp.core.common import Settings, UiStrings, translate
-from openlp.core.lib import ColorButton, SettingsTab
+from openlp.core.lib import SettingsTab
from openlp.core.lib.ui import create_valign_selection_widgets
+from openlp.core.ui.lib.colorbutton import ColorButton
class AlertsTab(SettingsTab):
=== modified file 'openlp/plugins/bibles/forms/bibleimportform.py'
--- openlp/plugins/bibles/forms/bibleimportform.py 2016-04-05 17:30:20 +0000
+++ openlp/plugins/bibles/forms/bibleimportform.py 2016-04-22 19:42:45 +0000
@@ -31,7 +31,7 @@
from openlp.core.common import AppLocation, Settings, UiStrings, translate, clean_filename
from openlp.core.lib.db import delete_database
from openlp.core.lib.ui import critical_error_message_box
-from openlp.core.ui.wizard import OpenLPWizard, WizardStrings
+from openlp.core.ui.lib.wizard import OpenLPWizard, WizardStrings
from openlp.core.common.languagemanager import get_locale_key
from openlp.plugins.bibles.lib.manager import BibleFormat
from openlp.plugins.bibles.lib.db import BiblesResourcesDB, clean_filename
=== modified file 'openlp/plugins/bibles/forms/bibleupgradeform.py'
--- openlp/plugins/bibles/forms/bibleupgradeform.py 2016-04-05 17:10:51 +0000
+++ openlp/plugins/bibles/forms/bibleupgradeform.py 2016-04-22 19:42:45 +0000
@@ -32,7 +32,7 @@
from openlp.core.common import Registry, AppLocation, UiStrings, Settings, check_directory_exists, translate, \
delete_file
from openlp.core.lib.ui import critical_error_message_box
-from openlp.core.ui.wizard import OpenLPWizard, WizardStrings
+from openlp.core.ui.lib.wizard import OpenLPWizard, WizardStrings
from openlp.plugins.bibles.lib.db import BibleDB, BibleMeta, OldBibleDB, BiblesResourcesDB
from openlp.plugins.bibles.lib.http import BSExtract, BGExtract, CWExtract
=== modified file 'openlp/plugins/images/lib/imagetab.py'
--- openlp/plugins/images/lib/imagetab.py 2015-12-31 22:46:06 +0000
+++ openlp/plugins/images/lib/imagetab.py 2016-04-22 19:42:45 +0000
@@ -23,7 +23,8 @@
from PyQt5 import QtWidgets
from openlp.core.common import Settings, UiStrings, translate
-from openlp.core.lib import ColorButton, SettingsTab
+from openlp.core.lib import SettingsTab
+from openlp.core.ui.lib.colorbutton import ColorButton
class ImageTab(SettingsTab):
=== modified file 'openlp/plugins/images/lib/mediaitem.py'
--- openlp/plugins/images/lib/mediaitem.py 2016-04-13 17:40:05 +0000
+++ openlp/plugins/images/lib/mediaitem.py 2016-04-22 19:42:45 +0000
@@ -27,9 +27,10 @@
from openlp.core.common import Registry, AppLocation, Settings, UiStrings, check_directory_exists, translate, \
delete_file, get_images_filter
-from openlp.core.lib import ItemCapabilities, MediaManagerItem, ServiceItemContext, StringContent, TreeWidgetWithDnD,\
- build_icon, check_item_selected, create_thumb, validate_thumb
+from openlp.core.lib import ItemCapabilities, MediaManagerItem, ServiceItemContext, StringContent, build_icon, \
+ check_item_selected, create_thumb, validate_thumb
from openlp.core.lib.ui import create_widget_action, critical_error_message_box
+from openlp.core.ui.lib.treewidgetwithdnd import TreeWidgetWithDnD
from openlp.core.common.languagemanager import get_locale_key
from openlp.plugins.images.forms import AddGroupForm, ChooseGroupForm
from openlp.plugins.images.lib.db import ImageFilenames, ImageGroups
=== modified file 'openlp/plugins/songs/forms/duplicatesongremovalform.py'
--- openlp/plugins/songs/forms/duplicatesongremovalform.py 2015-12-31 22:46:06 +0000
+++ openlp/plugins/songs/forms/duplicatesongremovalform.py 2016-04-22 19:42:45 +0000
@@ -30,7 +30,7 @@
from PyQt5 import QtCore, QtWidgets
from openlp.core.common import Registry, RegistryProperties, translate
-from openlp.core.ui.wizard import OpenLPWizard, WizardStrings
+from openlp.core.ui.lib.wizard import OpenLPWizard, WizardStrings
from openlp.plugins.songs.lib import delete_song
from openlp.plugins.songs.lib.db import Song, MediaFile
from openlp.plugins.songs.forms.songreviewwidget import SongReviewWidget
=== modified file 'openlp/plugins/songs/forms/songexportform.py'
--- openlp/plugins/songs/forms/songexportform.py 2016-01-09 22:35:56 +0000
+++ openlp/plugins/songs/forms/songexportform.py 2016-04-22 19:42:45 +0000
@@ -30,7 +30,7 @@
from openlp.core.common import Registry, UiStrings, translate
from openlp.core.lib import create_separated_list, build_icon
from openlp.core.lib.ui import critical_error_message_box
-from openlp.core.ui.wizard import OpenLPWizard, WizardStrings
+from openlp.core.ui.lib.wizard import OpenLPWizard, WizardStrings
from openlp.plugins.songs.lib.db import Song
from openlp.plugins.songs.lib.openlyricsexport import OpenLyricsExport
=== modified file 'openlp/plugins/songs/forms/songimportform.py'
--- openlp/plugins/songs/forms/songimportform.py 2015-12-31 22:46:06 +0000
+++ openlp/plugins/songs/forms/songimportform.py 2016-04-22 19:42:45 +0000
@@ -31,7 +31,7 @@
from openlp.core.common import RegistryProperties, Settings, UiStrings, translate
from openlp.core.lib import FileDialog
from openlp.core.lib.ui import critical_error_message_box
-from openlp.core.ui.wizard import OpenLPWizard, WizardStrings
+from openlp.core.ui.lib.wizard import OpenLPWizard, WizardStrings
from openlp.plugins.songs.lib.importer import SongFormat, SongFormatSelect
log = logging.getLogger(__name__)
=== modified file 'openlp/plugins/songs/lib/importer.py'
--- openlp/plugins/songs/lib/importer.py 2016-03-31 05:39:13 +0000
+++ openlp/plugins/songs/lib/importer.py 2016-04-22 19:42:45 +0000
@@ -26,7 +26,7 @@
import logging
from openlp.core.common import translate, UiStrings, is_win
-from openlp.core.ui.wizard import WizardStrings
+from openlp.core.ui.lib.wizard import WizardStrings
from .importers.opensong import OpenSongImport
from .importers.easyslides import EasySlidesImport
from .importers.openlp import OpenLPSongImport
=== modified file 'openlp/plugins/songs/lib/importers/foilpresenter.py'
--- openlp/plugins/songs/lib/importers/foilpresenter.py 2016-01-09 16:26:14 +0000
+++ openlp/plugins/songs/lib/importers/foilpresenter.py 2016-04-22 19:42:45 +0000
@@ -90,7 +90,7 @@
from lxml import etree, objectify
from openlp.core.lib import translate
-from openlp.core.ui.wizard import WizardStrings
+from openlp.core.ui.lib.wizard import WizardStrings
from openlp.plugins.songs.lib import clean_song, VerseType
from openlp.plugins.songs.lib.importers.songimport import SongImport
from openlp.plugins.songs.lib.db import Author, Book, Song, Topic
=== modified file 'openlp/plugins/songs/lib/importers/openlp.py'
--- openlp/plugins/songs/lib/importers/openlp.py 2015-12-31 22:46:06 +0000
+++ openlp/plugins/songs/lib/importers/openlp.py 2016-04-22 19:42:45 +0000
@@ -31,7 +31,7 @@
from openlp.core.common import translate
from openlp.core.lib.db import BaseModel
-from openlp.core.ui.wizard import WizardStrings
+from openlp.core.ui.lib.wizard import WizardStrings
from openlp.plugins.songs.lib import clean_song
from openlp.plugins.songs.lib.db import Author, Book, Song, Topic, MediaFile
from .songimport import SongImport
=== modified file 'openlp/plugins/songs/lib/importers/openlyrics.py'
--- openlp/plugins/songs/lib/importers/openlyrics.py 2015-12-31 22:46:06 +0000
+++ openlp/plugins/songs/lib/importers/openlyrics.py 2016-04-22 19:42:45 +0000
@@ -29,7 +29,7 @@
from lxml import etree
-from openlp.core.ui.wizard import WizardStrings
+from openlp.core.ui.lib.wizard import WizardStrings
from openlp.plugins.songs.lib.importers.songimport import SongImport
from openlp.plugins.songs.lib.ui import SongStrings
from openlp.plugins.songs.lib.openlyricsxml import OpenLyrics, OpenLyricsError
=== modified file 'openlp/plugins/songs/lib/importers/powerpraise.py'
--- openlp/plugins/songs/lib/importers/powerpraise.py 2015-12-31 22:46:06 +0000
+++ openlp/plugins/songs/lib/importers/powerpraise.py 2016-04-22 19:42:45 +0000
@@ -27,7 +27,7 @@
import os
from lxml import objectify
-from openlp.core.ui.wizard import WizardStrings
+from openlp.core.ui.lib.wizard import WizardStrings
from .songimport import SongImport
=== modified file 'openlp/plugins/songs/lib/importers/presentationmanager.py'
--- openlp/plugins/songs/lib/importers/presentationmanager.py 2015-12-31 22:46:06 +0000
+++ openlp/plugins/songs/lib/importers/presentationmanager.py 2016-04-22 19:42:45 +0000
@@ -26,10 +26,11 @@
import os
import re
+
import chardet
from lxml import objectify, etree
-from openlp.core.ui.wizard import WizardStrings
+from openlp.core.ui.lib.wizard import WizardStrings
from .songimport import SongImport
=== modified file 'openlp/plugins/songs/lib/importers/propresenter.py'
--- openlp/plugins/songs/lib/importers/propresenter.py 2016-03-31 05:39:13 +0000
+++ openlp/plugins/songs/lib/importers/propresenter.py 2016-04-22 19:42:45 +0000
@@ -29,7 +29,7 @@
import logging
from lxml import objectify
-from openlp.core.ui.wizard import WizardStrings
+from openlp.core.ui.lib.wizard import WizardStrings
from openlp.plugins.songs.lib import strip_rtf
from .songimport import SongImport
=== modified file 'openlp/plugins/songs/lib/importers/songimport.py'
--- openlp/plugins/songs/lib/importers/songimport.py 2016-03-19 20:28:32 +0000
+++ openlp/plugins/songs/lib/importers/songimport.py 2016-04-22 19:42:45 +0000
@@ -28,7 +28,7 @@
from PyQt5 import QtCore
from openlp.core.common import Registry, AppLocation, check_directory_exists, translate
-from openlp.core.ui.wizard import WizardStrings
+from openlp.core.ui.lib.wizard import WizardStrings
from openlp.plugins.songs.lib import clean_song, VerseType
from openlp.plugins.songs.lib.db import Song, Author, Topic, Book, MediaFile
from openlp.plugins.songs.lib.ui import SongStrings
=== modified file 'openlp/plugins/songs/lib/importers/songshowplus.py'
--- openlp/plugins/songs/lib/importers/songshowplus.py 2015-12-31 22:46:06 +0000
+++ openlp/plugins/songs/lib/importers/songshowplus.py 2016-04-22 19:42:45 +0000
@@ -29,7 +29,7 @@
import re
import struct
-from openlp.core.ui.wizard import WizardStrings
+from openlp.core.ui.lib.wizard import WizardStrings
from openlp.plugins.songs.lib import VerseType, retrieve_windows_encoding
from openlp.plugins.songs.lib.importers.songimport import SongImport
=== modified file 'tests/functional/openlp_core_common/test_projector_utilities.py'
--- tests/functional/openlp_core_common/test_projector_utilities.py 2016-01-09 17:21:20 +0000
+++ tests/functional/openlp_core_common/test_projector_utilities.py 2016-04-22 19:42:45 +0000
@@ -23,13 +23,12 @@
Package to test the openlp.core.ui.projector.networkutils package.
"""
-import os
-
from unittest import TestCase
from openlp.core.common import verify_ip_address, md5_hash, qmd5_hash
from tests.resources.projector.data import TEST_PIN, TEST_SALT, TEST_HASH
+
salt = TEST_SALT
pin = TEST_PIN
test_hash = TEST_HASH
=== removed file 'tests/functional/openlp_core_lib/test_color_button.py'
--- tests/functional/openlp_core_lib/test_color_button.py 2015-12-31 22:46:06 +0000
+++ tests/functional/openlp_core_lib/test_color_button.py 1970-01-01 00:00:00 +0000
@@ -1,199 +0,0 @@
-# -*- coding: utf-8 -*-
-# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
-
-###############################################################################
-# OpenLP - Open Source Lyrics Projection #
-# --------------------------------------------------------------------------- #
-# Copyright (c) 2008-2016 OpenLP Developers #
-# --------------------------------------------------------------------------- #
-# This program is free software; you can redistribute it and/or modify it #
-# under the terms of the GNU General Public License as published by the Free #
-# Software Foundation; version 2 of the License. #
-# #
-# This program is distributed in the hope that it will be useful, but WITHOUT #
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
-# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
-# more details. #
-# #
-# You should have received a copy of the GNU General Public License along #
-# with this program; if not, write to the Free Software Foundation, Inc., 59 #
-# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
-###############################################################################
-"""
-This module contains tests for the openlp.core.lib.filedialog module
-"""
-from unittest import TestCase
-
-from openlp.core.lib.colorbutton import ColorButton
-from tests.functional import MagicMock, call, patch
-
-
-class TestColorDialog(TestCase):
- """
- Test the :class:`~openlp.core.lib.colorbutton.ColorButton` class
- """
- def setUp(self):
- self.change_color_patcher = patch('openlp.core.lib.colorbutton.ColorButton.change_color')
- self.clicked_patcher = patch('openlp.core.lib.colorbutton.ColorButton.clicked')
- self.color_changed_patcher = patch('openlp.core.lib.colorbutton.ColorButton.colorChanged')
- self.qt_gui_patcher = patch('openlp.core.lib.colorbutton.QtWidgets')
- self.translate_patcher = patch('openlp.core.lib.colorbutton.translate', **{'return_value': 'Tool Tip Text'})
- self.addCleanup(self.change_color_patcher.stop)
- self.addCleanup(self.clicked_patcher.stop)
- self.addCleanup(self.color_changed_patcher.stop)
- self.addCleanup(self.qt_gui_patcher.stop)
- self.addCleanup(self.translate_patcher.stop)
- self.mocked_change_color = self.change_color_patcher.start()
- self.mocked_clicked = self.clicked_patcher.start()
- self.mocked_color_changed = self.color_changed_patcher.start()
- self.mocked_qt_widgets = self.qt_gui_patcher.start()
- self.mocked_translate = self.translate_patcher.start()
-
- def constructor_test(self):
- """
- Test that constructing a ColorButton object works correctly
- """
-
- # GIVEN: The ColorButton class, a mocked change_color, setToolTip methods and clicked signal
- with patch('openlp.core.lib.colorbutton.ColorButton.setToolTip') as mocked_set_tool_tip:
-
- # WHEN: The ColorButton object is instantiated
- widget = ColorButton()
-
- # THEN: The widget __init__ method should have the correct properties and methods called
- self.assertEqual(widget.parent, None,
- 'The parent should be the same as the one that the class was instianted with')
- self.mocked_change_color.assert_called_once_with('#ffffff')
- mocked_set_tool_tip.assert_called_once_with('Tool Tip Text')
- self.mocked_clicked.connect.assert_called_once_with(widget.on_clicked)
-
- def change_color_test(self):
- """
- Test that change_color sets the new color and the stylesheet
- """
- self.change_color_patcher.stop()
-
- # GIVEN: An instance of the ColorButton object, and a mocked out setStyleSheet
- with patch('openlp.core.lib.colorbutton.ColorButton.setStyleSheet') as mocked_set_style_sheet:
- widget = ColorButton()
-
- # WHEN: Changing the color
- widget.change_color('#000000')
-
- # THEN: The _color attribute should be set to #000000 and setStyleSheet should have been called twice
- self.assertEqual(widget._color, '#000000', '_color should have been set to #000000')
- mocked_set_style_sheet.assert_has_calls(
- [call('background-color: #ffffff'), call('background-color: #000000')])
-
- self.mocked_change_color = self.change_color_patcher.start()
-
- def color_test(self):
- """
- Test that the color property method returns the set color
- """
-
- # GIVEN: An instance of ColorButton, with a set _color attribute
- widget = ColorButton()
- widget._color = '#000000'
-
- # WHEN: Accesing the color property
- value = widget.color
-
- # THEN: The value set in _color should be returned
- self.assertEqual(value, '#000000', 'The value returned should be equal to the one we set')
-
- def color_test(self):
- """
- Test that the color property method returns the set color
- """
-
- # GIVEN: An instance of ColorButton, with a set _color attribute
- widget = ColorButton()
- widget._color = '#000000'
-
- # WHEN: Accesing the color property
- value = widget.color
-
- # THEN: The value set in _color should be returned
- self.assertEqual(value, '#000000', 'The value returned should be equal to the one we set')
-
- def color_setter_test(self):
- """
- Test that the color property setter method sets the color
- """
-
- # GIVEN: An instance of ColorButton, with a mocked __init__
- with patch('openlp.core.lib.colorbutton.ColorButton.__init__', **{'return_value': None}):
- widget = ColorButton()
-
- # WHEN: Setting the color property
- widget.color = '#000000'
-
- # THEN: Then change_color should have been called with the value we set
- self.mocked_change_color.assert_called_once_with('#000000')
-
- def on_clicked_invalid_color_test(self):
- """
- Test the on_click method when an invalid color has been supplied
- """
-
- # GIVEN: An instance of ColorButton, and a set _color attribute
- widget = ColorButton()
- self.mocked_change_color.reset_mock()
- self.mocked_color_changed.reset_mock()
- widget._color = '#000000'
-
- # WHEN: The on_clicked method is called, and the color is invalid
- self.mocked_qt_widgets.QColorDialog.getColor.return_value = MagicMock(**{'isValid.return_value': False})
- widget.on_clicked()
-
- # THEN: change_color should not have been called and the colorChanged signal should not have been emitted
- self.assertEqual(
- self.mocked_change_color.call_count, 0, 'change_color should not have been called with an invalid color')
- self.assertEqual(
- self.mocked_color_changed.emit.call_count, 0,
- 'colorChange signal should not have been emitted with an invalid color')
-
- def on_clicked_same_color_test(self):
- """
- Test the on_click method when a new color has not been chosen
- """
-
- # GIVEN: An instance of ColorButton, and a set _color attribute
- widget = ColorButton()
- self.mocked_change_color.reset_mock()
- self.mocked_color_changed.reset_mock()
- widget._color = '#000000'
-
- # WHEN: The on_clicked method is called, and the color is valid, but the same as the existing color
- self.mocked_qt_widgets.QColorDialog.getColor.return_value = MagicMock(
- **{'isValid.return_value': True, 'name.return_value': '#000000'})
- widget.on_clicked()
-
- # THEN: change_color should not have been called and the colorChanged signal should not have been emitted
- self.assertEqual(
- self.mocked_change_color.call_count, 0,
- 'change_color should not have been called when the color has not changed')
- self.assertEqual(
- self.mocked_color_changed.emit.call_count, 0,
- 'colorChange signal should not have been emitted when the color has not changed')
-
- def on_clicked_new_color_test(self):
- """
- Test the on_click method when a new color has been chosen and is valid
- """
-
- # GIVEN: An instance of ColorButton, and a set _color attribute
- widget = ColorButton()
- self.mocked_change_color.reset_mock()
- self.mocked_color_changed.reset_mock()
- widget._color = '#000000'
-
- # WHEN: The on_clicked method is called, and the color is valid, and different to the existing color
- self.mocked_qt_widgets.QColorDialog.getColor.return_value = MagicMock(
- **{'isValid.return_value': True, 'name.return_value': '#ffffff'})
- widget.on_clicked()
-
- # THEN: change_color should have been called and the colorChanged signal should have been emitted
- self.mocked_change_color.assert_called_once_with('#ffffff')
- self.mocked_color_changed.emit.assert_called_once_with('#ffffff')
=== removed file 'tests/functional/openlp_core_ui/test_listpreviewwidget.py'
--- tests/functional/openlp_core_ui/test_listpreviewwidget.py 2016-04-16 16:35:08 +0000
+++ tests/functional/openlp_core_ui/test_listpreviewwidget.py 1970-01-01 00:00:00 +0000
@@ -1,377 +0,0 @@
-# -*- coding: utf-8 -*-
-# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
-
-###############################################################################
-# OpenLP - Open Source Lyrics Projection #
-# --------------------------------------------------------------------------- #
-# Copyright (c) 2008-2016 OpenLP Developers #
-# --------------------------------------------------------------------------- #
-# This program is free software; you can redistribute it and/or modify it #
-# under the terms of the GNU General Public License as published by the Free #
-# Software Foundation; version 2 of the License. #
-# #
-# This program is distributed in the hope that it will be useful, but WITHOUT #
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
-# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
-# more details. #
-# #
-# You should have received a copy of the GNU General Public License along #
-# with this program; if not, write to the Free Software Foundation, Inc., 59 #
-# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
-###############################################################################
-"""
-Package to test the openlp.core.ui.listpreviewwidget package.
-"""
-from unittest import TestCase
-
-from openlp.core.common import Settings
-from openlp.core.ui.listpreviewwidget import ListPreviewWidget
-from openlp.core.lib import ServiceItem
-
-from tests.functional import MagicMock, patch, call
-
-
-class TestListPreviewWidget(TestCase):
-
- def setUp(self):
- """
- Mock out stuff for all the tests
- """
- # Mock self.parent().width()
- self.parent_patcher = patch('openlp.core.ui.listpreviewwidget.ListPreviewWidget.parent')
- self.mocked_parent = self.parent_patcher.start()
- self.mocked_parent.width.return_value = 100
- self.addCleanup(self.parent_patcher.stop)
-
- # Mock Settings().value()
- self.Settings_patcher = patch('openlp.core.ui.listpreviewwidget.Settings')
- self.mocked_Settings = self.Settings_patcher.start()
- self.mocked_Settings_obj = MagicMock()
- self.mocked_Settings_obj.value.return_value = None
- self.mocked_Settings.return_value = self.mocked_Settings_obj
- self.addCleanup(self.Settings_patcher.stop)
-
- # Mock self.viewport().width()
- self.viewport_patcher = patch('openlp.core.ui.listpreviewwidget.ListPreviewWidget.viewport')
- self.mocked_viewport = self.viewport_patcher.start()
- self.mocked_viewport_obj = MagicMock()
- self.mocked_viewport_obj.width.return_value = 200
- self.mocked_viewport.return_value = self.mocked_viewport_obj
- self.addCleanup(self.viewport_patcher.stop)
-
- def new_list_preview_widget_test(self):
- """
- Test that creating an instance of ListPreviewWidget works
- """
- # GIVEN: A ListPreviewWidget class
-
- # WHEN: An object is created
- list_preview_widget = ListPreviewWidget(None, 1)
-
- # THEN: The object is not None, and the _setup() method was called.
- self.assertIsNotNone(list_preview_widget, 'The ListPreviewWidget object should not be None')
- self.assertEquals(list_preview_widget.screen_ratio, 1, 'Should not be called')
-
- @patch(u'openlp.core.ui.listpreviewwidget.ListPreviewWidget.resizeRowsToContents')
- @patch(u'openlp.core.ui.listpreviewwidget.ListPreviewWidget.setRowHeight')
- def replace_recalculate_layout_test_text(self, mocked_setRowHeight, mocked_resizeRowsToContents):
- """
- Test if "Max height for non-text slides..." enabled, txt slides unchanged in replace_service_item & __recalc...
- """
- # GIVEN: A setting to adjust "Max height for non-text slides in slide controller",
- # a text ServiceItem and a ListPreviewWidget.
-
- # Mock Settings().value('advanced/slide max height')
- self.mocked_Settings_obj.value.return_value = 100
- # Mock self.viewport().width()
- self.mocked_viewport_obj.width.return_value = 200
- # Mock text service item
- service_item = MagicMock()
- service_item.is_text.return_value = True
- service_item.get_frames.return_value = [{'title': None, 'text': None, 'verseTag': None},
- {'title': None, 'text': None, 'verseTag': None}]
- # init ListPreviewWidget and load service item
- list_preview_widget = ListPreviewWidget(None, 1)
- list_preview_widget.replace_service_item(service_item, 200, 0)
- # Change viewport width before forcing a resize
- self.mocked_viewport_obj.width.return_value = 400
-
- # WHEN: __recalculate_layout() is called (via resizeEvent)
- list_preview_widget.resizeEvent(None)
-
- # THEN: setRowHeight() should not be called, while resizeRowsToContents() should be called twice
- # (once each in __recalculate_layout and replace_service_item)
- self.assertEquals(mocked_resizeRowsToContents.call_count, 2, 'Should be called')
- self.assertEquals(mocked_setRowHeight.call_count, 0, 'Should not be called')
-
- @patch(u'openlp.core.ui.listpreviewwidget.ListPreviewWidget.resizeRowsToContents')
- @patch(u'openlp.core.ui.listpreviewwidget.ListPreviewWidget.setRowHeight')
- def replace_recalculate_layout_test_img(self, mocked_setRowHeight, mocked_resizeRowsToContents):
- """
- Test if "Max height for non-text slides..." disabled, img slides unchanged in replace_service_item & __recalc...
- """
- # GIVEN: A setting to adjust "Max height for non-text slides in slide controller",
- # an image ServiceItem and a ListPreviewWidget.
-
- # Mock Settings().value('advanced/slide max height')
- self.mocked_Settings_obj.value.return_value = 0
- # Mock self.viewport().width()
- self.mocked_viewport_obj.width.return_value = 200
- # Mock image service item
- service_item = MagicMock()
- service_item.is_text.return_value = False
- service_item.get_frames.return_value = [{'title': None, 'path': None, 'image': None},
- {'title': None, 'path': None, 'image': None}]
- # init ListPreviewWidget and load service item
- list_preview_widget = ListPreviewWidget(None, 1)
- list_preview_widget.replace_service_item(service_item, 200, 0)
- # Change viewport width before forcing a resize
- self.mocked_viewport_obj.width.return_value = 400
-
- # WHEN: __recalculate_layout() is called (via resizeEvent)
- list_preview_widget.resizeEvent(None)
- self.mocked_Settings_obj.value.return_value = None
- list_preview_widget.resizeEvent(None)
-
- # THEN: resizeRowsToContents() should not be called, while setRowHeight() should be called
- # twice for each slide.
- self.assertEquals(mocked_resizeRowsToContents.call_count, 0, 'Should not be called')
- self.assertEquals(mocked_setRowHeight.call_count, 6, 'Should be called 3 times for each slide')
- calls = [call(0, 200), call(1, 200), call(0, 400), call(1, 400), call(0, 400), call(1, 400)]
- mocked_setRowHeight.assert_has_calls(calls)
-
- @patch(u'openlp.core.ui.listpreviewwidget.ListPreviewWidget.resizeRowsToContents')
- @patch(u'openlp.core.ui.listpreviewwidget.ListPreviewWidget.setRowHeight')
- def replace_recalculate_layout_test_img_max(self, mocked_setRowHeight, mocked_resizeRowsToContents):
- """
- Test if "Max height for non-text slides..." enabled, img slides resized in replace_service_item & __recalc...
- """
- # GIVEN: A setting to adjust "Max height for non-text slides in slide controller",
- # an image ServiceItem and a ListPreviewWidget.
-
- # Mock Settings().value('advanced/slide max height')
- self.mocked_Settings_obj.value.return_value = 100
- # Mock self.viewport().width()
- self.mocked_viewport_obj.width.return_value = 200
- # Mock image service item
- service_item = MagicMock()
- service_item.is_text.return_value = False
- service_item.get_frames.return_value = [{'title': None, 'path': None, 'image': None},
- {'title': None, 'path': None, 'image': None}]
- # init ListPreviewWidget and load service item
- list_preview_widget = ListPreviewWidget(None, 1)
- list_preview_widget.replace_service_item(service_item, 200, 0)
- # Change viewport width before forcing a resize
- self.mocked_viewport_obj.width.return_value = 400
-
- # WHEN: __recalculate_layout() is called (via resizeEvent)
- list_preview_widget.resizeEvent(None)
-
- # THEN: resizeRowsToContents() should not be called, while setRowHeight() should be called
- # twice for each slide.
- self.assertEquals(mocked_resizeRowsToContents.call_count, 0, 'Should not be called')
- self.assertEquals(mocked_setRowHeight.call_count, 4, 'Should be called twice for each slide')
- calls = [call(0, 100), call(1, 100), call(0, 100), call(1, 100)]
- mocked_setRowHeight.assert_has_calls(calls)
-
- @patch(u'openlp.core.ui.listpreviewwidget.ListPreviewWidget.resizeRowsToContents')
- @patch(u'openlp.core.ui.listpreviewwidget.ListPreviewWidget.setRowHeight')
- @patch(u'openlp.core.ui.listpreviewwidget.ListPreviewWidget.cellWidget')
- def row_resized_test_text(self, mocked_cellWidget, mocked_setRowHeight, mocked_resizeRowsToContents):
- """
- Test if "Max height for non-text slides..." enabled, text-based slides not affected in row_resized.
- """
- # GIVEN: A setting to adjust "Max height for non-text slides in slide controller",
- # a text ServiceItem and a ListPreviewWidget.
-
- # Mock Settings().value('advanced/slide max height')
- self.mocked_Settings_obj.value.return_value = 100
- # Mock self.viewport().width()
- self.mocked_viewport_obj.width.return_value = 200
- # Mock text service item
- service_item = MagicMock()
- service_item.is_text.return_value = True
- service_item.get_frames.return_value = [{'title': None, 'text': None, 'verseTag': None},
- {'title': None, 'text': None, 'verseTag': None}]
- # Mock self.cellWidget().children().setMaximumWidth()
- mocked_cellWidget_child = MagicMock()
- mocked_cellWidget_obj = MagicMock()
- mocked_cellWidget_obj.children.return_value = [None, mocked_cellWidget_child]
- mocked_cellWidget.return_value = mocked_cellWidget_obj
- # init ListPreviewWidget and load service item
- list_preview_widget = ListPreviewWidget(None, 1)
- list_preview_widget.replace_service_item(service_item, 200, 0)
-
- # WHEN: row_resized() is called
- list_preview_widget.row_resized(0, 100, 150)
-
- # THEN: self.cellWidget(row, 0).children()[1].setMaximumWidth() should not be called
- self.assertEquals(mocked_cellWidget_child.setMaximumWidth.call_count, 0, 'Should not be called')
-
- @patch(u'openlp.core.ui.listpreviewwidget.ListPreviewWidget.resizeRowsToContents')
- @patch(u'openlp.core.ui.listpreviewwidget.ListPreviewWidget.setRowHeight')
- @patch(u'openlp.core.ui.listpreviewwidget.ListPreviewWidget.cellWidget')
- def row_resized_test_img(self, mocked_cellWidget, mocked_setRowHeight, mocked_resizeRowsToContents):
- """
- Test if "Max height for non-text slides..." disabled, image-based slides not affected in row_resized.
- """
- # GIVEN: A setting to adjust "Max height for non-text slides in slide controller",
- # an image ServiceItem and a ListPreviewWidget.
-
- # Mock Settings().value('advanced/slide max height')
- self.mocked_Settings_obj.value.return_value = 0
- # Mock self.viewport().width()
- self.mocked_viewport_obj.width.return_value = 200
- # Mock image service item
- service_item = MagicMock()
- service_item.is_text.return_value = False
- service_item.get_frames.return_value = [{'title': None, 'path': None, 'image': None},
- {'title': None, 'path': None, 'image': None}]
- # Mock self.cellWidget().children().setMaximumWidth()
- mocked_cellWidget_child = MagicMock()
- mocked_cellWidget_obj = MagicMock()
- mocked_cellWidget_obj.children.return_value = [None, mocked_cellWidget_child]
- mocked_cellWidget.return_value = mocked_cellWidget_obj
- # init ListPreviewWidget and load service item
- list_preview_widget = ListPreviewWidget(None, 1)
- list_preview_widget.replace_service_item(service_item, 200, 0)
-
- # WHEN: row_resized() is called
- list_preview_widget.row_resized(0, 100, 150)
- self.mocked_Settings_obj.value.return_value = None
- list_preview_widget.row_resized(0, 100, 150)
-
- # THEN: self.cellWidget(row, 0).children()[1].setMaximumWidth() should not be called
- self.assertEquals(mocked_cellWidget_child.setMaximumWidth.call_count, 0, 'Should not be called')
-
- @patch(u'openlp.core.ui.listpreviewwidget.ListPreviewWidget.resizeRowsToContents')
- @patch(u'openlp.core.ui.listpreviewwidget.ListPreviewWidget.setRowHeight')
- @patch(u'openlp.core.ui.listpreviewwidget.ListPreviewWidget.cellWidget')
- def row_resized_test_img_max(self, mocked_cellWidget, mocked_setRowHeight, mocked_resizeRowsToContents):
- """
- Test if "Max height for non-text slides..." enabled, image-based slides are scaled in row_resized.
- """
- # GIVEN: A setting to adjust "Max height for non-text slides in slide controller",
- # an image ServiceItem and a ListPreviewWidget.
-
- # Mock Settings().value('advanced/slide max height')
- self.mocked_Settings_obj.value.return_value = 100
- # Mock self.viewport().width()
- self.mocked_viewport_obj.width.return_value = 200
- # Mock image service item
- service_item = MagicMock()
- service_item.is_text.return_value = False
- service_item.get_frames.return_value = [{'title': None, 'path': None, 'image': None},
- {'title': None, 'path': None, 'image': None}]
- # Mock self.cellWidget().children().setMaximumWidth()
- mocked_cellWidget_child = MagicMock()
- mocked_cellWidget_obj = MagicMock()
- mocked_cellWidget_obj.children.return_value = [None, mocked_cellWidget_child]
- mocked_cellWidget.return_value = mocked_cellWidget_obj
- # init ListPreviewWidget and load service item
- list_preview_widget = ListPreviewWidget(None, 1)
- list_preview_widget.replace_service_item(service_item, 200, 0)
-
- # WHEN: row_resized() is called
- list_preview_widget.row_resized(0, 100, 150)
-
- # THEN: self.cellWidget(row, 0).children()[1].setMaximumWidth() should be called
- mocked_cellWidget_child.setMaximumWidth.assert_called_once_with(150)
-
- @patch(u'openlp.core.ui.listpreviewwidget.ListPreviewWidget.selectRow')
- @patch(u'openlp.core.ui.listpreviewwidget.ListPreviewWidget.scrollToItem')
- @patch(u'openlp.core.ui.listpreviewwidget.ListPreviewWidget.item')
- @patch(u'openlp.core.ui.listpreviewwidget.ListPreviewWidget.slide_count')
- def autoscroll_test_setting_invalid(self, mocked_slide_count, mocked_item, mocked_scrollToItem, mocked_selectRow):
- """
- Test if 'advanced/autoscrolling' setting None or invalid, that no autoscrolling occurs on change_slide().
- """
- # GIVEN: A setting for autoscrolling and a ListPreviewWidget.
- # Mock Settings().value('advanced/autoscrolling')
- self.mocked_Settings_obj.value.return_value = None
- # Mocked returns
- mocked_slide_count.return_value = 1
- mocked_item.return_value = None
- # init ListPreviewWidget and load service item
- list_preview_widget = ListPreviewWidget(None, 1)
-
- # WHEN: change_slide() is called
- list_preview_widget.change_slide(0)
- self.mocked_Settings_obj.value.return_value = 1
- list_preview_widget.change_slide(0)
- self.mocked_Settings_obj.value.return_value = {'fail': 1}
- list_preview_widget.change_slide(0)
- self.mocked_Settings_obj.value.return_value = {'dist': 1, 'fail': 1}
- list_preview_widget.change_slide(0)
- self.mocked_Settings_obj.value.return_value = {'dist': 'fail', 'pos': 1}
- list_preview_widget.change_slide(0)
- self.mocked_Settings_obj.value.return_value = {'dist': 1, 'pos': 'fail'}
- list_preview_widget.change_slide(0)
-
- # THEN: no further functions should be called
- self.assertEquals(mocked_slide_count.call_count, 0, 'Should not be called')
- self.assertEquals(mocked_scrollToItem.call_count, 0, 'Should not be called')
- self.assertEquals(mocked_selectRow.call_count, 0, 'Should not be called')
- self.assertEquals(mocked_item.call_count, 0, 'Should not be called')
-
- @patch(u'openlp.core.ui.listpreviewwidget.ListPreviewWidget.selectRow')
- @patch(u'openlp.core.ui.listpreviewwidget.ListPreviewWidget.scrollToItem')
- @patch(u'openlp.core.ui.listpreviewwidget.ListPreviewWidget.item')
- @patch(u'openlp.core.ui.listpreviewwidget.ListPreviewWidget.slide_count')
- def autoscroll_test_dist_bounds(self, mocked_slide_count, mocked_item, mocked_scrollToItem, mocked_selectRow):
- """
- Test if 'advanced/autoscrolling' setting asks to scroll beyond list bounds, that it does not beyond.
- """
- # GIVEN: A setting for autoscrolling and a ListPreviewWidget.
- # Mock Settings().value('advanced/autoscrolling')
- self.mocked_Settings_obj.value.return_value = {'dist': -1, 'pos': 1}
- # Mocked returns
- mocked_slide_count.return_value = 1
- mocked_item.return_value = None
- # init ListPreviewWidget and load service item
- list_preview_widget = ListPreviewWidget(None, 1)
-
- # WHEN: change_slide() is called
- list_preview_widget.change_slide(0)
- self.mocked_Settings_obj.value.return_value = {'dist': 1, 'pos': 1}
- list_preview_widget.change_slide(0)
-
- # THEN: no further functions should be called
- self.assertEquals(mocked_slide_count.call_count, 3, 'Should be called')
- self.assertEquals(mocked_scrollToItem.call_count, 2, 'Should be called')
- self.assertEquals(mocked_selectRow.call_count, 2, 'Should be called')
- self.assertEquals(mocked_item.call_count, 2, 'Should be called')
- calls = [call(0, 0), call(0, 0)]
- mocked_item.assert_has_calls(calls)
-
- @patch(u'openlp.core.ui.listpreviewwidget.ListPreviewWidget.selectRow')
- @patch(u'openlp.core.ui.listpreviewwidget.ListPreviewWidget.scrollToItem')
- @patch(u'openlp.core.ui.listpreviewwidget.ListPreviewWidget.item')
- @patch(u'openlp.core.ui.listpreviewwidget.ListPreviewWidget.slide_count')
- def autoscroll_test_normal(self, mocked_slide_count, mocked_item, mocked_scrollToItem, mocked_selectRow):
- """
- Test if 'advanced/autoscrolling' setting valid, autoscrolling called as expected.
- """
- # GIVEN: A setting for autoscrolling and a ListPreviewWidget.
- # Mock Settings().value('advanced/autoscrolling')
- self.mocked_Settings_obj.value.return_value = {'dist': -1, 'pos': 1}
- # Mocked returns
- mocked_slide_count.return_value = 3
- mocked_item.return_value = None
- # init ListPreviewWidget and load service item
- list_preview_widget = ListPreviewWidget(None, 1)
-
- # WHEN: change_slide() is called
- list_preview_widget.change_slide(1)
- self.mocked_Settings_obj.value.return_value = {'dist': 0, 'pos': 1}
- list_preview_widget.change_slide(1)
- self.mocked_Settings_obj.value.return_value = {'dist': 1, 'pos': 1}
- list_preview_widget.change_slide(1)
-
- # THEN: no further functions should be called
- self.assertEquals(mocked_slide_count.call_count, 3, 'Should be called')
- self.assertEquals(mocked_scrollToItem.call_count, 3, 'Should be called')
- self.assertEquals(mocked_selectRow.call_count, 3, 'Should be called')
- self.assertEquals(mocked_item.call_count, 3, 'Should be called')
- calls = [call(0, 0), call(1, 0), call(2, 0)]
- mocked_item.assert_has_calls(calls)
=== added directory 'tests/functional/openlp_core_ui_lib'
=== added file 'tests/functional/openlp_core_ui_lib/__init__.py'
=== added file 'tests/functional/openlp_core_ui_lib/test_color_button.py'
--- tests/functional/openlp_core_ui_lib/test_color_button.py 1970-01-01 00:00:00 +0000
+++ tests/functional/openlp_core_ui_lib/test_color_button.py 2016-04-22 19:42:45 +0000
@@ -0,0 +1,199 @@
+# -*- coding: utf-8 -*-
+# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
+
+###############################################################################
+# OpenLP - Open Source Lyrics Projection #
+# --------------------------------------------------------------------------- #
+# Copyright (c) 2008-2016 OpenLP Developers #
+# --------------------------------------------------------------------------- #
+# This program is free software; you can redistribute it and/or modify it #
+# under the terms of the GNU General Public License as published by the Free #
+# Software Foundation; version 2 of the License. #
+# #
+# This program is distributed in the hope that it will be useful, but WITHOUT #
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
+# more details. #
+# #
+# You should have received a copy of the GNU General Public License along #
+# with this program; if not, write to the Free Software Foundation, Inc., 59 #
+# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
+###############################################################################
+"""
+This module contains tests for the openlp.core.lib.filedialog module
+"""
+from unittest import TestCase
+
+from openlp.core.ui.lib.colorbutton import ColorButton
+from tests.functional import MagicMock, call, patch
+
+
+class TestColorDialog(TestCase):
+ """
+ Test the :class:`~openlp.core.lib.colorbutton.ColorButton` class
+ """
+ def setUp(self):
+ self.change_color_patcher = patch('openlp.core.ui.lib.colorbutton.ColorButton.change_color')
+ self.clicked_patcher = patch('openlp.core.ui.lib.colorbutton.ColorButton.clicked')
+ self.color_changed_patcher = patch('openlp.core.ui.lib.colorbutton.ColorButton.colorChanged')
+ self.qt_gui_patcher = patch('openlp.core.ui.lib.colorbutton.QtWidgets')
+ self.translate_patcher = patch('openlp.core.ui.lib.colorbutton.translate', **{'return_value': 'Tool Tip Text'})
+ self.addCleanup(self.change_color_patcher.stop)
+ self.addCleanup(self.clicked_patcher.stop)
+ self.addCleanup(self.color_changed_patcher.stop)
+ self.addCleanup(self.qt_gui_patcher.stop)
+ self.addCleanup(self.translate_patcher.stop)
+ self.mocked_change_color = self.change_color_patcher.start()
+ self.mocked_clicked = self.clicked_patcher.start()
+ self.mocked_color_changed = self.color_changed_patcher.start()
+ self.mocked_qt_widgets = self.qt_gui_patcher.start()
+ self.mocked_translate = self.translate_patcher.start()
+
+ def constructor_test(self):
+ """
+ Test that constructing a ColorButton object works correctly
+ """
+
+ # GIVEN: The ColorButton class, a mocked change_color, setToolTip methods and clicked signal
+ with patch('openlp.core.ui.lib.colorbutton.ColorButton.setToolTip') as mocked_set_tool_tip:
+
+ # WHEN: The ColorButton object is instantiated
+ widget = ColorButton()
+
+ # THEN: The widget __init__ method should have the correct properties and methods called
+ self.assertEqual(widget.parent, None,
+ 'The parent should be the same as the one that the class was instianted with')
+ self.mocked_change_color.assert_called_once_with('#ffffff')
+ mocked_set_tool_tip.assert_called_once_with('Tool Tip Text')
+ self.mocked_clicked.connect.assert_called_once_with(widget.on_clicked)
+
+ def change_color_test(self):
+ """
+ Test that change_color sets the new color and the stylesheet
+ """
+ self.change_color_patcher.stop()
+
+ # GIVEN: An instance of the ColorButton object, and a mocked out setStyleSheet
+ with patch('openlp.core.ui.lib.colorbutton.ColorButton.setStyleSheet') as mocked_set_style_sheet:
+ widget = ColorButton()
+
+ # WHEN: Changing the color
+ widget.change_color('#000000')
+
+ # THEN: The _color attribute should be set to #000000 and setStyleSheet should have been called twice
+ self.assertEqual(widget._color, '#000000', '_color should have been set to #000000')
+ mocked_set_style_sheet.assert_has_calls(
+ [call('background-color: #ffffff'), call('background-color: #000000')])
+
+ self.mocked_change_color = self.change_color_patcher.start()
+
+ def color_test(self):
+ """
+ Test that the color property method returns the set color
+ """
+
+ # GIVEN: An instance of ColorButton, with a set _color attribute
+ widget = ColorButton()
+ widget._color = '#000000'
+
+ # WHEN: Accesing the color property
+ value = widget.color
+
+ # THEN: The value set in _color should be returned
+ self.assertEqual(value, '#000000', 'The value returned should be equal to the one we set')
+
+ def color_test(self):
+ """
+ Test that the color property method returns the set color
+ """
+
+ # GIVEN: An instance of ColorButton, with a set _color attribute
+ widget = ColorButton()
+ widget._color = '#000000'
+
+ # WHEN: Accesing the color property
+ value = widget.color
+
+ # THEN: The value set in _color should be returned
+ self.assertEqual(value, '#000000', 'The value returned should be equal to the one we set')
+
+ def color_setter_test(self):
+ """
+ Test that the color property setter method sets the color
+ """
+
+ # GIVEN: An instance of ColorButton, with a mocked __init__
+ with patch('openlp.core.ui.lib.colorbutton.ColorButton.__init__', **{'return_value': None}):
+ widget = ColorButton()
+
+ # WHEN: Setting the color property
+ widget.color = '#000000'
+
+ # THEN: Then change_color should have been called with the value we set
+ self.mocked_change_color.assert_called_once_with('#000000')
+
+ def on_clicked_invalid_color_test(self):
+ """
+ Test the on_click method when an invalid color has been supplied
+ """
+
+ # GIVEN: An instance of ColorButton, and a set _color attribute
+ widget = ColorButton()
+ self.mocked_change_color.reset_mock()
+ self.mocked_color_changed.reset_mock()
+ widget._color = '#000000'
+
+ # WHEN: The on_clicked method is called, and the color is invalid
+ self.mocked_qt_widgets.QColorDialog.getColor.return_value = MagicMock(**{'isValid.return_value': False})
+ widget.on_clicked()
+
+ # THEN: change_color should not have been called and the colorChanged signal should not have been emitted
+ self.assertEqual(
+ self.mocked_change_color.call_count, 0, 'change_color should not have been called with an invalid color')
+ self.assertEqual(
+ self.mocked_color_changed.emit.call_count, 0,
+ 'colorChange signal should not have been emitted with an invalid color')
+
+ def on_clicked_same_color_test(self):
+ """
+ Test the on_click method when a new color has not been chosen
+ """
+
+ # GIVEN: An instance of ColorButton, and a set _color attribute
+ widget = ColorButton()
+ self.mocked_change_color.reset_mock()
+ self.mocked_color_changed.reset_mock()
+ widget._color = '#000000'
+
+ # WHEN: The on_clicked method is called, and the color is valid, but the same as the existing color
+ self.mocked_qt_widgets.QColorDialog.getColor.return_value = MagicMock(
+ **{'isValid.return_value': True, 'name.return_value': '#000000'})
+ widget.on_clicked()
+
+ # THEN: change_color should not have been called and the colorChanged signal should not have been emitted
+ self.assertEqual(
+ self.mocked_change_color.call_count, 0,
+ 'change_color should not have been called when the color has not changed')
+ self.assertEqual(
+ self.mocked_color_changed.emit.call_count, 0,
+ 'colorChange signal should not have been emitted when the color has not changed')
+
+ def on_clicked_new_color_test(self):
+ """
+ Test the on_click method when a new color has been chosen and is valid
+ """
+
+ # GIVEN: An instance of ColorButton, and a set _color attribute
+ widget = ColorButton()
+ self.mocked_change_color.reset_mock()
+ self.mocked_color_changed.reset_mock()
+ widget._color = '#000000'
+
+ # WHEN: The on_clicked method is called, and the color is valid, and different to the existing color
+ self.mocked_qt_widgets.QColorDialog.getColor.return_value = MagicMock(
+ **{'isValid.return_value': True, 'name.return_value': '#ffffff'})
+ widget.on_clicked()
+
+ # THEN: change_color should have been called and the colorChanged signal should have been emitted
+ self.mocked_change_color.assert_called_once_with('#ffffff')
+ self.mocked_color_changed.emit.assert_called_once_with('#ffffff')
=== added file 'tests/functional/openlp_core_ui_lib/test_listpreviewwidget.py'
--- tests/functional/openlp_core_ui_lib/test_listpreviewwidget.py 1970-01-01 00:00:00 +0000
+++ tests/functional/openlp_core_ui_lib/test_listpreviewwidget.py 2016-04-22 19:42:45 +0000
@@ -0,0 +1,377 @@
+# -*- coding: utf-8 -*-
+# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
+
+###############################################################################
+# OpenLP - Open Source Lyrics Projection #
+# --------------------------------------------------------------------------- #
+# Copyright (c) 2008-2016 OpenLP Developers #
+# --------------------------------------------------------------------------- #
+# This program is free software; you can redistribute it and/or modify it #
+# under the terms of the GNU General Public License as published by the Free #
+# Software Foundation; version 2 of the License. #
+# #
+# This program is distributed in the hope that it will be useful, but WITHOUT #
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
+# more details. #
+# #
+# You should have received a copy of the GNU General Public License along #
+# with this program; if not, write to the Free Software Foundation, Inc., 59 #
+# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
+###############################################################################
+"""
+Package to test the openlp.core.ui.lib.listpreviewwidget package.
+"""
+from unittest import TestCase
+
+from openlp.core.common import Settings
+from openlp.core.ui.lib.listpreviewwidget import ListPreviewWidget
+from openlp.core.lib import ServiceItem
+
+from tests.functional import MagicMock, patch, call
+
+
+class TestListPreviewWidget(TestCase):
+
+ def setUp(self):
+ """
+ Mock out stuff for all the tests
+ """
+ # Mock self.parent().width()
+ self.parent_patcher = patch('openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.parent')
+ self.mocked_parent = self.parent_patcher.start()
+ self.mocked_parent.width.return_value = 100
+ self.addCleanup(self.parent_patcher.stop)
+
+ # Mock Settings().value()
+ self.Settings_patcher = patch('openlp.core.ui.lib.listpreviewwidget.Settings')
+ self.mocked_Settings = self.Settings_patcher.start()
+ self.mocked_Settings_obj = MagicMock()
+ self.mocked_Settings_obj.value.return_value = None
+ self.mocked_Settings.return_value = self.mocked_Settings_obj
+ self.addCleanup(self.Settings_patcher.stop)
+
+ # Mock self.viewport().width()
+ self.viewport_patcher = patch('openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.viewport')
+ self.mocked_viewport = self.viewport_patcher.start()
+ self.mocked_viewport_obj = MagicMock()
+ self.mocked_viewport_obj.width.return_value = 200
+ self.mocked_viewport.return_value = self.mocked_viewport_obj
+ self.addCleanup(self.viewport_patcher.stop)
+
+ def new_list_preview_widget_test(self):
+ """
+ Test that creating an instance of ListPreviewWidget works
+ """
+ # GIVEN: A ListPreviewWidget class
+
+ # WHEN: An object is created
+ list_preview_widget = ListPreviewWidget(None, 1)
+
+ # THEN: The object is not None, and the _setup() method was called.
+ self.assertIsNotNone(list_preview_widget, 'The ListPreviewWidget object should not be None')
+ self.assertEquals(list_preview_widget.screen_ratio, 1, 'Should not be called')
+
+ @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.resizeRowsToContents')
+ @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.setRowHeight')
+ def replace_recalculate_layout_test_text(self, mocked_setRowHeight, mocked_resizeRowsToContents):
+ """
+ Test if "Max height for non-text slides..." enabled, txt slides unchanged in replace_service_item & __recalc...
+ """
+ # GIVEN: A setting to adjust "Max height for non-text slides in slide controller",
+ # a text ServiceItem and a ListPreviewWidget.
+
+ # Mock Settings().value('advanced/slide max height')
+ self.mocked_Settings_obj.value.return_value = 100
+ # Mock self.viewport().width()
+ self.mocked_viewport_obj.width.return_value = 200
+ # Mock text service item
+ service_item = MagicMock()
+ service_item.is_text.return_value = True
+ service_item.get_frames.return_value = [{'title': None, 'text': None, 'verseTag': None},
+ {'title': None, 'text': None, 'verseTag': None}]
+ # init ListPreviewWidget and load service item
+ list_preview_widget = ListPreviewWidget(None, 1)
+ list_preview_widget.replace_service_item(service_item, 200, 0)
+ # Change viewport width before forcing a resize
+ self.mocked_viewport_obj.width.return_value = 400
+
+ # WHEN: __recalculate_layout() is called (via resizeEvent)
+ list_preview_widget.resizeEvent(None)
+
+ # THEN: setRowHeight() should not be called, while resizeRowsToContents() should be called twice
+ # (once each in __recalculate_layout and replace_service_item)
+ self.assertEquals(mocked_resizeRowsToContents.call_count, 2, 'Should be called')
+ self.assertEquals(mocked_setRowHeight.call_count, 0, 'Should not be called')
+
+ @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.resizeRowsToContents')
+ @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.setRowHeight')
+ def replace_recalculate_layout_test_img(self, mocked_setRowHeight, mocked_resizeRowsToContents):
+ """
+ Test if "Max height for non-text slides..." disabled, img slides unchanged in replace_service_item & __recalc...
+ """
+ # GIVEN: A setting to adjust "Max height for non-text slides in slide controller",
+ # an image ServiceItem and a ListPreviewWidget.
+
+ # Mock Settings().value('advanced/slide max height')
+ self.mocked_Settings_obj.value.return_value = 0
+ # Mock self.viewport().width()
+ self.mocked_viewport_obj.width.return_value = 200
+ # Mock image service item
+ service_item = MagicMock()
+ service_item.is_text.return_value = False
+ service_item.get_frames.return_value = [{'title': None, 'path': None, 'image': None},
+ {'title': None, 'path': None, 'image': None}]
+ # init ListPreviewWidget and load service item
+ list_preview_widget = ListPreviewWidget(None, 1)
+ list_preview_widget.replace_service_item(service_item, 200, 0)
+ # Change viewport width before forcing a resize
+ self.mocked_viewport_obj.width.return_value = 400
+
+ # WHEN: __recalculate_layout() is called (via resizeEvent)
+ list_preview_widget.resizeEvent(None)
+ self.mocked_Settings_obj.value.return_value = None
+ list_preview_widget.resizeEvent(None)
+
+ # THEN: resizeRowsToContents() should not be called, while setRowHeight() should be called
+ # twice for each slide.
+ self.assertEquals(mocked_resizeRowsToContents.call_count, 0, 'Should not be called')
+ self.assertEquals(mocked_setRowHeight.call_count, 6, 'Should be called 3 times for each slide')
+ calls = [call(0, 200), call(1, 200), call(0, 400), call(1, 400), call(0, 400), call(1, 400)]
+ mocked_setRowHeight.assert_has_calls(calls)
+
+ @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.resizeRowsToContents')
+ @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.setRowHeight')
+ def replace_recalculate_layout_test_img_max(self, mocked_setRowHeight, mocked_resizeRowsToContents):
+ """
+ Test if "Max height for non-text slides..." enabled, img slides resized in replace_service_item & __recalc...
+ """
+ # GIVEN: A setting to adjust "Max height for non-text slides in slide controller",
+ # an image ServiceItem and a ListPreviewWidget.
+
+ # Mock Settings().value('advanced/slide max height')
+ self.mocked_Settings_obj.value.return_value = 100
+ # Mock self.viewport().width()
+ self.mocked_viewport_obj.width.return_value = 200
+ # Mock image service item
+ service_item = MagicMock()
+ service_item.is_text.return_value = False
+ service_item.get_frames.return_value = [{'title': None, 'path': None, 'image': None},
+ {'title': None, 'path': None, 'image': None}]
+ # init ListPreviewWidget and load service item
+ list_preview_widget = ListPreviewWidget(None, 1)
+ list_preview_widget.replace_service_item(service_item, 200, 0)
+ # Change viewport width before forcing a resize
+ self.mocked_viewport_obj.width.return_value = 400
+
+ # WHEN: __recalculate_layout() is called (via resizeEvent)
+ list_preview_widget.resizeEvent(None)
+
+ # THEN: resizeRowsToContents() should not be called, while setRowHeight() should be called
+ # twice for each slide.
+ self.assertEquals(mocked_resizeRowsToContents.call_count, 0, 'Should not be called')
+ self.assertEquals(mocked_setRowHeight.call_count, 4, 'Should be called twice for each slide')
+ calls = [call(0, 100), call(1, 100), call(0, 100), call(1, 100)]
+ mocked_setRowHeight.assert_has_calls(calls)
+
+ @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.resizeRowsToContents')
+ @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.setRowHeight')
+ @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.cellWidget')
+ def row_resized_test_text(self, mocked_cellWidget, mocked_setRowHeight, mocked_resizeRowsToContents):
+ """
+ Test if "Max height for non-text slides..." enabled, text-based slides not affected in row_resized.
+ """
+ # GIVEN: A setting to adjust "Max height for non-text slides in slide controller",
+ # a text ServiceItem and a ListPreviewWidget.
+
+ # Mock Settings().value('advanced/slide max height')
+ self.mocked_Settings_obj.value.return_value = 100
+ # Mock self.viewport().width()
+ self.mocked_viewport_obj.width.return_value = 200
+ # Mock text service item
+ service_item = MagicMock()
+ service_item.is_text.return_value = True
+ service_item.get_frames.return_value = [{'title': None, 'text': None, 'verseTag': None},
+ {'title': None, 'text': None, 'verseTag': None}]
+ # Mock self.cellWidget().children().setMaximumWidth()
+ mocked_cellWidget_child = MagicMock()
+ mocked_cellWidget_obj = MagicMock()
+ mocked_cellWidget_obj.children.return_value = [None, mocked_cellWidget_child]
+ mocked_cellWidget.return_value = mocked_cellWidget_obj
+ # init ListPreviewWidget and load service item
+ list_preview_widget = ListPreviewWidget(None, 1)
+ list_preview_widget.replace_service_item(service_item, 200, 0)
+
+ # WHEN: row_resized() is called
+ list_preview_widget.row_resized(0, 100, 150)
+
+ # THEN: self.cellWidget(row, 0).children()[1].setMaximumWidth() should not be called
+ self.assertEquals(mocked_cellWidget_child.setMaximumWidth.call_count, 0, 'Should not be called')
+
+ @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.resizeRowsToContents')
+ @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.setRowHeight')
+ @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.cellWidget')
+ def row_resized_test_img(self, mocked_cellWidget, mocked_setRowHeight, mocked_resizeRowsToContents):
+ """
+ Test if "Max height for non-text slides..." disabled, image-based slides not affected in row_resized.
+ """
+ # GIVEN: A setting to adjust "Max height for non-text slides in slide controller",
+ # an image ServiceItem and a ListPreviewWidget.
+
+ # Mock Settings().value('advanced/slide max height')
+ self.mocked_Settings_obj.value.return_value = 0
+ # Mock self.viewport().width()
+ self.mocked_viewport_obj.width.return_value = 200
+ # Mock image service item
+ service_item = MagicMock()
+ service_item.is_text.return_value = False
+ service_item.get_frames.return_value = [{'title': None, 'path': None, 'image': None},
+ {'title': None, 'path': None, 'image': None}]
+ # Mock self.cellWidget().children().setMaximumWidth()
+ mocked_cellWidget_child = MagicMock()
+ mocked_cellWidget_obj = MagicMock()
+ mocked_cellWidget_obj.children.return_value = [None, mocked_cellWidget_child]
+ mocked_cellWidget.return_value = mocked_cellWidget_obj
+ # init ListPreviewWidget and load service item
+ list_preview_widget = ListPreviewWidget(None, 1)
+ list_preview_widget.replace_service_item(service_item, 200, 0)
+
+ # WHEN: row_resized() is called
+ list_preview_widget.row_resized(0, 100, 150)
+ self.mocked_Settings_obj.value.return_value = None
+ list_preview_widget.row_resized(0, 100, 150)
+
+ # THEN: self.cellWidget(row, 0).children()[1].setMaximumWidth() should not be called
+ self.assertEquals(mocked_cellWidget_child.setMaximumWidth.call_count, 0, 'Should not be called')
+
+ @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.resizeRowsToContents')
+ @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.setRowHeight')
+ @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.cellWidget')
+ def row_resized_test_img_max(self, mocked_cellWidget, mocked_setRowHeight, mocked_resizeRowsToContents):
+ """
+ Test if "Max height for non-text slides..." enabled, image-based slides are scaled in row_resized.
+ """
+ # GIVEN: A setting to adjust "Max height for non-text slides in slide controller",
+ # an image ServiceItem and a ListPreviewWidget.
+
+ # Mock Settings().value('advanced/slide max height')
+ self.mocked_Settings_obj.value.return_value = 100
+ # Mock self.viewport().width()
+ self.mocked_viewport_obj.width.return_value = 200
+ # Mock image service item
+ service_item = MagicMock()
+ service_item.is_text.return_value = False
+ service_item.get_frames.return_value = [{'title': None, 'path': None, 'image': None},
+ {'title': None, 'path': None, 'image': None}]
+ # Mock self.cellWidget().children().setMaximumWidth()
+ mocked_cellWidget_child = MagicMock()
+ mocked_cellWidget_obj = MagicMock()
+ mocked_cellWidget_obj.children.return_value = [None, mocked_cellWidget_child]
+ mocked_cellWidget.return_value = mocked_cellWidget_obj
+ # init ListPreviewWidget and load service item
+ list_preview_widget = ListPreviewWidget(None, 1)
+ list_preview_widget.replace_service_item(service_item, 200, 0)
+
+ # WHEN: row_resized() is called
+ list_preview_widget.row_resized(0, 100, 150)
+
+ # THEN: self.cellWidget(row, 0).children()[1].setMaximumWidth() should be called
+ mocked_cellWidget_child.setMaximumWidth.assert_called_once_with(150)
+
+ @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.selectRow')
+ @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.scrollToItem')
+ @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.item')
+ @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.slide_count')
+ def autoscroll_test_setting_invalid(self, mocked_slide_count, mocked_item, mocked_scrollToItem, mocked_selectRow):
+ """
+ Test if 'advanced/autoscrolling' setting None or invalid, that no autoscrolling occurs on change_slide().
+ """
+ # GIVEN: A setting for autoscrolling and a ListPreviewWidget.
+ # Mock Settings().value('advanced/autoscrolling')
+ self.mocked_Settings_obj.value.return_value = None
+ # Mocked returns
+ mocked_slide_count.return_value = 1
+ mocked_item.return_value = None
+ # init ListPreviewWidget and load service item
+ list_preview_widget = ListPreviewWidget(None, 1)
+
+ # WHEN: change_slide() is called
+ list_preview_widget.change_slide(0)
+ self.mocked_Settings_obj.value.return_value = 1
+ list_preview_widget.change_slide(0)
+ self.mocked_Settings_obj.value.return_value = {'fail': 1}
+ list_preview_widget.change_slide(0)
+ self.mocked_Settings_obj.value.return_value = {'dist': 1, 'fail': 1}
+ list_preview_widget.change_slide(0)
+ self.mocked_Settings_obj.value.return_value = {'dist': 'fail', 'pos': 1}
+ list_preview_widget.change_slide(0)
+ self.mocked_Settings_obj.value.return_value = {'dist': 1, 'pos': 'fail'}
+ list_preview_widget.change_slide(0)
+
+ # THEN: no further functions should be called
+ self.assertEquals(mocked_slide_count.call_count, 0, 'Should not be called')
+ self.assertEquals(mocked_scrollToItem.call_count, 0, 'Should not be called')
+ self.assertEquals(mocked_selectRow.call_count, 0, 'Should not be called')
+ self.assertEquals(mocked_item.call_count, 0, 'Should not be called')
+
+ @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.selectRow')
+ @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.scrollToItem')
+ @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.item')
+ @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.slide_count')
+ def autoscroll_test_dist_bounds(self, mocked_slide_count, mocked_item, mocked_scrollToItem, mocked_selectRow):
+ """
+ Test if 'advanced/autoscrolling' setting asks to scroll beyond list bounds, that it does not beyond.
+ """
+ # GIVEN: A setting for autoscrolling and a ListPreviewWidget.
+ # Mock Settings().value('advanced/autoscrolling')
+ self.mocked_Settings_obj.value.return_value = {'dist': -1, 'pos': 1}
+ # Mocked returns
+ mocked_slide_count.return_value = 1
+ mocked_item.return_value = None
+ # init ListPreviewWidget and load service item
+ list_preview_widget = ListPreviewWidget(None, 1)
+
+ # WHEN: change_slide() is called
+ list_preview_widget.change_slide(0)
+ self.mocked_Settings_obj.value.return_value = {'dist': 1, 'pos': 1}
+ list_preview_widget.change_slide(0)
+
+ # THEN: no further functions should be called
+ self.assertEquals(mocked_slide_count.call_count, 3, 'Should be called')
+ self.assertEquals(mocked_scrollToItem.call_count, 2, 'Should be called')
+ self.assertEquals(mocked_selectRow.call_count, 2, 'Should be called')
+ self.assertEquals(mocked_item.call_count, 2, 'Should be called')
+ calls = [call(0, 0), call(0, 0)]
+ mocked_item.assert_has_calls(calls)
+
+ @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.selectRow')
+ @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.scrollToItem')
+ @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.item')
+ @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.slide_count')
+ def autoscroll_test_normal(self, mocked_slide_count, mocked_item, mocked_scrollToItem, mocked_selectRow):
+ """
+ Test if 'advanced/autoscrolling' setting valid, autoscrolling called as expected.
+ """
+ # GIVEN: A setting for autoscrolling and a ListPreviewWidget.
+ # Mock Settings().value('advanced/autoscrolling')
+ self.mocked_Settings_obj.value.return_value = {'dist': -1, 'pos': 1}
+ # Mocked returns
+ mocked_slide_count.return_value = 3
+ mocked_item.return_value = None
+ # init ListPreviewWidget and load service item
+ list_preview_widget = ListPreviewWidget(None, 1)
+
+ # WHEN: change_slide() is called
+ list_preview_widget.change_slide(1)
+ self.mocked_Settings_obj.value.return_value = {'dist': 0, 'pos': 1}
+ list_preview_widget.change_slide(1)
+ self.mocked_Settings_obj.value.return_value = {'dist': 1, 'pos': 1}
+ list_preview_widget.change_slide(1)
+
+ # THEN: no further functions should be called
+ self.assertEquals(mocked_slide_count.call_count, 3, 'Should be called')
+ self.assertEquals(mocked_scrollToItem.call_count, 3, 'Should be called')
+ self.assertEquals(mocked_selectRow.call_count, 3, 'Should be called')
+ self.assertEquals(mocked_item.call_count, 3, 'Should be called')
+ calls = [call(0, 0), call(1, 0), call(2, 0)]
+ mocked_item.assert_has_calls(calls)
=== removed file 'tests/interfaces/openlp_core_ui/test_listpreviewwidget.py'
--- tests/interfaces/openlp_core_ui/test_listpreviewwidget.py 2015-12-31 22:46:06 +0000
+++ tests/interfaces/openlp_core_ui/test_listpreviewwidget.py 1970-01-01 00:00:00 +0000
@@ -1,106 +0,0 @@
-# -*- coding: utf-8 -*-
-# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
-
-###############################################################################
-# OpenLP - Open Source Lyrics Projection #
-# --------------------------------------------------------------------------- #
-# Copyright (c) 2008-2016 OpenLP Developers #
-# --------------------------------------------------------------------------- #
-# This program is free software; you can redistribute it and/or modify it #
-# under the terms of the GNU General Public License as published by the Free #
-# Software Foundation; version 2 of the License. #
-# #
-# This program is distributed in the hope that it will be useful, but WITHOUT #
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
-# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
-# more details. #
-# #
-# You should have received a copy of the GNU General Public License along #
-# with this program; if not, write to the Free Software Foundation, Inc., 59 #
-# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
-###############################################################################
-"""
- Package to test the openlp.core.ui.listpreviewwidget.
-"""
-
-from unittest import TestCase
-
-from PyQt5 import QtGui, QtWidgets
-
-from openlp.core.common import Registry
-from openlp.core.lib import ServiceItem
-from openlp.core.ui import listpreviewwidget
-from tests.interfaces import MagicMock, patch
-from tests.utils.osdinteraction import read_service_from_file
-from tests.helpers.testmixin import TestMixin
-
-
-class TestListPreviewWidget(TestCase, TestMixin):
-
- def setUp(self):
- """
- Create the UI.
- """
- Registry.create()
- self.setup_application()
- self.main_window = QtWidgets.QMainWindow()
- self.image = QtGui.QImage(1, 1, QtGui.QImage.Format_RGB32)
- self.image_manager = MagicMock()
- self.image_manager.get_image.return_value = self.image
- Registry().register('image_manager', self.image_manager)
- self.preview_widget = listpreviewwidget.ListPreviewWidget(self.main_window, 2)
-
- def tearDown(self):
- """
- Delete all the C++ objects at the end so that we don't have a segfault.
- """
- del self.preview_widget
- del self.main_window
-
- def initial_slide_count_test(self):
- """
- Test the initial slide count .
- """
- # GIVEN: A new ListPreviewWidget instance.
- # WHEN: No SlideItem has been added yet.
- # THEN: The count of items should be zero.
- self.assertEqual(self.preview_widget.slide_count(), 0, 'The slide list should be empty.')
-
- def initial_slide_number_test(self):
- """
- Test the initial current slide number.
- """
- # GIVEN: A new ListPreviewWidget instance.
- # WHEN: No SlideItem has been added yet.
- # THEN: The number of the current item should be -1.
- self.assertEqual(self.preview_widget.current_slide_number(), -1, 'The slide number should be -1.')
-
- def replace_service_item_test(self):
- """
- Test item counts and current number with a service item.
- """
- # GIVEN: A ServiceItem with two frames.
- service_item = ServiceItem(None)
- service = read_service_from_file('serviceitem_image_3.osj')
- with patch('os.path.exists'):
- service_item.set_from_service(service[0])
- # WHEN: Added to the preview widget.
- self.preview_widget.replace_service_item(service_item, 1, 1)
- # THEN: The slide count and number should fit.
- self.assertEqual(self.preview_widget.slide_count(), 2, 'The slide count should be 2.')
- self.assertEqual(self.preview_widget.current_slide_number(), 1, 'The current slide number should be 1.')
-
- def change_slide_test(self):
- """
- Test the change_slide method.
- """
- # GIVEN: A ServiceItem with two frames content.
- service_item = ServiceItem(None)
- service = read_service_from_file('serviceitem_image_3.osj')
- with patch('os.path.exists'):
- service_item.set_from_service(service[0])
- # WHEN: Added to the preview widget and switched to the second frame.
- self.preview_widget.replace_service_item(service_item, 1, 0)
- self.preview_widget.change_slide(1)
- # THEN: The current_slide_number should reflect the change.
- self.assertEqual(self.preview_widget.current_slide_number(), 1, 'The current slide number should be 1.')
=== added file 'tests/interfaces/openlp_core_ui_lib/test_listpreviewwidget.py'
--- tests/interfaces/openlp_core_ui_lib/test_listpreviewwidget.py 1970-01-01 00:00:00 +0000
+++ tests/interfaces/openlp_core_ui_lib/test_listpreviewwidget.py 2016-04-22 19:42:45 +0000
@@ -0,0 +1,106 @@
+# -*- coding: utf-8 -*-
+# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
+
+###############################################################################
+# OpenLP - Open Source Lyrics Projection #
+# --------------------------------------------------------------------------- #
+# Copyright (c) 2008-2016 OpenLP Developers #
+# --------------------------------------------------------------------------- #
+# This program is free software; you can redistribute it and/or modify it #
+# under the terms of the GNU General Public License as published by the Free #
+# Software Foundation; version 2 of the License. #
+# #
+# This program is distributed in the hope that it will be useful, but WITHOUT #
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
+# more details. #
+# #
+# You should have received a copy of the GNU General Public License along #
+# with this program; if not, write to the Free Software Foundation, Inc., 59 #
+# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
+###############################################################################
+"""
+ Package to test the openlp.core.ui.lib.listpreviewwidget.
+"""
+
+from unittest import TestCase
+
+from PyQt5 import QtGui, QtWidgets
+
+from openlp.core.common import Registry
+from openlp.core.lib import ServiceItem
+from openlp.core.ui.lib import ListWidgetWithDnD, ListPreviewWidget
+from tests.interfaces import MagicMock, patch
+from tests.utils.osdinteraction import read_service_from_file
+from tests.helpers.testmixin import TestMixin
+
+
+class TestListPreviewWidget(TestCase, TestMixin):
+
+ def setUp(self):
+ """
+ Create the UI.
+ """
+ Registry.create()
+ self.setup_application()
+ self.main_window = QtWidgets.QMainWindow()
+ self.image = QtGui.QImage(1, 1, QtGui.QImage.Format_RGB32)
+ self.image_manager = MagicMock()
+ self.image_manager.get_image.return_value = self.image
+ Registry().register('image_manager', self.image_manager)
+ self.preview_widget = ListPreviewWidget(self.main_window, 2)
+
+ def tearDown(self):
+ """
+ Delete all the C++ objects at the end so that we don't have a segfault.
+ """
+ del self.preview_widget
+ del self.main_window
+
+ def initial_slide_count_test(self):
+ """
+ Test the initial slide count .
+ """
+ # GIVEN: A new ListPreviewWidget instance.
+ # WHEN: No SlideItem has been added yet.
+ # THEN: The count of items should be zero.
+ self.assertEqual(self.preview_widget.slide_count(), 0, 'The slide list should be empty.')
+
+ def initial_slide_number_test(self):
+ """
+ Test the initial current slide number.
+ """
+ # GIVEN: A new ListPreviewWidget instance.
+ # WHEN: No SlideItem has been added yet.
+ # THEN: The number of the current item should be -1.
+ self.assertEqual(self.preview_widget.current_slide_number(), -1, 'The slide number should be -1.')
+
+ def replace_service_item_test(self):
+ """
+ Test item counts and current number with a service item.
+ """
+ # GIVEN: A ServiceItem with two frames.
+ service_item = ServiceItem(None)
+ service = read_service_from_file('serviceitem_image_3.osj')
+ with patch('os.path.exists'):
+ service_item.set_from_service(service[0])
+ # WHEN: Added to the preview widget.
+ self.preview_widget.replace_service_item(service_item, 1, 1)
+ # THEN: The slide count and number should fit.
+ self.assertEqual(self.preview_widget.slide_count(), 2, 'The slide count should be 2.')
+ self.assertEqual(self.preview_widget.current_slide_number(), 1, 'The current slide number should be 1.')
+
+ def change_slide_test(self):
+ """
+ Test the change_slide method.
+ """
+ # GIVEN: A ServiceItem with two frames content.
+ service_item = ServiceItem(None)
+ service = read_service_from_file('serviceitem_image_3.osj')
+ with patch('os.path.exists'):
+ service_item.set_from_service(service[0])
+ # WHEN: Added to the preview widget and switched to the second frame.
+ self.preview_widget.replace_service_item(service_item, 1, 0)
+ self.preview_widget.change_slide(1)
+ # THEN: The current_slide_number should reflect the change.
+ self.assertEqual(self.preview_widget.current_slide_number(), 1, 'The current slide number should be 1.')
Follow ups