Add a custom widget for editing and selecting paths. Implemented in OpenLP, with the exception of the import wizards, as I have other plans for refactoring these!

lp:~phill-ridout/openlp/path_edit (revision 2737)
[SUCCESS] https://ci.openlp.io/job/Branch-01-Pull/2009/
[SUCCESS] https://ci.openlp.io/job/Branch-02-Functional-Tests/1919/
[SUCCESS] https://ci.openlp.io/job/Branch-03-Interface-Tests/1855/
[SUCCESS] https://ci.openlp.io/job/Branch-04a-Code_Analysis/1235/
[SUCCESS] https://ci.openl...

bzr-revno: 2742
This commit is contained in:
Phill 2017-05-23 05:58:49 +01:00 committed by Tim Bentley
commit 533bef159a
18 changed files with 635 additions and 346 deletions

View File

@ -442,7 +442,7 @@ def check_binary_exists(program_path):
"""
Function that checks whether a binary exists.
:param program_path:The full path to the binary to check.
:param program_path: The full path to the binary to check.
:return: program output to be parsed
"""
log.debug('testing program_path: {text}'.format(text=program_path))

View File

@ -164,7 +164,7 @@ class ThemeXML(object):
jsn = get_text_file_string(json_file)
jsn = json.loads(jsn)
self.expand_json(jsn)
self.background_filename = None
self.background_filename = ''
def expand_json(self, var, prev=None):
"""

View File

@ -25,13 +25,13 @@ The :mod:`advancedtab` provides an advanced settings facility.
from datetime import datetime, timedelta
import logging
import os
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
from openlp.core.common import AppLocation, Settings, SlideLimits, UiStrings, translate
from openlp.core.lib import SettingsTab, build_icon
from openlp.core.common.languagemanager import format_time
from openlp.core.lib import SettingsTab, build_icon
from openlp.core.ui.lib import PathEdit, PathType
log = logging.getLogger(__name__)
@ -153,32 +153,17 @@ class AdvancedTab(SettingsTab):
self.data_directory_group_box.setObjectName('data_directory_group_box')
self.data_directory_layout = QtWidgets.QFormLayout(self.data_directory_group_box)
self.data_directory_layout.setObjectName('data_directory_layout')
self.data_directory_current_label = QtWidgets.QLabel(self.data_directory_group_box)
self.data_directory_current_label.setObjectName('data_directory_current_label')
self.data_directory_label = QtWidgets.QLabel(self.data_directory_group_box)
self.data_directory_label.setObjectName('data_directory_label')
self.data_directory_new_label = QtWidgets.QLabel(self.data_directory_group_box)
self.data_directory_new_label.setObjectName('data_directory_current_label')
self.new_data_directory_edit = QtWidgets.QLineEdit(self.data_directory_group_box)
self.new_data_directory_edit.setObjectName('new_data_directory_edit')
self.new_data_directory_edit.setReadOnly(True)
self.data_directory_path_edit = PathEdit(self.data_directory_group_box, path_type=PathType.Directories,
default_path=AppLocation.get_directory(AppLocation.DataDir))
self.data_directory_layout.addRow(self.data_directory_new_label, self.data_directory_path_edit)
self.new_data_directory_has_files_label = QtWidgets.QLabel(self.data_directory_group_box)
self.new_data_directory_has_files_label.setObjectName('new_data_directory_has_files_label')
self.new_data_directory_has_files_label.setWordWrap(True)
self.data_directory_browse_button = QtWidgets.QToolButton(self.data_directory_group_box)
self.data_directory_browse_button.setObjectName('data_directory_browse_button')
self.data_directory_browse_button.setIcon(build_icon(':/general/general_open.png'))
self.data_directory_default_button = QtWidgets.QToolButton(self.data_directory_group_box)
self.data_directory_default_button.setObjectName('data_directory_default_button')
self.data_directory_default_button.setIcon(build_icon(':/general/general_revert.png'))
self.data_directory_cancel_button = QtWidgets.QToolButton(self.data_directory_group_box)
self.data_directory_cancel_button.setObjectName('data_directory_cancel_button')
self.data_directory_cancel_button.setIcon(build_icon(':/general/general_delete.png'))
self.new_data_directory_label_layout = QtWidgets.QHBoxLayout()
self.new_data_directory_label_layout.setObjectName('new_data_directory_label_layout')
self.new_data_directory_label_layout.addWidget(self.new_data_directory_edit)
self.new_data_directory_label_layout.addWidget(self.data_directory_browse_button)
self.new_data_directory_label_layout.addWidget(self.data_directory_default_button)
self.data_directory_copy_check_layout = QtWidgets.QHBoxLayout()
self.data_directory_copy_check_layout.setObjectName('data_directory_copy_check_layout')
self.data_directory_copy_check_box = QtWidgets.QCheckBox(self.data_directory_group_box)
@ -186,8 +171,6 @@ class AdvancedTab(SettingsTab):
self.data_directory_copy_check_layout.addWidget(self.data_directory_copy_check_box)
self.data_directory_copy_check_layout.addStretch()
self.data_directory_copy_check_layout.addWidget(self.data_directory_cancel_button)
self.data_directory_layout.addRow(self.data_directory_current_label, self.data_directory_label)
self.data_directory_layout.addRow(self.data_directory_new_label, self.new_data_directory_label_layout)
self.data_directory_layout.addRow(self.data_directory_copy_check_layout)
self.data_directory_layout.addRow(self.new_data_directory_has_files_label)
self.left_layout.addWidget(self.data_directory_group_box)
@ -239,8 +222,7 @@ class AdvancedTab(SettingsTab):
self.service_name_edit.textChanged.connect(self.update_service_name_example)
self.service_name_revert_button.clicked.connect(self.on_service_name_revert_button_clicked)
self.alternate_rows_check_box.toggled.connect(self.on_alternate_rows_check_box_toggled)
self.data_directory_browse_button.clicked.connect(self.on_data_directory_browse_button_clicked)
self.data_directory_default_button.clicked.connect(self.on_data_directory_default_button_clicked)
self.data_directory_path_edit.pathChanged.connect(self.on_data_directory_path_edit_path_changed)
self.data_directory_cancel_button.clicked.connect(self.on_data_directory_cancel_button_clicked)
self.data_directory_copy_check_box.toggled.connect(self.on_data_directory_copy_check_box_toggled)
self.end_slide_radio_button.clicked.connect(self.on_end_slide_button_clicked)
@ -317,12 +299,7 @@ class AdvancedTab(SettingsTab):
self.service_name_example_label.setText(translate('OpenLP.AdvancedTab', 'Example:'))
self.hide_mouse_group_box.setTitle(translate('OpenLP.AdvancedTab', 'Mouse Cursor'))
self.hide_mouse_check_box.setText(translate('OpenLP.AdvancedTab', 'Hide mouse cursor when over display window'))
self.data_directory_current_label.setText(translate('OpenLP.AdvancedTab', 'Current path:'))
self.data_directory_new_label.setText(translate('OpenLP.AdvancedTab', 'Custom path:'))
self.data_directory_browse_button.setToolTip(translate('OpenLP.AdvancedTab',
'Browse for new data file location.'))
self.data_directory_default_button.setToolTip(
translate('OpenLP.AdvancedTab', 'Set the data location to the default.'))
self.data_directory_new_label.setText(translate('OpenLP.AdvancedTab', 'Path:'))
self.data_directory_cancel_button.setText(translate('OpenLP.AdvancedTab', 'Cancel'))
self.data_directory_cancel_button.setToolTip(
translate('OpenLP.AdvancedTab', 'Cancel OpenLP data directory location change.'))
@ -396,8 +373,7 @@ class AdvancedTab(SettingsTab):
self.new_data_directory_has_files_label.hide()
self.data_directory_cancel_button.hide()
# Since data location can be changed, make sure the path is present.
self.current_data_path = AppLocation.get_data_path()
self.data_directory_label.setText(os.path.abspath(self.current_data_path))
self.data_directory_path_edit.path = AppLocation.get_data_path()
# Don't allow data directory move if running portable.
if settings.value('advanced/is portable'):
self.data_directory_group_box.hide()
@ -509,24 +485,10 @@ class AdvancedTab(SettingsTab):
self.service_name_edit.setText(UiStrings().DefaultServiceName)
self.service_name_edit.setFocus()
def on_data_directory_browse_button_clicked(self):
def on_data_directory_path_edit_path_changed(self, new_data_path):
"""
Browse for a new data directory location.
"""
old_root_path = str(self.data_directory_label.text())
# Get the new directory location.
new_data_path = QtWidgets.QFileDialog.getExistingDirectory(self, translate('OpenLP.AdvancedTab',
'Select Data Directory Location'),
old_root_path,
options=QtWidgets.QFileDialog.ShowDirsOnly)
# Set the new data path.
if new_data_path:
new_data_path = os.path.normpath(new_data_path)
if self.current_data_path.lower() == new_data_path.lower():
self.on_data_directory_cancel_button_clicked()
return
else:
return
# Make sure they want to change the data.
answer = QtWidgets.QMessageBox.question(self, translate('OpenLP.AdvancedTab', 'Confirm Data Directory Change'),
translate('OpenLP.AdvancedTab', 'Are you sure you want to change the '
@ -537,42 +499,14 @@ class AdvancedTab(SettingsTab):
QtWidgets.QMessageBox.No),
QtWidgets.QMessageBox.No)
if answer != QtWidgets.QMessageBox.Yes:
self.data_directory_path_edit.path = AppLocation.get_data_path()
return
# Check if data already exists here.
self.check_data_overwrite(new_data_path)
# Save the new location.
self.main_window.set_new_data_path(new_data_path)
self.new_data_directory_edit.setText(new_data_path)
self.data_directory_cancel_button.show()
def on_data_directory_default_button_clicked(self):
"""
Re-set the data directory location to the 'default' location.
"""
new_data_path = AppLocation.get_directory(AppLocation.DataDir)
if self.current_data_path.lower() != new_data_path.lower():
# Make sure they want to change the data location back to the
# default.
answer = QtWidgets.QMessageBox.question(self, translate('OpenLP.AdvancedTab', 'Reset Data Directory'),
translate('OpenLP.AdvancedTab', 'Are you sure you want to change '
'the location of the OpenLP data '
'directory to the default location?'
'\n\nThis location will be used '
'after OpenLP is closed.'),
QtWidgets.QMessageBox.StandardButtons(QtWidgets.QMessageBox.Yes |
QtWidgets.QMessageBox.No),
QtWidgets.QMessageBox.No)
if answer != QtWidgets.QMessageBox.Yes:
return
self.check_data_overwrite(new_data_path)
# Save the new location.
self.main_window.set_new_data_path(new_data_path)
self.new_data_directory_edit.setText(os.path.abspath(new_data_path))
self.data_directory_cancel_button.show()
else:
# We cancel the change in case user changed their mind.
self.on_data_directory_cancel_button_clicked()
def on_data_directory_copy_check_box_toggled(self):
"""
Copy existing data when you change your data directory.
@ -589,7 +523,6 @@ class AdvancedTab(SettingsTab):
Check if there's already data in the target directory.
"""
test_path = os.path.join(data_path, 'songs')
self.data_directory_copy_check_box.show()
if os.path.exists(test_path):
self.data_exists = True
# Check is they want to replace existing data.
@ -603,6 +536,7 @@ class AdvancedTab(SettingsTab):
QtWidgets.QMessageBox.StandardButtons(QtWidgets.QMessageBox.Yes |
QtWidgets.QMessageBox.No),
QtWidgets.QMessageBox.No)
self.data_directory_copy_check_box.show()
if answer == QtWidgets.QMessageBox.Yes:
self.data_directory_copy_check_box.setChecked(True)
self.new_data_directory_has_files_label.show()
@ -618,7 +552,7 @@ class AdvancedTab(SettingsTab):
"""
Cancel the data directory location change
"""
self.new_data_directory_edit.clear()
self.data_directory_path_edit.path = AppLocation.get_data_path()
self.data_directory_copy_check_box.setChecked(False)
self.main_window.set_new_data_path(None)
self.main_window.set_copy_data(False)

View File

@ -27,8 +27,8 @@ import logging
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, build_icon
from openlp.core.ui.lib.colorbutton import ColorButton
from openlp.core.lib import SettingsTab, ScreenList
from openlp.core.ui.lib import ColorButton, PathEdit
log = logging.getLogger(__name__)
@ -172,20 +172,8 @@ class GeneralTab(SettingsTab):
self.logo_layout.setObjectName('logo_layout')
self.logo_file_label = QtWidgets.QLabel(self.logo_group_box)
self.logo_file_label.setObjectName('logo_file_label')
self.logo_file_edit = QtWidgets.QLineEdit(self.logo_group_box)
self.logo_file_edit.setObjectName('logo_file_edit')
self.logo_browse_button = QtWidgets.QToolButton(self.logo_group_box)
self.logo_browse_button.setObjectName('logo_browse_button')
self.logo_browse_button.setIcon(build_icon(':/general/general_open.png'))
self.logo_revert_button = QtWidgets.QToolButton(self.logo_group_box)
self.logo_revert_button.setObjectName('logo_revert_button')
self.logo_revert_button.setIcon(build_icon(':/general/general_revert.png'))
self.logo_file_layout = QtWidgets.QHBoxLayout()
self.logo_file_layout.setObjectName('logo_file_layout')
self.logo_file_layout.addWidget(self.logo_file_edit)
self.logo_file_layout.addWidget(self.logo_browse_button)
self.logo_file_layout.addWidget(self.logo_revert_button)
self.logo_layout.addRow(self.logo_file_label, self.logo_file_layout)
self.logo_file_path_edit = PathEdit(self.logo_group_box, default_path=':/graphics/openlp-splash-screen.png')
self.logo_layout.addRow(self.logo_file_label, self.logo_file_path_edit)
self.logo_color_label = QtWidgets.QLabel(self.logo_group_box)
self.logo_color_label.setObjectName('logo_color_label')
self.logo_color_button = ColorButton(self.logo_group_box)
@ -196,8 +184,6 @@ class GeneralTab(SettingsTab):
self.logo_layout.addRow(self.logo_hide_on_startup_check_box)
self.right_layout.addWidget(self.logo_group_box)
self.logo_color_button.colorChanged.connect(self.on_logo_background_color_changed)
self.logo_browse_button.clicked.connect(self.on_logo_browse_button_clicked)
self.logo_revert_button.clicked.connect(self.on_logo_revert_button_clicked)
# Application Settings
self.settings_group_box = QtWidgets.QGroupBox(self.right_column)
self.settings_group_box.setObjectName('settings_group_box')
@ -254,8 +240,6 @@ class GeneralTab(SettingsTab):
self.logo_group_box.setTitle(translate('OpenLP.GeneralTab', 'Logo'))
self.logo_color_label.setText(UiStrings().BackgroundColorColon)
self.logo_file_label.setText(translate('OpenLP.GeneralTab', 'Logo file:'))
self.logo_browse_button.setToolTip(translate('OpenLP.GeneralTab', 'Browse for an image file to display.'))
self.logo_revert_button.setToolTip(translate('OpenLP.GeneralTab', 'Revert to the default OpenLP logo.'))
self.logo_hide_on_startup_check_box.setText(translate('OpenLP.GeneralTab', 'Don\'t show logo on startup'))
self.check_for_updates_check_box.setText(translate('OpenLP.GeneralTab', 'Check for updates to OpenLP'))
self.settings_group_box.setTitle(translate('OpenLP.GeneralTab', 'Application Settings'))
@ -282,6 +266,9 @@ class GeneralTab(SettingsTab):
self.audio_group_box.setTitle(translate('OpenLP.GeneralTab', 'Background Audio'))
self.start_paused_check_box.setText(translate('OpenLP.GeneralTab', 'Start background audio paused'))
self.repeat_list_check_box.setText(translate('OpenLP.GeneralTab', 'Repeat track list'))
self.logo_file_path_edit.dialog_caption = dialog_caption = translate('OpenLP.AdvancedTab', 'Select Logo File')
self.logo_file_path_edit.filters = '{text};;{names} (*)'.format(
text=get_images_filter(), names=UiStrings().AllFiles)
def load(self):
"""
@ -304,7 +291,7 @@ class GeneralTab(SettingsTab):
self.auto_open_check_box.setChecked(settings.value('auto open'))
self.show_splash_check_box.setChecked(settings.value('show splash'))
self.logo_background_color = settings.value('logo background color')
self.logo_file_edit.setText(settings.value('logo file'))
self.logo_file_path_edit.path = settings.value('logo file')
self.logo_hide_on_startup_check_box.setChecked(settings.value('logo hide on startup'))
self.logo_color_button.color = self.logo_background_color
self.check_for_updates_check_box.setChecked(settings.value('update check'))
@ -338,7 +325,7 @@ class GeneralTab(SettingsTab):
settings.setValue('auto open', self.auto_open_check_box.isChecked())
settings.setValue('show splash', self.show_splash_check_box.isChecked())
settings.setValue('logo background color', self.logo_background_color)
settings.setValue('logo file', self.logo_file_edit.text())
settings.setValue('logo file', self.logo_file_path_edit.path)
settings.setValue('logo hide on startup', self.logo_hide_on_startup_check_box.isChecked())
settings.setValue('update check', self.check_for_updates_check_box.isChecked())
settings.setValue('save prompt', self.save_check_service_check_box.isChecked())
@ -404,25 +391,6 @@ class GeneralTab(SettingsTab):
"""
self.display_changed = True
def on_logo_browse_button_clicked(self):
"""
Select the logo file
"""
file_filters = '{text};;{names} (*.*)'.format(text=get_images_filter(), names=UiStrings().AllFiles)
filename, filter_used = QtWidgets.QFileDialog.getOpenFileName(self,
translate('OpenLP.AdvancedTab', 'Open File'), '',
file_filters)
if filename:
self.logo_file_edit.setText(filename)
self.logo_file_edit.setFocus()
def on_logo_revert_button_clicked(self):
"""
Revert the logo file back to the default setting.
"""
self.logo_file_edit.setText(':/graphics/openlp-splash-screen.png')
self.logo_file_edit.setFocus()
def on_logo_background_color_changed(self, color):
"""
Select the background color for logo.

View File

@ -21,14 +21,16 @@
###############################################################################
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
from .listwidgetwithdnd import ListWidgetWithDnD
from .mediadockmanager import MediaDockManager
from .dockwidget import OpenLPDockWidget
from .toolbar import OpenLPToolbar
from .wizard import OpenLPWizard, WizardStrings
from .pathedit import PathEdit, PathType
from .spelltextedit import SpellTextEdit
from .treewidgetwithdnd import TreeWidgetWithDnD
__all__ = ['ColorButton', 'ListPreviewWidget', 'ListWidgetWithDnD', 'OpenLPToolbar', 'OpenLPDockWidget',
'OpenLPWizard', 'WizardStrings', 'MediaDockManager', 'ListPreviewWidget', 'SpellTextEdit']
__all__ = ['ColorButton', 'ListPreviewWidget', 'ListWidgetWithDnD', 'MediaDockManager', 'OpenLPDockWidget',
'OpenLPToolbar', 'OpenLPWizard', 'PathEdit', 'PathType', 'SpellTextEdit', 'TreeWidgetWithDnD',
'WizardStrings']

View File

@ -39,7 +39,7 @@ class ColorButton(QtWidgets.QPushButton):
"""
Initialise the ColorButton
"""
super(ColorButton, self).__init__()
super().__init__(parent)
self.parent = parent
self.change_color('#ffffff')
self.setToolTip(translate('OpenLP.ColorButton', 'Click to select a color.'))

205
openlp/core/ui/lib/pathedit.py Executable file
View File

@ -0,0 +1,205 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2017 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 #
###############################################################################
from enum import Enum
import os.path
from PyQt5 import QtCore, QtWidgets
from openlp.core.common import UiStrings, translate
from openlp.core.lib import build_icon
class PathType(Enum):
Files = 1
Directories = 2
class PathEdit(QtWidgets.QWidget):
"""
The :class:`~openlp.core.ui.lib.pathedit.PathEdit` class subclasses QWidget to create a custom widget for use when
a file or directory needs to be selected.
"""
pathChanged = QtCore.pyqtSignal(str)
def __init__(self, parent=None, path_type=PathType.Files, default_path=None, dialog_caption=None, show_revert=True):
"""
Initalise the PathEdit widget
:param parent: The parent of the widget. This is just passed to the super method.
:type parent: QWidget or None
:param dialog_caption: Used to customise the caption in the QFileDialog.
:param dialog_caption: str
:param default_path: The default path. This is set as the path when the revert button is clicked
:type default_path: str
:param show_revert: Used to determin if the 'revert button' should be visible.
:type show_revert: bool
:return: None
:rtype: None
"""
super().__init__(parent)
self.default_path = default_path
self.dialog_caption = dialog_caption
self._path_type = path_type
self._path = None
self.filters = '{all_files} (*)'.format(all_files=UiStrings().AllFiles)
self._setup(show_revert)
def _setup(self, show_revert):
"""
Set up the widget
:param show_revert: Show or hide the revert button
:type show_revert: bool
:return: None
:rtype: None
"""
widget_layout = QtWidgets.QHBoxLayout()
widget_layout.setContentsMargins(0, 0, 0, 0)
self.line_edit = QtWidgets.QLineEdit(self)
self.line_edit.setText(self._path)
widget_layout.addWidget(self.line_edit)
self.browse_button = QtWidgets.QToolButton(self)
self.browse_button.setIcon(build_icon(':/general/general_open.png'))
widget_layout.addWidget(self.browse_button)
self.revert_button = QtWidgets.QToolButton(self)
self.revert_button.setIcon(build_icon(':/general/general_revert.png'))
self.revert_button.setVisible(show_revert)
widget_layout.addWidget(self.revert_button)
self.setLayout(widget_layout)
# Signals and Slots
self.browse_button.clicked.connect(self.on_browse_button_clicked)
self.revert_button.clicked.connect(self.on_revert_button_clicked)
self.line_edit.editingFinished.connect(self.on_line_edit_editing_finished)
self.update_button_tool_tips()
@property
def path(self):
"""
A property getter method to return the selected path.
:return: The selected path
:rtype: str
"""
return self._path
@path.setter
def path(self, path):
"""
A Property setter method to set the selected path
:param path: The path to set the widget to
:type path: str
"""
self._path = path
self.line_edit.setText(path)
self.line_edit.setToolTip(path)
@property
def path_type(self):
"""
A property getter method to return the path_type. Path type allows you to sepecify if the user is restricted to
selecting a file or directory.
:return: The type selected
:rtype: Enum of PathEdit
"""
return self._path_type
@path_type.setter
def path_type(self, path_type):
"""
A Property setter method to set the path type
:param path: The type of path to select
:type path: Enum of PathEdit
"""
self._path_type = path_type
self.update_button_tool_tips()
def update_button_tool_tips(self):
"""
Called to update the tooltips on the buttons. This is changing path types, and when the widget is initalised
:return: None
"""
if self._path_type == PathType.Directories:
self.browse_button.setToolTip(translate('OpenLP.PathEdit', 'Browse for directory.'))
self.revert_button.setToolTip(translate('OpenLP.PathEdit', 'Revert to default directory.'))
else:
self.browse_button.setToolTip(translate('OpenLP.PathEdit', 'Browse for file.'))
self.revert_button.setToolTip(translate('OpenLP.PathEdit', 'Revert to default file.'))
def on_browse_button_clicked(self):
"""
A handler to handle a click on the browse button.
Show the QFileDialog and process the input from the user
:return: None
"""
caption = self.dialog_caption
path = ''
if self._path_type == PathType.Directories:
if not caption:
caption = translate('OpenLP.PathEdit', 'Select Directory')
path = QtWidgets.QFileDialog.getExistingDirectory(self, caption,
self._path, QtWidgets.QFileDialog.ShowDirsOnly)
elif self._path_type == PathType.Files:
if not caption:
caption = self.dialog_caption = translate('OpenLP.PathEdit', 'Select File')
path, filter_used = QtWidgets.QFileDialog.getOpenFileName(self, caption, self._path, self.filters)
if path:
path = os.path.normpath(path)
self.on_new_path(path)
def on_revert_button_clicked(self):
"""
A handler to handle a click on the revert button.
Set the new path to the value of the default_path instance variable.
:return: None
"""
self.on_new_path(self.default_path)
def on_line_edit_editing_finished(self):
"""
A handler to handle when the line edit has finished being edited.
:return: None
"""
self.on_new_path(self.line_edit.text())
def on_new_path(self, path):
"""
A method called to validate and set a new path.
Emits the pathChanged Signal
:param path: The new path
:type path: str
:return: None
"""
if self._path != path:
self.path = path
self.pathChanged.emit(path)

View File

@ -69,10 +69,16 @@ class ThemeForm(QtWidgets.QWizard, Ui_ThemeWizard, RegistryProperties):
self.video_color_button.colorChanged.connect(self.on_video_color_changed)
self.gradient_start_button.colorChanged.connect(self.on_gradient_start_color_changed)
self.gradient_end_button.colorChanged.connect(self.on_gradient_end_color_changed)
self.image_browse_button.clicked.connect(self.on_image_browse_button_clicked)
self.image_file_edit.editingFinished.connect(self.on_image_file_edit_editing_finished)
self.video_browse_button.clicked.connect(self.on_video_browse_button_clicked)
self.video_file_edit.editingFinished.connect(self.on_video_file_edit_editing_finished)
self.image_path_edit.filters = \
'{name};;{text} (*)'.format(name=get_images_filter(), text=UiStrings().AllFiles)
self.image_path_edit.pathChanged.connect(self.on_image_path_edit_path_changed)
# TODO: Should work
visible_formats = '({name})'.format(name='; '.join(VIDEO_EXT))
actual_formats = '({name})'.format(name=' '.join(VIDEO_EXT))
video_filter = '{trans} {visible} {actual}'.format(trans=translate('OpenLP', 'Video Files'),
visible=visible_formats, actual=actual_formats)
self.video_path_edit.filters = '{video};;{ui} (*)'.format(video=video_filter, ui=UiStrings().AllFiles)
self.video_path_edit.pathChanged.connect(self.on_video_path_edit_path_changed)
self.main_color_button.colorChanged.connect(self.on_main_color_changed)
self.outline_color_button.colorChanged.connect(self.on_outline_color_changed)
self.shadow_color_button.colorChanged.connect(self.on_shadow_color_changed)
@ -112,7 +118,8 @@ class ThemeForm(QtWidgets.QWizard, Ui_ThemeWizard, RegistryProperties):
self.background_page.registerField('color', self.color_button)
self.background_page.registerField('gradient_start', self.gradient_start_button)
self.background_page.registerField('gradient_end', self.gradient_end_button)
self.background_page.registerField('background_image', self.image_file_edit)
self.background_page.registerField('background_image', self.image_path_edit,
'path', self.image_path_edit.pathChanged)
self.background_page.registerField('gradient', self.gradient_combo_box)
self.main_area_page.registerField('main_color_button', self.main_color_button)
self.main_area_page.registerField('main_size_spin_box', self.main_size_spin_box)
@ -309,11 +316,11 @@ class ThemeForm(QtWidgets.QWizard, Ui_ThemeWizard, RegistryProperties):
self.setField('background_type', 1)
elif self.theme.background_type == BackgroundType.to_string(BackgroundType.Image):
self.image_color_button.color = self.theme.background_border_color
self.image_file_edit.setText(self.theme.background_filename)
self.image_path_edit.path = self.theme.background_filename
self.setField('background_type', 2)
elif self.theme.background_type == BackgroundType.to_string(BackgroundType.Video):
self.video_color_button.color = self.theme.background_border_color
self.video_file_edit.setText(self.theme.background_filename)
self.video_path_edit.path = self.theme.background_filename
self.setField('background_type', 4)
elif self.theme.background_type == BackgroundType.to_string(BackgroundType.Transparent):
self.setField('background_type', 3)
@ -441,48 +448,20 @@ class ThemeForm(QtWidgets.QWizard, Ui_ThemeWizard, RegistryProperties):
"""
self.theme.background_end_color = color
def on_image_browse_button_clicked(self):
def on_image_path_edit_path_changed(self, filename):
"""
Background Image button pushed.
"""
images_filter = get_images_filter()
images_filter = '{name};;{text} (*.*)'.format(name=images_filter, text=UiStrings().AllFiles)
filename, filter_used = QtWidgets.QFileDialog.getOpenFileName(
self, translate('OpenLP.ThemeWizard', 'Select Image'),
self.image_file_edit.text(), images_filter)
if filename:
self.theme.background_filename = filename
self.theme.background_filename = filename
self.set_background_page_values()
def on_image_file_edit_editing_finished(self):
"""
Background image path edited
"""
self.theme.background_filename = str(self.image_file_edit.text())
def on_video_browse_button_clicked(self):
def on_video_path_edit_path_changed(self, filename):
"""
Background video button pushed.
"""
# TODO: Should work
visible_formats = '({name})'.format(name='; '.join(VIDEO_EXT))
actual_formats = '({name})'.format(name=' '.join(VIDEO_EXT))
video_filter = '{trans} {visible} {actual}'.format(trans=translate('OpenLP', 'Video Files'),
visible=visible_formats, actual=actual_formats)
video_filter = '{video};;{ui} (*.*)'.format(video=video_filter, ui=UiStrings().AllFiles)
filename, filter_used = QtWidgets.QFileDialog.getOpenFileName(
self, translate('OpenLP.ThemeWizard', 'Select Video'),
self.video_file_edit.text(), video_filter)
if filename:
self.theme.background_filename = filename
self.theme.background_filename = filename
self.set_background_page_values()
def on_video_file_edit_editing_finished(self):
"""
Background video path edited
"""
self.theme.background_filename = str(self.image_file_edit.text())
def on_main_color_changed(self, color):
"""
Set the main colour value

View File

@ -28,7 +28,7 @@ from openlp.core.common import UiStrings, translate, is_macosx
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
from openlp.core.ui.lib import ColorButton, PathEdit
class Ui_ThemeWizard(object):
@ -116,16 +116,10 @@ class Ui_ThemeWizard(object):
self.image_layout.addRow(self.image_color_label, self.image_color_button)
self.image_label = QtWidgets.QLabel(self.image_widget)
self.image_label.setObjectName('image_label')
self.image_file_layout = QtWidgets.QHBoxLayout()
self.image_file_layout.setObjectName('image_file_layout')
self.image_file_edit = QtWidgets.QLineEdit(self.image_widget)
self.image_file_edit.setObjectName('image_file_edit')
self.image_file_layout.addWidget(self.image_file_edit)
self.image_browse_button = QtWidgets.QToolButton(self.image_widget)
self.image_browse_button.setObjectName('image_browse_button')
self.image_browse_button.setIcon(build_icon(':/general/general_open.png'))
self.image_file_layout.addWidget(self.image_browse_button)
self.image_layout.addRow(self.image_label, self.image_file_layout)
self.image_path_edit = PathEdit(self.image_widget,
dialog_caption=translate('OpenLP.ThemeWizard', 'Select Image'),
show_revert=False)
self.image_layout.addRow(self.image_label, self.image_path_edit)
self.image_layout.setItem(2, QtWidgets.QFormLayout.LabelRole, self.spacer)
self.background_stack.addWidget(self.image_widget)
self.transparent_widget = QtWidgets.QWidget(self.background_page)
@ -147,16 +141,10 @@ class Ui_ThemeWizard(object):
self.video_layout.addRow(self.video_color_label, self.video_color_button)
self.video_label = QtWidgets.QLabel(self.video_widget)
self.video_label.setObjectName('video_label')
self.video_file_layout = QtWidgets.QHBoxLayout()
self.video_file_layout.setObjectName('video_file_layout')
self.video_file_edit = QtWidgets.QLineEdit(self.video_widget)
self.video_file_edit.setObjectName('video_file_edit')
self.video_file_layout.addWidget(self.video_file_edit)
self.video_browse_button = QtWidgets.QToolButton(self.video_widget)
self.video_browse_button.setObjectName('video_browse_button')
self.video_browse_button.setIcon(build_icon(':/general/general_open.png'))
self.video_file_layout.addWidget(self.video_browse_button)
self.video_layout.addRow(self.video_label, self.video_file_layout)
self.video_path_edit = PathEdit(self.video_widget,
dialog_caption=translate('OpenLP.ThemeWizard', 'Select Video'),
show_revert=False)
self.video_layout.addRow(self.video_label, self.video_path_edit)
self.video_layout.setItem(2, QtWidgets.QFormLayout.LabelRole, self.spacer)
self.background_stack.addWidget(self.video_widget)
theme_wizard.addPage(self.background_page)

View File

@ -135,7 +135,6 @@ class BibleImportForm(OpenLPWizard):
Add the bible import specific wizard pages.
"""
# Select Page
self.spacers = []
self.select_page = QtWidgets.QWizardPage()
self.select_page.setObjectName('SelectPage')
self.select_page_layout = QtWidgets.QVBoxLayout(self.select_page)
@ -148,8 +147,8 @@ class BibleImportForm(OpenLPWizard):
self.format_combo_box.addItems(['', '', '', '', '', '', ''])
self.format_combo_box.setObjectName('FormatComboBox')
self.format_layout.addRow(self.format_label, self.format_combo_box)
self.spacers.append(QtWidgets.QSpacerItem(10, 0, QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Minimum))
self.format_layout.setItem(1, QtWidgets.QFormLayout.LabelRole, self.spacers[-1])
self.spacer = QtWidgets.QSpacerItem(10, 0, QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Minimum)
self.format_layout.setItem(1, QtWidgets.QFormLayout.LabelRole, self.spacer)
self.select_page_layout.addLayout(self.format_layout)
self.select_stack = QtWidgets.QStackedLayout()
self.select_stack.setObjectName('SelectStack')
@ -171,8 +170,7 @@ class BibleImportForm(OpenLPWizard):
self.osis_browse_button.setObjectName('OsisBrowseButton')
self.osis_file_layout.addWidget(self.osis_browse_button)
self.osis_layout.addRow(self.osis_file_label, self.osis_file_layout)
self.spacers.append(QtWidgets.QSpacerItem(10, 0, QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Minimum))
self.osis_layout.setItem(1, QtWidgets.QFormLayout.LabelRole, self.spacers[-1])
self.osis_layout.setItem(1, QtWidgets.QFormLayout.LabelRole, self.spacer)
self.select_stack.addWidget(self.osis_widget)
self.csv_widget = QtWidgets.QWidget(self.select_page)
self.csv_widget.setObjectName('CsvWidget')
@ -205,8 +203,7 @@ class BibleImportForm(OpenLPWizard):
self.csv_verses_button.setObjectName('CsvVersesButton')
self.csv_verses_layout.addWidget(self.csv_verses_button)
self.csv_layout.addRow(self.csv_verses_label, self.csv_verses_layout)
self.spacers.append(QtWidgets.QSpacerItem(10, 0, QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Minimum))
self.csv_layout.setItem(2, QtWidgets.QFormLayout.LabelRole, self.spacers[-1])
self.csv_layout.setItem(3, QtWidgets.QFormLayout.LabelRole, self.spacer)
self.select_stack.addWidget(self.csv_widget)
self.open_song_widget = QtWidgets.QWidget(self.select_page)
self.open_song_widget.setObjectName('OpenSongWidget')
@ -226,8 +223,7 @@ class BibleImportForm(OpenLPWizard):
self.open_song_browse_button.setObjectName('OpenSongBrowseButton')
self.open_song_file_layout.addWidget(self.open_song_browse_button)
self.open_song_layout.addRow(self.open_song_file_label, self.open_song_file_layout)
self.spacers.append(QtWidgets.QSpacerItem(10, 0, QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Minimum))
self.open_song_layout.setItem(1, QtWidgets.QFormLayout.LabelRole, self.spacers[-1])
self.open_song_layout.setItem(1, QtWidgets.QFormLayout.LabelRole, self.spacer)
self.select_stack.addWidget(self.open_song_widget)
self.web_tab_widget = QtWidgets.QTabWidget(self.select_page)
self.web_tab_widget.setObjectName('WebTabWidget')
@ -304,8 +300,7 @@ class BibleImportForm(OpenLPWizard):
self.zefania_browse_button.setObjectName('ZefaniaBrowseButton')
self.zefania_file_layout.addWidget(self.zefania_browse_button)
self.zefania_layout.addRow(self.zefania_file_label, self.zefania_file_layout)
self.spacers.append(QtWidgets.QSpacerItem(10, 0, QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Minimum))
self.zefania_layout.setItem(1, QtWidgets.QFormLayout.LabelRole, self.spacers[-1])
self.zefania_layout.setItem(5, QtWidgets.QFormLayout.LabelRole, self.spacer)
self.select_stack.addWidget(self.zefania_widget)
self.sword_widget = QtWidgets.QWidget(self.select_page)
self.sword_widget.setObjectName('SwordWidget')
@ -386,8 +381,7 @@ class BibleImportForm(OpenLPWizard):
self.wordproject_browse_button.setObjectName('WordProjectBrowseButton')
self.wordproject_file_layout.addWidget(self.wordproject_browse_button)
self.wordproject_layout.addRow(self.wordproject_file_label, self.wordproject_file_layout)
self.spacers.append(QtWidgets.QSpacerItem(10, 0, QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Minimum))
self.wordproject_layout.setItem(1, QtWidgets.QFormLayout.LabelRole, self.spacers[-1])
self.wordproject_layout.setItem(5, QtWidgets.QFormLayout.LabelRole, self.spacer)
self.select_stack.addWidget(self.wordproject_widget)
self.select_page_layout.addLayout(self.select_stack)
self.addPage(self.select_page)
@ -505,8 +499,7 @@ class BibleImportForm(OpenLPWizard):
self.csv_verses_label.minimumSizeHint().width(),
self.open_song_file_label.minimumSizeHint().width(),
self.zefania_file_label.minimumSizeHint().width())
for spacer in self.spacers:
spacer.changeSize(label_width, 0, QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
self.spacer.changeSize(label_width, 0, QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
def validateCurrentPage(self):
"""

View File

@ -25,6 +25,7 @@ from PyQt5 import QtGui, QtWidgets
from openlp.core.common import Settings, UiStrings, translate
from openlp.core.lib import SettingsTab, build_icon
from openlp.core.lib.ui import critical_error_message_box
from openlp.core.ui.lib import PathEdit
from openlp.plugins.presentations.lib.pdfcontroller import PdfController
@ -88,26 +89,15 @@ class PresentationTab(SettingsTab):
self.pdf_program_check_box = QtWidgets.QCheckBox(self.pdf_group_box)
self.pdf_program_check_box.setObjectName('pdf_program_check_box')
self.pdf_layout.addRow(self.pdf_program_check_box)
self.pdf_program_path_layout = QtWidgets.QHBoxLayout()
self.pdf_program_path_layout.setObjectName('pdf_program_path_layout')
self.pdf_program_path = QtWidgets.QLineEdit(self.pdf_group_box)
self.pdf_program_path.setObjectName('pdf_program_path')
self.pdf_program_path.setReadOnly(True)
self.pdf_program_path.setPalette(self.get_grey_text_palette(True))
self.pdf_program_path_layout.addWidget(self.pdf_program_path)
self.pdf_program_browse_button = QtWidgets.QToolButton(self.pdf_group_box)
self.pdf_program_browse_button.setObjectName('pdf_program_browse_button')
self.pdf_program_browse_button.setIcon(build_icon(':/general/general_open.png'))
self.pdf_program_browse_button.setEnabled(False)
self.pdf_program_path_layout.addWidget(self.pdf_program_browse_button)
self.pdf_layout.addRow(self.pdf_program_path_layout)
self.program_path_edit = PathEdit(self.pdf_group_box)
self.pdf_layout.addRow(self.program_path_edit)
self.left_layout.addWidget(self.pdf_group_box)
self.left_layout.addStretch()
self.right_column.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred)
self.right_layout.addStretch()
# Signals and slots
self.pdf_program_browse_button.clicked.connect(self.on_pdf_program_browse_button_clicked)
self.pdf_program_check_box.clicked.connect(self.on_pdf_program_check_box_clicked)
self.program_path_edit.pathChanged.connect(self.on_program_path_edit_path_changed)
self.pdf_program_check_box.clicked.connect(self.program_path_edit.setEnabled)
def retranslateUi(self):
"""
@ -132,6 +122,8 @@ class PresentationTab(SettingsTab):
'(This may fix PowerPoint scaling issues in Windows 8 and 10)'))
self.pdf_program_check_box.setText(
translate('PresentationPlugin.PresentationTab', 'Use given full path for mudraw or ghostscript binary:'))
self.program_path_edit.dialog_caption = translate('PresentationPlugin.PresentationTab',
'Select mudraw or ghostscript binary')
def set_controller_text(self, checkbox, controller):
if checkbox.isEnabled():
@ -161,11 +153,10 @@ class PresentationTab(SettingsTab):
# load pdf-program settings
enable_pdf_program = Settings().value(self.settings_section + '/enable_pdf_program')
self.pdf_program_check_box.setChecked(enable_pdf_program)
self.pdf_program_path.setPalette(self.get_grey_text_palette(not enable_pdf_program))
self.pdf_program_browse_button.setEnabled(enable_pdf_program)
self.program_path_edit.setEnabled(enable_pdf_program)
pdf_program = Settings().value(self.settings_section + '/pdf_program')
if pdf_program:
self.pdf_program_path.setText(pdf_program)
self.program_path_edit.path = pdf_program
def save(self):
"""
@ -201,7 +192,7 @@ class PresentationTab(SettingsTab):
Settings().setValue(setting_key, self.ppt_window_check_box.checkState())
changed = True
# Save pdf-settings
pdf_program = self.pdf_program_path.text()
pdf_program = self.program_path_edit.path
enable_pdf_program = self.pdf_program_check_box.checkState()
# If the given program is blank disable using the program
if pdf_program == '':
@ -228,42 +219,12 @@ class PresentationTab(SettingsTab):
checkbox.setEnabled(controller.is_available())
self.set_controller_text(checkbox, controller)
def on_pdf_program_browse_button_clicked(self):
def on_program_path_edit_path_changed(self, filename):
"""
Select the mudraw or ghostscript binary that should be used.
"""
filename, filter_used = QtWidgets.QFileDialog.getOpenFileName(
self, translate('PresentationPlugin.PresentationTab', 'Select mudraw or ghostscript binary.'),
self.pdf_program_path.text())
if filename:
program_type = PdfController.process_check_binary(filename)
if not program_type:
if not PdfController.process_check_binary(filename):
critical_error_message_box(UiStrings().Error,
translate('PresentationPlugin.PresentationTab',
'The program is not ghostscript or mudraw which is required.'))
else:
self.pdf_program_path.setText(filename)
def on_pdf_program_check_box_clicked(self, checked):
"""
When checkbox for manual entering pdf-program is clicked,
enable or disable the textbox for the programpath and the browse-button.
:param checked: If the box is checked or not.
"""
self.pdf_program_path.setPalette(self.get_grey_text_palette(not checked))
self.pdf_program_browse_button.setEnabled(checked)
def get_grey_text_palette(self, greyed):
"""
Returns a QPalette with greyed out text as used for placeholderText.
:param greyed: Determines whether the palette should be grayed.
:return: The created palette.
"""
palette = QtGui.QPalette()
color = self.palette().color(QtGui.QPalette.Active, QtGui.QPalette.Text)
if greyed:
color.setAlpha(128)
palette.setColor(QtGui.QPalette.Active, QtGui.QPalette.Text, color)
return palette

View File

@ -1,4 +1,4 @@
# -*- coding: utf-8 -*-
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
###############################################################################

View File

@ -25,6 +25,7 @@ from PyQt5 import QtCore, QtWidgets
from openlp.core.common import translate
from openlp.core.lib import build_icon
from openlp.core.lib.ui import create_button_box
from openlp.core.ui.lib import PathEdit, PathType
class Ui_SongUsageDetailDialog(object):
@ -68,20 +69,13 @@ class Ui_SongUsageDetailDialog(object):
self.file_horizontal_layout.setSpacing(8)
self.file_horizontal_layout.setContentsMargins(8, 8, 8, 8)
self.file_horizontal_layout.setObjectName('file_horizontal_layout')
self.file_line_edit = QtWidgets.QLineEdit(self.file_group_box)
self.file_line_edit.setObjectName('file_line_edit')
self.file_line_edit.setReadOnly(True)
self.file_horizontal_layout.addWidget(self.file_line_edit)
self.save_file_push_button = QtWidgets.QPushButton(self.file_group_box)
self.save_file_push_button.setMaximumWidth(self.save_file_push_button.size().height())
self.save_file_push_button.setIcon(build_icon(':/general/general_open.png'))
self.save_file_push_button.setObjectName('save_file_push_button')
self.file_horizontal_layout.addWidget(self.save_file_push_button)
self.report_path_edit = PathEdit(self.file_group_box, path_type = PathType.Directories, show_revert=False)
self.file_horizontal_layout.addWidget(self.report_path_edit)
self.vertical_layout.addWidget(self.file_group_box)
self.button_box = create_button_box(song_usage_detail_dialog, 'button_box', ['cancel', 'ok'])
self.vertical_layout.addWidget(self.button_box)
self.retranslateUi(song_usage_detail_dialog)
self.save_file_push_button.clicked.connect(song_usage_detail_dialog.define_output_location)
self.report_path_edit.pathChanged.connect(song_usage_detail_dialog.on_report_path_edit_path_changed)
def retranslateUi(self, song_usage_detail_dialog):
"""

View File

@ -54,25 +54,20 @@ class SongUsageDetailForm(QtWidgets.QDialog, Ui_SongUsageDetailDialog, RegistryP
"""
self.from_date_calendar.setSelectedDate(Settings().value(self.plugin.settings_section + '/from date'))
self.to_date_calendar.setSelectedDate(Settings().value(self.plugin.settings_section + '/to date'))
self.file_line_edit.setText(Settings().value(self.plugin.settings_section + '/last directory export'))
self.report_path_edit.path = Settings().value(self.plugin.settings_section + '/last directory export')
def define_output_location(self):
def on_report_path_edit_path_changed(self, file_path):
"""
Triggered when the Directory selection button is clicked
"""
path = QtWidgets.QFileDialog.getExistingDirectory(
self, translate('SongUsagePlugin.SongUsageDetailForm', 'Output File Location'),
Settings().value(self.plugin.settings_section + '/last directory export'))
if path:
Settings().setValue(self.plugin.settings_section + '/last directory export', path)
self.file_line_edit.setText(path)
Settings().setValue(self.plugin.settings_section + '/last directory export', file_path)
def accept(self):
"""
Ok was triggered so lets save the data and run the report
"""
log.debug('accept')
path = self.file_line_edit.text()
path = self.report_path_edit.path
if not path:
self.main_window.error_message(
translate('SongUsagePlugin.SongUsageDetailForm', 'Output Path Not Selected'),

View File

@ -32,60 +32,21 @@ class TestThemeManager(TestCase):
"""
Test the functions in the ThemeManager Class
"""
def test_select_image_file_dialog_cancelled(self):
"""
Test the select image file dialog when the user presses cancel
"""
# GIVEN: An instance of Theme Form and mocked QFileDialog which returns an empty string (similating a user
# pressing cancel)
with patch('openlp.core.ui.ThemeForm._setup'),\
patch('openlp.core.ui.themeform.get_images_filter',
**{'return_value': 'Image Files (*.bmp; *.gif)(*.bmp *.gif)'}),\
patch('openlp.core.ui.themeform.QtWidgets.QFileDialog.getOpenFileName',
**{'return_value': ('', '')}) as mocked_get_open_file_name,\
patch('openlp.core.ui.themeform.translate', **{'return_value': 'Translated String'}),\
patch('openlp.core.ui.ThemeForm.set_background_page_values') as mocked_set_background_page_values:
instance = ThemeForm(None)
mocked_image_file_edit = MagicMock()
mocked_image_file_edit.text.return_value = '/original_path/file.ext'
instance.image_file_edit = mocked_image_file_edit
def setUp(self):
with patch('openlp.core.ui.ThemeForm._setup'):
self.instance = ThemeForm(None)
# WHEN: on_image_browse_button is clicked
instance.on_image_browse_button_clicked()
def test_on_image_path_edit_path_changed(self):
"""
Test the `image_path_edit.pathChanged` handler
"""
# GIVEN: An instance of Theme Form
with patch.object(self.instance, 'set_background_page_values') as mocked_set_background_page_values:
self.instance.theme = MagicMock()
# THEN: The QFileDialog getOpenFileName and set_background_page_values moethods should have been called
# with known arguments
mocked_get_open_file_name.assert_called_once_with(instance, 'Translated String', '/original_path/file.ext',
'Image Files (*.bmp; *.gif)(*.bmp *.gif);;'
'All Files (*.*)')
# WHEN: `on_image_path_edit_path_changed` is clicked
self.instance.on_image_path_edit_path_changed('/new/pat.h')
# THEN: The theme background file should be set and `set_background_page_values` should have been called
self.assertEqual(self.instance.theme.background_filename, '/new/pat.h')
mocked_set_background_page_values.assert_called_once_with()
def test_select_image_file_dialog_new_file(self):
"""
Test the select image file dialog when the user presses ok
"""
# GIVEN: An instance of Theme Form and mocked QFileDialog which returns a file path
with patch('openlp.core.ui.ThemeForm._setup'),\
patch('openlp.core.ui.themeform.get_images_filter',
**{'return_value': 'Image Files (*.bmp; *.gif)(*.bmp *.gif)'}),\
patch('openlp.core.ui.themeform.QtWidgets.QFileDialog.getOpenFileName',
**{'return_value': ('/new_path/file.ext', '')}) as mocked_get_open_file_name,\
patch('openlp.core.ui.themeform.translate', **{'return_value': 'Translated String'}),\
patch('openlp.core.ui.ThemeForm.set_background_page_values') as mocked_background_page_values:
instance = ThemeForm(None)
mocked_image_file_edit = MagicMock()
mocked_image_file_edit.text.return_value = '/original_path/file.ext'
instance.image_file_edit = mocked_image_file_edit
instance.theme = MagicMock()
# WHEN: on_image_browse_button is clicked
instance.on_image_browse_button_clicked()
# THEN: The QFileDialog getOpenFileName and set_background_page_values moethods should have been called
# with known arguments and theme.background_filename should be set
mocked_get_open_file_name.assert_called_once_with(instance, 'Translated String', '/original_path/file.ext',
'Image Files (*.bmp; *.gif)(*.bmp *.gif);;'
'All Files (*.*)')
self.assertEqual(instance.theme.background_filename, '/new_path/file.ext',
'theme.background_filename should be set to the path that the file dialog returns')
mocked_background_page_values.assert_called_once_with()

View File

@ -20,12 +20,12 @@
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
"""
This module contains tests for the openlp.core.lib.filedialog module
This module contains tests for the openlp.core.ui.lib.colorbutton module
"""
from unittest import TestCase
from unittest.mock import MagicMock, call, patch
from openlp.core.ui.lib.colorbutton import ColorButton
from openlp.core.ui.lib import ColorButton
class TestColorDialog(TestCase):
@ -148,11 +148,10 @@ class TestColorDialog(TestCase):
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')
self.assertFalse(self.mocked_change_color.called,
'change_color should not have been called with an invalid color')
self.assertFalse(self.mocked_color_changed.emit.called,
'colorChange signal should not have been emitted with an invalid color')
def test_on_clicked_same_color(self):
"""
@ -171,12 +170,10 @@ class TestColorDialog(TestCase):
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')
self.assertFalse(self.mocked_change_color.called,
'change_color should not have been called when the color has not changed')
self.assertFalse(self.mocked_color_changed.emit.called,
'colorChange signal should not have been emitted when the color has not changed')
def test_on_clicked_new_color(self):
"""

View File

@ -0,0 +1,311 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2017 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.ui.lib.pathedit module
"""
from unittest import TestCase
from PyQt5 import QtWidgets
from openlp.core.ui.lib import PathEdit, PathType
from unittest.mock import MagicMock, PropertyMock, patch
class TestPathEdit(TestCase):
"""
Test the :class:`~openlp.core.lib.pathedit.PathEdit` class
"""
def setUp(self):
with patch('openlp.core.ui.lib.pathedit.PathEdit._setup'):
self.widget = PathEdit()
def test_path_getter(self):
"""
Test the `path` property getter.
"""
# GIVEN: An instance of PathEdit with the `_path` instance variable set
self.widget._path = 'getter/test/pat.h'
# WHEN: Reading the `path` property
# THEN: The value that we set should be returned
self.assertEqual(self.widget.path, 'getter/test/pat.h')
def test_path_setter(self):
"""
Test the `path` property setter.
"""
# GIVEN: An instance of the PathEdit object and a mocked `line_edit`
self.widget.line_edit = MagicMock()
# WHEN: Writing to the `path` property
self.widget.path = 'setter/test/pat.h'
# THEN: The `_path` instance variable should be set with the test data. The `line_edit` text and tooltip
# should have also been set.
self.assertEqual(self.widget._path, 'setter/test/pat.h')
self.widget.line_edit.setToolTip.assert_called_once_with('setter/test/pat.h')
self.widget.line_edit.setText.assert_called_once_with('setter/test/pat.h')
def test_path_type_getter(self):
"""
Test the `path_type` property getter.
"""
# GIVEN: An instance of PathEdit
# WHEN: Reading the `path` property
# THEN: The default value should be returned
self.assertEqual(self.widget.path_type, PathType.Files)
def test_path_type_setter(self):
"""
Test the `path_type` property setter.
"""
# GIVEN: An instance of the PathEdit object and a mocked `update_button_tool_tips` method.
with patch.object(self.widget, 'update_button_tool_tips') as mocked_update_button_tool_tips:
# WHEN: Writing to a different value than default to the `path_type` property
self.widget.path_type = PathType.Directories
# THEN: The `_path_type` instance variable should be set with the test data and not the default. The
# update_button_tool_tips should have been called.
self.assertEqual(self.widget._path_type, PathType.Directories)
mocked_update_button_tool_tips.assert_called_once_with()
def test_update_button_tool_tips_directories(self):
"""
Test the `update_button_tool_tips` method.
"""
# GIVEN: An instance of PathEdit with the `path_type` set to `Directories`
self.widget.browse_button = MagicMock()
self.widget.revert_button = MagicMock()
self.widget._path_type = PathType.Directories
# WHEN: Calling update_button_tool_tips
self.widget.update_button_tool_tips()
self.widget.browse_button.setToolTip.assert_called_once_with('Browse for directory.')
self.widget.revert_button.setToolTip.assert_called_once_with('Revert to default directory.')
def test_update_button_tool_tips_files(self):
"""
Test the `update_button_tool_tips` method.
"""
# GIVEN: An instance of PathEdit with the `path_type` set to `Files`
self.widget.browse_button = MagicMock()
self.widget.revert_button = MagicMock()
self.widget._path_type = PathType.Files
# WHEN: Calling update_button_tool_tips
self.widget.update_button_tool_tips()
self.widget.browse_button.setToolTip.assert_called_once_with('Browse for file.')
self.widget.revert_button.setToolTip.assert_called_once_with('Revert to default file.')
def test_on_browse_button_clicked_directory(self):
"""
Test the `browse_button` `clicked` handler on_browse_button_clicked when the `path_type` is set to Directories.
"""
# GIVEN: An instance of PathEdit with the `path_type` set to `Directories` and a mocked
# QFileDialog.getExistingDirectory
with patch('openlp.core.ui.lib.pathedit.QtWidgets.QFileDialog.getExistingDirectory', return_value='') as \
mocked_get_existing_directory, \
patch('openlp.core.ui.lib.pathedit.QtWidgets.QFileDialog.getOpenFileName') as \
mocked_get_open_file_name, \
patch('openlp.core.ui.lib.pathedit.os.path.normpath') as mocked_normpath:
self.widget._path_type = PathType.Directories
self.widget._path = 'test/path/'
# WHEN: Calling on_browse_button_clicked
self.widget.on_browse_button_clicked()
# THEN: The FileDialog.getExistingDirectory should have been called with the default caption
mocked_get_existing_directory.assert_called_once_with(self.widget, 'Select Directory', 'test/path/',
QtWidgets.QFileDialog.ShowDirsOnly)
self.assertFalse(mocked_get_open_file_name.called)
self.assertFalse(mocked_normpath.called)
def test_on_browse_button_clicked_directory_custom_caption(self):
"""
Test the `browse_button` `clicked` handler on_browse_button_clicked when the `path_type` is set to Directories,
and `dialog_caption` is set.
"""
# GIVEN: An instance of PathEdit with the `path_type` set to `Directories` and a mocked
# QFileDialog.getExistingDirectory with `default_caption` set.
with patch('openlp.core.ui.lib.pathedit.QtWidgets.QFileDialog.getExistingDirectory', return_value='') as \
mocked_get_existing_directory, \
patch('openlp.core.ui.lib.pathedit.QtWidgets.QFileDialog.getOpenFileName') as \
mocked_get_open_file_name, \
patch('openlp.core.ui.lib.pathedit.os.path.normpath') as mocked_normpath:
self.widget._path_type = PathType.Directories
self.widget._path = 'test/path/'
self.widget.dialog_caption = 'Directory Caption'
# WHEN: Calling on_browse_button_clicked
self.widget.on_browse_button_clicked()
# THEN: The FileDialog.getExistingDirectory should have been called with the custom caption
mocked_get_existing_directory.assert_called_once_with(self.widget, 'Directory Caption', 'test/path/',
QtWidgets.QFileDialog.ShowDirsOnly)
self.assertFalse(mocked_get_open_file_name.called)
self.assertFalse(mocked_normpath.called)
def test_on_browse_button_clicked_file(self):
"""
Test the `browse_button` `clicked` handler on_browse_button_clicked when the `path_type` is set to Files.
"""
# GIVEN: An instance of PathEdit with the `path_type` set to `Files` and a mocked QFileDialog.getOpenFileName
with patch('openlp.core.ui.lib.pathedit.QtWidgets.QFileDialog.getExistingDirectory') as \
mocked_get_existing_directory, \
patch('openlp.core.ui.lib.pathedit.QtWidgets.QFileDialog.getOpenFileName', return_value=('', '')) as \
mocked_get_open_file_name, \
patch('openlp.core.ui.lib.pathedit.os.path.normpath') as mocked_normpath:
self.widget._path_type = PathType.Files
self.widget._path = 'test/pat.h'
# WHEN: Calling on_browse_button_clicked
self.widget.on_browse_button_clicked()
# THEN: The FileDialog.getOpenFileName should have been called with the default caption
mocked_get_open_file_name.assert_called_once_with(self.widget, 'Select File', 'test/pat.h',
self.widget.filters)
self.assertFalse(mocked_get_existing_directory.called)
self.assertFalse(mocked_normpath.called)
def test_on_browse_button_clicked_file_custom_caption(self):
"""
Test the `browse_button` `clicked` handler on_browse_button_clicked when the `path_type` is set to Files and
`dialog_caption` is set.
"""
# GIVEN: An instance of PathEdit with the `path_type` set to `Files` and a mocked QFileDialog.getOpenFileName
# with `default_caption` set.
with patch('openlp.core.ui.lib.pathedit.QtWidgets.QFileDialog.getExistingDirectory') as \
mocked_get_existing_directory, \
patch('openlp.core.ui.lib.pathedit.QtWidgets.QFileDialog.getOpenFileName', return_value=('', '')) as \
mocked_get_open_file_name, \
patch('openlp.core.ui.lib.pathedit.os.path.normpath') as mocked_normpath:
self.widget._path_type = PathType.Files
self.widget._path = 'test/pat.h'
self.widget.dialog_caption = 'File Caption'
# WHEN: Calling on_browse_button_clicked
self.widget.on_browse_button_clicked()
# THEN: The FileDialog.getOpenFileName should have been called with the custom caption
mocked_get_open_file_name.assert_called_once_with(self.widget, 'File Caption', 'test/pat.h',
self.widget.filters)
self.assertFalse(mocked_get_existing_directory.called)
self.assertFalse(mocked_normpath.called)
def test_on_browse_button_clicked_user_cancels(self):
"""
Test the `browse_button` `clicked` handler on_browse_button_clicked when the user cancels the FileDialog (an
empty str is returned)
"""
# GIVEN: An instance of PathEdit with a mocked QFileDialog.getOpenFileName which returns an empty str for the
# file path.
with patch('openlp.core.ui.lib.pathedit.QtWidgets.QFileDialog.getOpenFileName', return_value=('', '')) as \
mocked_get_open_file_name, \
patch('openlp.core.ui.lib.pathedit.os.path.normpath') as mocked_normpath:
# WHEN: Calling on_browse_button_clicked
self.widget.on_browse_button_clicked()
# THEN: normpath should not have been called
self.assertTrue(mocked_get_open_file_name.called)
self.assertFalse(mocked_normpath.called)
def test_on_browse_button_clicked_user_accepts(self):
"""
Test the `browse_button` `clicked` handler on_browse_button_clicked when the user accepts the FileDialog (a path
is returned)
"""
# GIVEN: An instance of PathEdit with a mocked QFileDialog.getOpenFileName which returns a str for the file
# path.
with patch('openlp.core.ui.lib.pathedit.QtWidgets.QFileDialog.getOpenFileName',
return_value=('/test/pat.h', '')) as mocked_get_open_file_name, \
patch('openlp.core.ui.lib.pathedit.os.path.normpath') as mocked_normpath, \
patch.object(self.widget, 'on_new_path'):
# WHEN: Calling on_browse_button_clicked
self.widget.on_browse_button_clicked()
# THEN: normpath and `on_new_path` should have been called
self.assertTrue(mocked_get_open_file_name.called)
mocked_normpath.assert_called_once_with('/test/pat.h')
self.assertTrue(self.widget.on_new_path.called)
def test_on_revert_button_clicked(self):
"""
Test that the default path is set as the path when the `revert_button.clicked` handler is called.
"""
# GIVEN: An instance of PathEdit with a mocked `on_new_path`, and the `default_path` set.
with patch.object(self.widget, 'on_new_path') as mocked_on_new_path:
self.widget.default_path = '/default/pat.h'
# WHEN: Calling `on_revert_button_clicked`
self.widget.on_revert_button_clicked()
# THEN: on_new_path should have been called with the default path
mocked_on_new_path.assert_called_once_with('/default/pat.h')
def test_on_line_edit_editing_finished(self):
"""
Test that the new path is set as the path when the `line_edit.editingFinished` handler is called.
"""
# GIVEN: An instance of PathEdit with a mocked `line_edit` and `on_new_path`.
with patch.object(self.widget, 'on_new_path') as mocked_on_new_path:
self.widget.line_edit = MagicMock(**{'text.return_value': '/test/pat.h'})
# WHEN: Calling `on_line_edit_editing_finished`
self.widget.on_line_edit_editing_finished()
# THEN: on_new_path should have been called with the path enetered in `line_edit`
mocked_on_new_path.assert_called_once_with('/test/pat.h')
def test_on_new_path_no_change(self):
"""
Test `on_new_path` when called with a path that is the same as the existing path.
"""
# GIVEN: An instance of PathEdit with a test path and mocked `pathChanged` signal
with patch('openlp.core.ui.lib.pathedit.PathEdit.path', new_callable=PropertyMock):
self.widget._path = '/old/test/pat.h'
self.widget.pathChanged = MagicMock()
# WHEN: Calling `on_new_path` with the same path as the existing path
self.widget.on_new_path('/old/test/pat.h')
# THEN: The `pathChanged` signal should not be emitted
self.assertFalse(self.widget.pathChanged.emit.called)
def test_on_new_path_change(self):
"""
Test `on_new_path` when called with a path that is the different to the existing path.
"""
# GIVEN: An instance of PathEdit with a test path and mocked `pathChanged` signal
with patch('openlp.core.ui.lib.pathedit.PathEdit.path', new_callable=PropertyMock):
self.widget._path = '/old/test/pat.h'
self.widget.pathChanged = MagicMock()
# WHEN: Calling `on_new_path` with the a new path
self.widget.on_new_path('/new/test/pat.h')
# THEN: The `pathChanged` signal should be emitted
self.widget.pathChanged.emit.assert_called_once_with('/new/test/pat.h')

View File

@ -28,11 +28,12 @@ from unittest.mock import MagicMock, patch
from PyQt5 import QtWidgets
from openlp.core.common import Registry
from openlp.plugins.bibles.forms import bibleimportform
from openlp.plugins.bibles.forms.bibleimportform import BibleImportForm, PYSWORD_AVAILABLE
from tests.helpers.testmixin import TestMixin
@skip('One of the QFormLayouts in the BibleImportForm is causing a segfault')
class TestBibleImportForm(TestCase, TestMixin):
"""
Test the BibleImportForm class
@ -46,9 +47,9 @@ class TestBibleImportForm(TestCase, TestMixin):
self.setup_application()
self.main_window = QtWidgets.QMainWindow()
Registry().register('main_window', self.main_window)
bibleimportform.PYSWORD_AVAILABLE = False
PYSWORD_AVAILABLE = False
self.mocked_manager = MagicMock()
self.form = bibleimportform.BibleImportForm(self.main_window, self.mocked_manager, MagicMock())
self.form = BibleImportForm(self.main_window, self.mocked_manager, MagicMock())
def tearDown(self):
"""