Merge lp:~phill-ridout/openlp/path_edit into lp:openlp

Proposed by Phill
Status: Merged
Merged at revision: 2742
Proposed branch: lp:~phill-ridout/openlp/path_edit
Merge into: lp:openlp
Diff against target: 1499 lines (+635/-346)
18 files modified
openlp/core/common/__init__.py (+1/-1)
openlp/core/lib/theme.py (+1/-1)
openlp/core/ui/advancedtab.py (+12/-78)
openlp/core/ui/generaltab.py (+9/-41)
openlp/core/ui/lib/__init__.py (+8/-6)
openlp/core/ui/lib/colorbutton.py (+1/-1)
openlp/core/ui/lib/pathedit.py (+205/-0)
openlp/core/ui/themeform.py (+18/-39)
openlp/core/ui/themewizard.py (+9/-21)
openlp/plugins/bibles/forms/bibleimportform.py (+8/-15)
openlp/plugins/presentations/lib/presentationtab.py (+12/-51)
openlp/plugins/presentations/presentationplugin.py (+1/-1)
openlp/plugins/songusage/forms/songusagedetaildialog.py (+4/-10)
openlp/plugins/songusage/forms/songusagedetailform.py (+4/-9)
tests/functional/openlp_core_ui/test_themeform.py (+17/-56)
tests/functional/openlp_core_ui_lib/test_color_button.py (+10/-13)
tests/functional/openlp_core_ui_lib/test_path_edit.py (+311/-0)
tests/interfaces/openlp_plugins/bibles/forms/test_bibleimportform.py (+4/-3)
To merge this branch: bzr merge lp:~phill-ridout/openlp/path_edit
Reviewer Review Type Date Requested Status
Tim Bentley Approve
Tomas Groth Approve
Review via email: mp+324434@code.launchpad.net

This proposal supersedes a proposal from 2017-05-22.

Description of the change

To post a comment you must log in.
Revision history for this message
Tim Bentley (trb143) wrote : Posted in a previous version of this proposal

You tracking head as you have conflicts!

review: Needs Fixing
Revision history for this message
Phill (phill-ridout) wrote : Posted in a previous version of this proposal

I had merged with trunk, but forgot to update trunk!

Revision history for this message
Tim Bentley (trb143) wrote : Posted in a previous version of this proposal

Looks good

review: Approve
Revision history for this message
Tomas Groth (tomasgroth) wrote : Posted in a previous version of this proposal

Just tested the selection of custom pdf-bin, and the mask "*.*" causes issues since it filters out all files that does not contain a "."
So the all-files mask should maybe just be "*"?

review: Needs Fixing
Revision history for this message
Tim Bentley (trb143) wrote : Posted in a previous version of this proposal

Approved

review: Approve
Revision history for this message
Tomas Groth (tomasgroth) :
review: Approve
Revision history for this message
Tim Bentley (trb143) wrote :

Approved

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'openlp/core/common/__init__.py'
2--- openlp/core/common/__init__.py 2017-05-15 10:24:28 +0000
3+++ openlp/core/common/__init__.py 2017-05-22 19:57:32 +0000
4@@ -442,7 +442,7 @@
5 """
6 Function that checks whether a binary exists.
7
8- :param program_path:The full path to the binary to check.
9+ :param program_path: The full path to the binary to check.
10 :return: program output to be parsed
11 """
12 log.debug('testing program_path: {text}'.format(text=program_path))
13
14=== modified file 'openlp/core/lib/theme.py'
15--- openlp/core/lib/theme.py 2016-12-31 11:01:36 +0000
16+++ openlp/core/lib/theme.py 2017-05-22 19:57:32 +0000
17@@ -164,7 +164,7 @@
18 jsn = get_text_file_string(json_file)
19 jsn = json.loads(jsn)
20 self.expand_json(jsn)
21- self.background_filename = None
22+ self.background_filename = ''
23
24 def expand_json(self, var, prev=None):
25 """
26
27=== modified file 'openlp/core/ui/advancedtab.py'
28--- openlp/core/ui/advancedtab.py 2016-12-31 11:01:36 +0000
29+++ openlp/core/ui/advancedtab.py 2017-05-22 19:57:32 +0000
30@@ -25,13 +25,13 @@
31 from datetime import datetime, timedelta
32 import logging
33 import os
34-import sys
35
36 from PyQt5 import QtCore, QtGui, QtWidgets
37
38 from openlp.core.common import AppLocation, Settings, SlideLimits, UiStrings, translate
39+from openlp.core.common.languagemanager import format_time
40 from openlp.core.lib import SettingsTab, build_icon
41-from openlp.core.common.languagemanager import format_time
42+from openlp.core.ui.lib import PathEdit, PathType
43
44 log = logging.getLogger(__name__)
45
46@@ -153,32 +153,17 @@
47 self.data_directory_group_box.setObjectName('data_directory_group_box')
48 self.data_directory_layout = QtWidgets.QFormLayout(self.data_directory_group_box)
49 self.data_directory_layout.setObjectName('data_directory_layout')
50- self.data_directory_current_label = QtWidgets.QLabel(self.data_directory_group_box)
51- self.data_directory_current_label.setObjectName('data_directory_current_label')
52- self.data_directory_label = QtWidgets.QLabel(self.data_directory_group_box)
53- self.data_directory_label.setObjectName('data_directory_label')
54 self.data_directory_new_label = QtWidgets.QLabel(self.data_directory_group_box)
55 self.data_directory_new_label.setObjectName('data_directory_current_label')
56- self.new_data_directory_edit = QtWidgets.QLineEdit(self.data_directory_group_box)
57- self.new_data_directory_edit.setObjectName('new_data_directory_edit')
58- self.new_data_directory_edit.setReadOnly(True)
59+ self.data_directory_path_edit = PathEdit(self.data_directory_group_box, path_type=PathType.Directories,
60+ default_path=AppLocation.get_directory(AppLocation.DataDir))
61+ self.data_directory_layout.addRow(self.data_directory_new_label, self.data_directory_path_edit)
62 self.new_data_directory_has_files_label = QtWidgets.QLabel(self.data_directory_group_box)
63 self.new_data_directory_has_files_label.setObjectName('new_data_directory_has_files_label')
64 self.new_data_directory_has_files_label.setWordWrap(True)
65- self.data_directory_browse_button = QtWidgets.QToolButton(self.data_directory_group_box)
66- self.data_directory_browse_button.setObjectName('data_directory_browse_button')
67- self.data_directory_browse_button.setIcon(build_icon(':/general/general_open.png'))
68- self.data_directory_default_button = QtWidgets.QToolButton(self.data_directory_group_box)
69- self.data_directory_default_button.setObjectName('data_directory_default_button')
70- self.data_directory_default_button.setIcon(build_icon(':/general/general_revert.png'))
71 self.data_directory_cancel_button = QtWidgets.QToolButton(self.data_directory_group_box)
72 self.data_directory_cancel_button.setObjectName('data_directory_cancel_button')
73 self.data_directory_cancel_button.setIcon(build_icon(':/general/general_delete.png'))
74- self.new_data_directory_label_layout = QtWidgets.QHBoxLayout()
75- self.new_data_directory_label_layout.setObjectName('new_data_directory_label_layout')
76- self.new_data_directory_label_layout.addWidget(self.new_data_directory_edit)
77- self.new_data_directory_label_layout.addWidget(self.data_directory_browse_button)
78- self.new_data_directory_label_layout.addWidget(self.data_directory_default_button)
79 self.data_directory_copy_check_layout = QtWidgets.QHBoxLayout()
80 self.data_directory_copy_check_layout.setObjectName('data_directory_copy_check_layout')
81 self.data_directory_copy_check_box = QtWidgets.QCheckBox(self.data_directory_group_box)
82@@ -186,8 +171,6 @@
83 self.data_directory_copy_check_layout.addWidget(self.data_directory_copy_check_box)
84 self.data_directory_copy_check_layout.addStretch()
85 self.data_directory_copy_check_layout.addWidget(self.data_directory_cancel_button)
86- self.data_directory_layout.addRow(self.data_directory_current_label, self.data_directory_label)
87- self.data_directory_layout.addRow(self.data_directory_new_label, self.new_data_directory_label_layout)
88 self.data_directory_layout.addRow(self.data_directory_copy_check_layout)
89 self.data_directory_layout.addRow(self.new_data_directory_has_files_label)
90 self.left_layout.addWidget(self.data_directory_group_box)
91@@ -239,8 +222,7 @@
92 self.service_name_edit.textChanged.connect(self.update_service_name_example)
93 self.service_name_revert_button.clicked.connect(self.on_service_name_revert_button_clicked)
94 self.alternate_rows_check_box.toggled.connect(self.on_alternate_rows_check_box_toggled)
95- self.data_directory_browse_button.clicked.connect(self.on_data_directory_browse_button_clicked)
96- self.data_directory_default_button.clicked.connect(self.on_data_directory_default_button_clicked)
97+ self.data_directory_path_edit.pathChanged.connect(self.on_data_directory_path_edit_path_changed)
98 self.data_directory_cancel_button.clicked.connect(self.on_data_directory_cancel_button_clicked)
99 self.data_directory_copy_check_box.toggled.connect(self.on_data_directory_copy_check_box_toggled)
100 self.end_slide_radio_button.clicked.connect(self.on_end_slide_button_clicked)
101@@ -317,12 +299,7 @@
102 self.service_name_example_label.setText(translate('OpenLP.AdvancedTab', 'Example:'))
103 self.hide_mouse_group_box.setTitle(translate('OpenLP.AdvancedTab', 'Mouse Cursor'))
104 self.hide_mouse_check_box.setText(translate('OpenLP.AdvancedTab', 'Hide mouse cursor when over display window'))
105- self.data_directory_current_label.setText(translate('OpenLP.AdvancedTab', 'Current path:'))
106- self.data_directory_new_label.setText(translate('OpenLP.AdvancedTab', 'Custom path:'))
107- self.data_directory_browse_button.setToolTip(translate('OpenLP.AdvancedTab',
108- 'Browse for new data file location.'))
109- self.data_directory_default_button.setToolTip(
110- translate('OpenLP.AdvancedTab', 'Set the data location to the default.'))
111+ self.data_directory_new_label.setText(translate('OpenLP.AdvancedTab', 'Path:'))
112 self.data_directory_cancel_button.setText(translate('OpenLP.AdvancedTab', 'Cancel'))
113 self.data_directory_cancel_button.setToolTip(
114 translate('OpenLP.AdvancedTab', 'Cancel OpenLP data directory location change.'))
115@@ -396,8 +373,7 @@
116 self.new_data_directory_has_files_label.hide()
117 self.data_directory_cancel_button.hide()
118 # Since data location can be changed, make sure the path is present.
119- self.current_data_path = AppLocation.get_data_path()
120- self.data_directory_label.setText(os.path.abspath(self.current_data_path))
121+ self.data_directory_path_edit.path = AppLocation.get_data_path()
122 # Don't allow data directory move if running portable.
123 if settings.value('advanced/is portable'):
124 self.data_directory_group_box.hide()
125@@ -509,24 +485,10 @@
126 self.service_name_edit.setText(UiStrings().DefaultServiceName)
127 self.service_name_edit.setFocus()
128
129- def on_data_directory_browse_button_clicked(self):
130+ def on_data_directory_path_edit_path_changed(self, new_data_path):
131 """
132 Browse for a new data directory location.
133 """
134- old_root_path = str(self.data_directory_label.text())
135- # Get the new directory location.
136- new_data_path = QtWidgets.QFileDialog.getExistingDirectory(self, translate('OpenLP.AdvancedTab',
137- 'Select Data Directory Location'),
138- old_root_path,
139- options=QtWidgets.QFileDialog.ShowDirsOnly)
140- # Set the new data path.
141- if new_data_path:
142- new_data_path = os.path.normpath(new_data_path)
143- if self.current_data_path.lower() == new_data_path.lower():
144- self.on_data_directory_cancel_button_clicked()
145- return
146- else:
147- return
148 # Make sure they want to change the data.
149 answer = QtWidgets.QMessageBox.question(self, translate('OpenLP.AdvancedTab', 'Confirm Data Directory Change'),
150 translate('OpenLP.AdvancedTab', 'Are you sure you want to change the '
151@@ -537,42 +499,14 @@
152 QtWidgets.QMessageBox.No),
153 QtWidgets.QMessageBox.No)
154 if answer != QtWidgets.QMessageBox.Yes:
155+ self.data_directory_path_edit.path = AppLocation.get_data_path()
156 return
157 # Check if data already exists here.
158 self.check_data_overwrite(new_data_path)
159 # Save the new location.
160 self.main_window.set_new_data_path(new_data_path)
161- self.new_data_directory_edit.setText(new_data_path)
162 self.data_directory_cancel_button.show()
163
164- def on_data_directory_default_button_clicked(self):
165- """
166- Re-set the data directory location to the 'default' location.
167- """
168- new_data_path = AppLocation.get_directory(AppLocation.DataDir)
169- if self.current_data_path.lower() != new_data_path.lower():
170- # Make sure they want to change the data location back to the
171- # default.
172- answer = QtWidgets.QMessageBox.question(self, translate('OpenLP.AdvancedTab', 'Reset Data Directory'),
173- translate('OpenLP.AdvancedTab', 'Are you sure you want to change '
174- 'the location of the OpenLP data '
175- 'directory to the default location?'
176- '\n\nThis location will be used '
177- 'after OpenLP is closed.'),
178- QtWidgets.QMessageBox.StandardButtons(QtWidgets.QMessageBox.Yes |
179- QtWidgets.QMessageBox.No),
180- QtWidgets.QMessageBox.No)
181- if answer != QtWidgets.QMessageBox.Yes:
182- return
183- self.check_data_overwrite(new_data_path)
184- # Save the new location.
185- self.main_window.set_new_data_path(new_data_path)
186- self.new_data_directory_edit.setText(os.path.abspath(new_data_path))
187- self.data_directory_cancel_button.show()
188- else:
189- # We cancel the change in case user changed their mind.
190- self.on_data_directory_cancel_button_clicked()
191-
192 def on_data_directory_copy_check_box_toggled(self):
193 """
194 Copy existing data when you change your data directory.
195@@ -589,7 +523,6 @@
196 Check if there's already data in the target directory.
197 """
198 test_path = os.path.join(data_path, 'songs')
199- self.data_directory_copy_check_box.show()
200 if os.path.exists(test_path):
201 self.data_exists = True
202 # Check is they want to replace existing data.
203@@ -603,6 +536,7 @@
204 QtWidgets.QMessageBox.StandardButtons(QtWidgets.QMessageBox.Yes |
205 QtWidgets.QMessageBox.No),
206 QtWidgets.QMessageBox.No)
207+ self.data_directory_copy_check_box.show()
208 if answer == QtWidgets.QMessageBox.Yes:
209 self.data_directory_copy_check_box.setChecked(True)
210 self.new_data_directory_has_files_label.show()
211@@ -618,7 +552,7 @@
212 """
213 Cancel the data directory location change
214 """
215- self.new_data_directory_edit.clear()
216+ self.data_directory_path_edit.path = AppLocation.get_data_path()
217 self.data_directory_copy_check_box.setChecked(False)
218 self.main_window.set_new_data_path(None)
219 self.main_window.set_copy_data(False)
220
221=== modified file 'openlp/core/ui/generaltab.py'
222--- openlp/core/ui/generaltab.py 2016-12-31 11:01:36 +0000
223+++ openlp/core/ui/generaltab.py 2017-05-22 19:57:32 +0000
224@@ -27,8 +27,8 @@
225 from PyQt5 import QtCore, QtGui, QtWidgets
226
227 from openlp.core.common import Registry, Settings, UiStrings, translate, get_images_filter
228-from openlp.core.lib import SettingsTab, ScreenList, build_icon
229-from openlp.core.ui.lib.colorbutton import ColorButton
230+from openlp.core.lib import SettingsTab, ScreenList
231+from openlp.core.ui.lib import ColorButton, PathEdit
232
233 log = logging.getLogger(__name__)
234
235@@ -172,20 +172,8 @@
236 self.logo_layout.setObjectName('logo_layout')
237 self.logo_file_label = QtWidgets.QLabel(self.logo_group_box)
238 self.logo_file_label.setObjectName('logo_file_label')
239- self.logo_file_edit = QtWidgets.QLineEdit(self.logo_group_box)
240- self.logo_file_edit.setObjectName('logo_file_edit')
241- self.logo_browse_button = QtWidgets.QToolButton(self.logo_group_box)
242- self.logo_browse_button.setObjectName('logo_browse_button')
243- self.logo_browse_button.setIcon(build_icon(':/general/general_open.png'))
244- self.logo_revert_button = QtWidgets.QToolButton(self.logo_group_box)
245- self.logo_revert_button.setObjectName('logo_revert_button')
246- self.logo_revert_button.setIcon(build_icon(':/general/general_revert.png'))
247- self.logo_file_layout = QtWidgets.QHBoxLayout()
248- self.logo_file_layout.setObjectName('logo_file_layout')
249- self.logo_file_layout.addWidget(self.logo_file_edit)
250- self.logo_file_layout.addWidget(self.logo_browse_button)
251- self.logo_file_layout.addWidget(self.logo_revert_button)
252- self.logo_layout.addRow(self.logo_file_label, self.logo_file_layout)
253+ self.logo_file_path_edit = PathEdit(self.logo_group_box, default_path=':/graphics/openlp-splash-screen.png')
254+ self.logo_layout.addRow(self.logo_file_label, self.logo_file_path_edit)
255 self.logo_color_label = QtWidgets.QLabel(self.logo_group_box)
256 self.logo_color_label.setObjectName('logo_color_label')
257 self.logo_color_button = ColorButton(self.logo_group_box)
258@@ -196,8 +184,6 @@
259 self.logo_layout.addRow(self.logo_hide_on_startup_check_box)
260 self.right_layout.addWidget(self.logo_group_box)
261 self.logo_color_button.colorChanged.connect(self.on_logo_background_color_changed)
262- self.logo_browse_button.clicked.connect(self.on_logo_browse_button_clicked)
263- self.logo_revert_button.clicked.connect(self.on_logo_revert_button_clicked)
264 # Application Settings
265 self.settings_group_box = QtWidgets.QGroupBox(self.right_column)
266 self.settings_group_box.setObjectName('settings_group_box')
267@@ -254,8 +240,6 @@
268 self.logo_group_box.setTitle(translate('OpenLP.GeneralTab', 'Logo'))
269 self.logo_color_label.setText(UiStrings().BackgroundColorColon)
270 self.logo_file_label.setText(translate('OpenLP.GeneralTab', 'Logo file:'))
271- self.logo_browse_button.setToolTip(translate('OpenLP.GeneralTab', 'Browse for an image file to display.'))
272- self.logo_revert_button.setToolTip(translate('OpenLP.GeneralTab', 'Revert to the default OpenLP logo.'))
273 self.logo_hide_on_startup_check_box.setText(translate('OpenLP.GeneralTab', 'Don\'t show logo on startup'))
274 self.check_for_updates_check_box.setText(translate('OpenLP.GeneralTab', 'Check for updates to OpenLP'))
275 self.settings_group_box.setTitle(translate('OpenLP.GeneralTab', 'Application Settings'))
276@@ -282,6 +266,9 @@
277 self.audio_group_box.setTitle(translate('OpenLP.GeneralTab', 'Background Audio'))
278 self.start_paused_check_box.setText(translate('OpenLP.GeneralTab', 'Start background audio paused'))
279 self.repeat_list_check_box.setText(translate('OpenLP.GeneralTab', 'Repeat track list'))
280+ self.logo_file_path_edit.dialog_caption = dialog_caption = translate('OpenLP.AdvancedTab', 'Select Logo File')
281+ self.logo_file_path_edit.filters = '{text};;{names} (*)'.format(
282+ text=get_images_filter(), names=UiStrings().AllFiles)
283
284 def load(self):
285 """
286@@ -304,7 +291,7 @@
287 self.auto_open_check_box.setChecked(settings.value('auto open'))
288 self.show_splash_check_box.setChecked(settings.value('show splash'))
289 self.logo_background_color = settings.value('logo background color')
290- self.logo_file_edit.setText(settings.value('logo file'))
291+ self.logo_file_path_edit.path = settings.value('logo file')
292 self.logo_hide_on_startup_check_box.setChecked(settings.value('logo hide on startup'))
293 self.logo_color_button.color = self.logo_background_color
294 self.check_for_updates_check_box.setChecked(settings.value('update check'))
295@@ -338,7 +325,7 @@
296 settings.setValue('auto open', self.auto_open_check_box.isChecked())
297 settings.setValue('show splash', self.show_splash_check_box.isChecked())
298 settings.setValue('logo background color', self.logo_background_color)
299- settings.setValue('logo file', self.logo_file_edit.text())
300+ settings.setValue('logo file', self.logo_file_path_edit.path)
301 settings.setValue('logo hide on startup', self.logo_hide_on_startup_check_box.isChecked())
302 settings.setValue('update check', self.check_for_updates_check_box.isChecked())
303 settings.setValue('save prompt', self.save_check_service_check_box.isChecked())
304@@ -404,25 +391,6 @@
305 """
306 self.display_changed = True
307
308- def on_logo_browse_button_clicked(self):
309- """
310- Select the logo file
311- """
312- file_filters = '{text};;{names} (*.*)'.format(text=get_images_filter(), names=UiStrings().AllFiles)
313- filename, filter_used = QtWidgets.QFileDialog.getOpenFileName(self,
314- translate('OpenLP.AdvancedTab', 'Open File'), '',
315- file_filters)
316- if filename:
317- self.logo_file_edit.setText(filename)
318- self.logo_file_edit.setFocus()
319-
320- def on_logo_revert_button_clicked(self):
321- """
322- Revert the logo file back to the default setting.
323- """
324- self.logo_file_edit.setText(':/graphics/openlp-splash-screen.png')
325- self.logo_file_edit.setFocus()
326-
327 def on_logo_background_color_changed(self, color):
328 """
329 Select the background color for logo.
330
331=== modified file 'openlp/core/ui/lib/__init__.py'
332--- openlp/core/ui/lib/__init__.py 2016-12-31 11:01:36 +0000
333+++ openlp/core/ui/lib/__init__.py 2017-05-22 19:57:32 +0000
334@@ -21,14 +21,16 @@
335 ###############################################################################
336
337 from .colorbutton import ColorButton
338+from .listpreviewwidget import ListPreviewWidget
339 from .listwidgetwithdnd import ListWidgetWithDnD
340-from .treewidgetwithdnd import TreeWidgetWithDnD
341+from .mediadockmanager import MediaDockManager
342+from .dockwidget import OpenLPDockWidget
343 from .toolbar import OpenLPToolbar
344-from .dockwidget import OpenLPDockWidget
345 from .wizard import OpenLPWizard, WizardStrings
346-from .mediadockmanager import MediaDockManager
347-from .listpreviewwidget import ListPreviewWidget
348+from .pathedit import PathEdit, PathType
349 from .spelltextedit import SpellTextEdit
350+from .treewidgetwithdnd import TreeWidgetWithDnD
351
352-__all__ = ['ColorButton', 'ListPreviewWidget', 'ListWidgetWithDnD', 'OpenLPToolbar', 'OpenLPDockWidget',
353- 'OpenLPWizard', 'WizardStrings', 'MediaDockManager', 'ListPreviewWidget', 'SpellTextEdit']
354+__all__ = ['ColorButton', 'ListPreviewWidget', 'ListWidgetWithDnD', 'MediaDockManager', 'OpenLPDockWidget',
355+ 'OpenLPToolbar', 'OpenLPWizard', 'PathEdit', 'PathType', 'SpellTextEdit', 'TreeWidgetWithDnD',
356+ 'WizardStrings']
357
358=== modified file 'openlp/core/ui/lib/colorbutton.py'
359--- openlp/core/ui/lib/colorbutton.py 2016-12-31 11:01:36 +0000
360+++ openlp/core/ui/lib/colorbutton.py 2017-05-22 19:57:32 +0000
361@@ -39,7 +39,7 @@
362 """
363 Initialise the ColorButton
364 """
365- super(ColorButton, self).__init__()
366+ super().__init__(parent)
367 self.parent = parent
368 self.change_color('#ffffff')
369 self.setToolTip(translate('OpenLP.ColorButton', 'Click to select a color.'))
370
371=== added file 'openlp/core/ui/lib/pathedit.py'
372--- openlp/core/ui/lib/pathedit.py 1970-01-01 00:00:00 +0000
373+++ openlp/core/ui/lib/pathedit.py 2017-05-22 19:57:32 +0000
374@@ -0,0 +1,205 @@
375+# -*- coding: utf-8 -*-
376+# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
377+
378+###############################################################################
379+# OpenLP - Open Source Lyrics Projection #
380+# --------------------------------------------------------------------------- #
381+# Copyright (c) 2008-2017 OpenLP Developers #
382+# --------------------------------------------------------------------------- #
383+# This program is free software; you can redistribute it and/or modify it #
384+# under the terms of the GNU General Public License as published by the Free #
385+# Software Foundation; version 2 of the License. #
386+# #
387+# This program is distributed in the hope that it will be useful, but WITHOUT #
388+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
389+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
390+# more details. #
391+# #
392+# You should have received a copy of the GNU General Public License along #
393+# with this program; if not, write to the Free Software Foundation, Inc., 59 #
394+# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
395+###############################################################################
396+from enum import Enum
397+import os.path
398+
399+from PyQt5 import QtCore, QtWidgets
400+
401+from openlp.core.common import UiStrings, translate
402+from openlp.core.lib import build_icon
403+
404+
405+class PathType(Enum):
406+ Files = 1
407+ Directories = 2
408+
409+
410+class PathEdit(QtWidgets.QWidget):
411+ """
412+ The :class:`~openlp.core.ui.lib.pathedit.PathEdit` class subclasses QWidget to create a custom widget for use when
413+ a file or directory needs to be selected.
414+ """
415+ pathChanged = QtCore.pyqtSignal(str)
416+
417+ def __init__(self, parent=None, path_type=PathType.Files, default_path=None, dialog_caption=None, show_revert=True):
418+ """
419+ Initalise the PathEdit widget
420+
421+ :param parent: The parent of the widget. This is just passed to the super method.
422+ :type parent: QWidget or None
423+
424+ :param dialog_caption: Used to customise the caption in the QFileDialog.
425+ :param dialog_caption: str
426+
427+ :param default_path: The default path. This is set as the path when the revert button is clicked
428+ :type default_path: str
429+
430+ :param show_revert: Used to determin if the 'revert button' should be visible.
431+ :type show_revert: bool
432+
433+ :return: None
434+ :rtype: None
435+ """
436+ super().__init__(parent)
437+ self.default_path = default_path
438+ self.dialog_caption = dialog_caption
439+ self._path_type = path_type
440+ self._path = None
441+ self.filters = '{all_files} (*)'.format(all_files=UiStrings().AllFiles)
442+ self._setup(show_revert)
443+
444+ def _setup(self, show_revert):
445+ """
446+ Set up the widget
447+ :param show_revert: Show or hide the revert button
448+ :type show_revert: bool
449+
450+ :return: None
451+ :rtype: None
452+ """
453+ widget_layout = QtWidgets.QHBoxLayout()
454+ widget_layout.setContentsMargins(0, 0, 0, 0)
455+ self.line_edit = QtWidgets.QLineEdit(self)
456+ self.line_edit.setText(self._path)
457+ widget_layout.addWidget(self.line_edit)
458+ self.browse_button = QtWidgets.QToolButton(self)
459+ self.browse_button.setIcon(build_icon(':/general/general_open.png'))
460+ widget_layout.addWidget(self.browse_button)
461+ self.revert_button = QtWidgets.QToolButton(self)
462+ self.revert_button.setIcon(build_icon(':/general/general_revert.png'))
463+ self.revert_button.setVisible(show_revert)
464+ widget_layout.addWidget(self.revert_button)
465+ self.setLayout(widget_layout)
466+ # Signals and Slots
467+ self.browse_button.clicked.connect(self.on_browse_button_clicked)
468+ self.revert_button.clicked.connect(self.on_revert_button_clicked)
469+ self.line_edit.editingFinished.connect(self.on_line_edit_editing_finished)
470+ self.update_button_tool_tips()
471+
472+ @property
473+ def path(self):
474+ """
475+ A property getter method to return the selected path.
476+
477+ :return: The selected path
478+ :rtype: str
479+ """
480+ return self._path
481+
482+ @path.setter
483+ def path(self, path):
484+ """
485+ A Property setter method to set the selected path
486+
487+ :param path: The path to set the widget to
488+ :type path: str
489+ """
490+ self._path = path
491+ self.line_edit.setText(path)
492+ self.line_edit.setToolTip(path)
493+
494+ @property
495+ def path_type(self):
496+ """
497+ A property getter method to return the path_type. Path type allows you to sepecify if the user is restricted to
498+ selecting a file or directory.
499+
500+ :return: The type selected
501+ :rtype: Enum of PathEdit
502+ """
503+ return self._path_type
504+
505+ @path_type.setter
506+ def path_type(self, path_type):
507+ """
508+ A Property setter method to set the path type
509+
510+ :param path: The type of path to select
511+ :type path: Enum of PathEdit
512+ """
513+ self._path_type = path_type
514+ self.update_button_tool_tips()
515+
516+ def update_button_tool_tips(self):
517+ """
518+ Called to update the tooltips on the buttons. This is changing path types, and when the widget is initalised
519+ :return: None
520+ """
521+ if self._path_type == PathType.Directories:
522+ self.browse_button.setToolTip(translate('OpenLP.PathEdit', 'Browse for directory.'))
523+ self.revert_button.setToolTip(translate('OpenLP.PathEdit', 'Revert to default directory.'))
524+ else:
525+ self.browse_button.setToolTip(translate('OpenLP.PathEdit', 'Browse for file.'))
526+ self.revert_button.setToolTip(translate('OpenLP.PathEdit', 'Revert to default file.'))
527+
528+ def on_browse_button_clicked(self):
529+ """
530+ A handler to handle a click on the browse button.
531+
532+ Show the QFileDialog and process the input from the user
533+ :return: None
534+ """
535+ caption = self.dialog_caption
536+ path = ''
537+ if self._path_type == PathType.Directories:
538+ if not caption:
539+ caption = translate('OpenLP.PathEdit', 'Select Directory')
540+ path = QtWidgets.QFileDialog.getExistingDirectory(self, caption,
541+ self._path, QtWidgets.QFileDialog.ShowDirsOnly)
542+ elif self._path_type == PathType.Files:
543+ if not caption:
544+ caption = self.dialog_caption = translate('OpenLP.PathEdit', 'Select File')
545+ path, filter_used = QtWidgets.QFileDialog.getOpenFileName(self, caption, self._path, self.filters)
546+ if path:
547+ path = os.path.normpath(path)
548+ self.on_new_path(path)
549+
550+ def on_revert_button_clicked(self):
551+ """
552+ A handler to handle a click on the revert button.
553+
554+ Set the new path to the value of the default_path instance variable.
555+ :return: None
556+ """
557+ self.on_new_path(self.default_path)
558+
559+ def on_line_edit_editing_finished(self):
560+ """
561+ A handler to handle when the line edit has finished being edited.
562+ :return: None
563+ """
564+ self.on_new_path(self.line_edit.text())
565+
566+ def on_new_path(self, path):
567+ """
568+ A method called to validate and set a new path.
569+
570+ Emits the pathChanged Signal
571+
572+ :param path: The new path
573+ :type path: str
574+
575+ :return: None
576+ """
577+ if self._path != path:
578+ self.path = path
579+ self.pathChanged.emit(path)
580
581=== modified file 'openlp/core/ui/themeform.py'
582--- openlp/core/ui/themeform.py 2016-12-31 11:01:36 +0000
583+++ openlp/core/ui/themeform.py 2017-05-22 19:57:32 +0000
584@@ -69,10 +69,16 @@
585 self.video_color_button.colorChanged.connect(self.on_video_color_changed)
586 self.gradient_start_button.colorChanged.connect(self.on_gradient_start_color_changed)
587 self.gradient_end_button.colorChanged.connect(self.on_gradient_end_color_changed)
588- self.image_browse_button.clicked.connect(self.on_image_browse_button_clicked)
589- self.image_file_edit.editingFinished.connect(self.on_image_file_edit_editing_finished)
590- self.video_browse_button.clicked.connect(self.on_video_browse_button_clicked)
591- self.video_file_edit.editingFinished.connect(self.on_video_file_edit_editing_finished)
592+ self.image_path_edit.filters = \
593+ '{name};;{text} (*)'.format(name=get_images_filter(), text=UiStrings().AllFiles)
594+ self.image_path_edit.pathChanged.connect(self.on_image_path_edit_path_changed)
595+ # TODO: Should work
596+ visible_formats = '({name})'.format(name='; '.join(VIDEO_EXT))
597+ actual_formats = '({name})'.format(name=' '.join(VIDEO_EXT))
598+ video_filter = '{trans} {visible} {actual}'.format(trans=translate('OpenLP', 'Video Files'),
599+ visible=visible_formats, actual=actual_formats)
600+ self.video_path_edit.filters = '{video};;{ui} (*)'.format(video=video_filter, ui=UiStrings().AllFiles)
601+ self.video_path_edit.pathChanged.connect(self.on_video_path_edit_path_changed)
602 self.main_color_button.colorChanged.connect(self.on_main_color_changed)
603 self.outline_color_button.colorChanged.connect(self.on_outline_color_changed)
604 self.shadow_color_button.colorChanged.connect(self.on_shadow_color_changed)
605@@ -112,7 +118,8 @@
606 self.background_page.registerField('color', self.color_button)
607 self.background_page.registerField('gradient_start', self.gradient_start_button)
608 self.background_page.registerField('gradient_end', self.gradient_end_button)
609- self.background_page.registerField('background_image', self.image_file_edit)
610+ self.background_page.registerField('background_image', self.image_path_edit,
611+ 'path', self.image_path_edit.pathChanged)
612 self.background_page.registerField('gradient', self.gradient_combo_box)
613 self.main_area_page.registerField('main_color_button', self.main_color_button)
614 self.main_area_page.registerField('main_size_spin_box', self.main_size_spin_box)
615@@ -309,11 +316,11 @@
616 self.setField('background_type', 1)
617 elif self.theme.background_type == BackgroundType.to_string(BackgroundType.Image):
618 self.image_color_button.color = self.theme.background_border_color
619- self.image_file_edit.setText(self.theme.background_filename)
620+ self.image_path_edit.path = self.theme.background_filename
621 self.setField('background_type', 2)
622 elif self.theme.background_type == BackgroundType.to_string(BackgroundType.Video):
623 self.video_color_button.color = self.theme.background_border_color
624- self.video_file_edit.setText(self.theme.background_filename)
625+ self.video_path_edit.path = self.theme.background_filename
626 self.setField('background_type', 4)
627 elif self.theme.background_type == BackgroundType.to_string(BackgroundType.Transparent):
628 self.setField('background_type', 3)
629@@ -441,48 +448,20 @@
630 """
631 self.theme.background_end_color = color
632
633- def on_image_browse_button_clicked(self):
634+ def on_image_path_edit_path_changed(self, filename):
635 """
636 Background Image button pushed.
637 """
638- images_filter = get_images_filter()
639- images_filter = '{name};;{text} (*.*)'.format(name=images_filter, text=UiStrings().AllFiles)
640- filename, filter_used = QtWidgets.QFileDialog.getOpenFileName(
641- self, translate('OpenLP.ThemeWizard', 'Select Image'),
642- self.image_file_edit.text(), images_filter)
643- if filename:
644- self.theme.background_filename = filename
645+ self.theme.background_filename = filename
646 self.set_background_page_values()
647
648- def on_image_file_edit_editing_finished(self):
649- """
650- Background image path edited
651- """
652- self.theme.background_filename = str(self.image_file_edit.text())
653-
654- def on_video_browse_button_clicked(self):
655+ def on_video_path_edit_path_changed(self, filename):
656 """
657 Background video button pushed.
658 """
659- # TODO: Should work
660- visible_formats = '({name})'.format(name='; '.join(VIDEO_EXT))
661- actual_formats = '({name})'.format(name=' '.join(VIDEO_EXT))
662- video_filter = '{trans} {visible} {actual}'.format(trans=translate('OpenLP', 'Video Files'),
663- visible=visible_formats, actual=actual_formats)
664- video_filter = '{video};;{ui} (*.*)'.format(video=video_filter, ui=UiStrings().AllFiles)
665- filename, filter_used = QtWidgets.QFileDialog.getOpenFileName(
666- self, translate('OpenLP.ThemeWizard', 'Select Video'),
667- self.video_file_edit.text(), video_filter)
668- if filename:
669- self.theme.background_filename = filename
670+ self.theme.background_filename = filename
671 self.set_background_page_values()
672
673- def on_video_file_edit_editing_finished(self):
674- """
675- Background video path edited
676- """
677- self.theme.background_filename = str(self.image_file_edit.text())
678-
679 def on_main_color_changed(self, color):
680 """
681 Set the main colour value
682
683=== modified file 'openlp/core/ui/themewizard.py'
684--- openlp/core/ui/themewizard.py 2016-12-31 11:01:36 +0000
685+++ openlp/core/ui/themewizard.py 2017-05-22 19:57:32 +0000
686@@ -28,7 +28,7 @@
687 from openlp.core.lib import build_icon
688 from openlp.core.lib.theme import HorizontalType, BackgroundType, BackgroundGradientType
689 from openlp.core.lib.ui import add_welcome_page, create_valign_selection_widgets
690-from openlp.core.ui.lib.colorbutton import ColorButton
691+from openlp.core.ui.lib import ColorButton, PathEdit
692
693
694 class Ui_ThemeWizard(object):
695@@ -116,16 +116,10 @@
696 self.image_layout.addRow(self.image_color_label, self.image_color_button)
697 self.image_label = QtWidgets.QLabel(self.image_widget)
698 self.image_label.setObjectName('image_label')
699- self.image_file_layout = QtWidgets.QHBoxLayout()
700- self.image_file_layout.setObjectName('image_file_layout')
701- self.image_file_edit = QtWidgets.QLineEdit(self.image_widget)
702- self.image_file_edit.setObjectName('image_file_edit')
703- self.image_file_layout.addWidget(self.image_file_edit)
704- self.image_browse_button = QtWidgets.QToolButton(self.image_widget)
705- self.image_browse_button.setObjectName('image_browse_button')
706- self.image_browse_button.setIcon(build_icon(':/general/general_open.png'))
707- self.image_file_layout.addWidget(self.image_browse_button)
708- self.image_layout.addRow(self.image_label, self.image_file_layout)
709+ self.image_path_edit = PathEdit(self.image_widget,
710+ dialog_caption=translate('OpenLP.ThemeWizard', 'Select Image'),
711+ show_revert=False)
712+ self.image_layout.addRow(self.image_label, self.image_path_edit)
713 self.image_layout.setItem(2, QtWidgets.QFormLayout.LabelRole, self.spacer)
714 self.background_stack.addWidget(self.image_widget)
715 self.transparent_widget = QtWidgets.QWidget(self.background_page)
716@@ -147,16 +141,10 @@
717 self.video_layout.addRow(self.video_color_label, self.video_color_button)
718 self.video_label = QtWidgets.QLabel(self.video_widget)
719 self.video_label.setObjectName('video_label')
720- self.video_file_layout = QtWidgets.QHBoxLayout()
721- self.video_file_layout.setObjectName('video_file_layout')
722- self.video_file_edit = QtWidgets.QLineEdit(self.video_widget)
723- self.video_file_edit.setObjectName('video_file_edit')
724- self.video_file_layout.addWidget(self.video_file_edit)
725- self.video_browse_button = QtWidgets.QToolButton(self.video_widget)
726- self.video_browse_button.setObjectName('video_browse_button')
727- self.video_browse_button.setIcon(build_icon(':/general/general_open.png'))
728- self.video_file_layout.addWidget(self.video_browse_button)
729- self.video_layout.addRow(self.video_label, self.video_file_layout)
730+ self.video_path_edit = PathEdit(self.video_widget,
731+ dialog_caption=translate('OpenLP.ThemeWizard', 'Select Video'),
732+ show_revert=False)
733+ self.video_layout.addRow(self.video_label, self.video_path_edit)
734 self.video_layout.setItem(2, QtWidgets.QFormLayout.LabelRole, self.spacer)
735 self.background_stack.addWidget(self.video_widget)
736 theme_wizard.addPage(self.background_page)
737
738=== modified file 'openlp/plugins/bibles/forms/bibleimportform.py'
739--- openlp/plugins/bibles/forms/bibleimportform.py 2017-05-06 09:22:34 +0000
740+++ openlp/plugins/bibles/forms/bibleimportform.py 2017-05-22 19:57:32 +0000
741@@ -135,7 +135,6 @@
742 Add the bible import specific wizard pages.
743 """
744 # Select Page
745- self.spacers = []
746 self.select_page = QtWidgets.QWizardPage()
747 self.select_page.setObjectName('SelectPage')
748 self.select_page_layout = QtWidgets.QVBoxLayout(self.select_page)
749@@ -148,8 +147,8 @@
750 self.format_combo_box.addItems(['', '', '', '', '', '', ''])
751 self.format_combo_box.setObjectName('FormatComboBox')
752 self.format_layout.addRow(self.format_label, self.format_combo_box)
753- self.spacers.append(QtWidgets.QSpacerItem(10, 0, QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Minimum))
754- self.format_layout.setItem(1, QtWidgets.QFormLayout.LabelRole, self.spacers[-1])
755+ self.spacer = QtWidgets.QSpacerItem(10, 0, QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Minimum)
756+ self.format_layout.setItem(1, QtWidgets.QFormLayout.LabelRole, self.spacer)
757 self.select_page_layout.addLayout(self.format_layout)
758 self.select_stack = QtWidgets.QStackedLayout()
759 self.select_stack.setObjectName('SelectStack')
760@@ -171,8 +170,7 @@
761 self.osis_browse_button.setObjectName('OsisBrowseButton')
762 self.osis_file_layout.addWidget(self.osis_browse_button)
763 self.osis_layout.addRow(self.osis_file_label, self.osis_file_layout)
764- self.spacers.append(QtWidgets.QSpacerItem(10, 0, QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Minimum))
765- self.osis_layout.setItem(1, QtWidgets.QFormLayout.LabelRole, self.spacers[-1])
766+ self.osis_layout.setItem(1, QtWidgets.QFormLayout.LabelRole, self.spacer)
767 self.select_stack.addWidget(self.osis_widget)
768 self.csv_widget = QtWidgets.QWidget(self.select_page)
769 self.csv_widget.setObjectName('CsvWidget')
770@@ -205,8 +203,7 @@
771 self.csv_verses_button.setObjectName('CsvVersesButton')
772 self.csv_verses_layout.addWidget(self.csv_verses_button)
773 self.csv_layout.addRow(self.csv_verses_label, self.csv_verses_layout)
774- self.spacers.append(QtWidgets.QSpacerItem(10, 0, QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Minimum))
775- self.csv_layout.setItem(2, QtWidgets.QFormLayout.LabelRole, self.spacers[-1])
776+ self.csv_layout.setItem(3, QtWidgets.QFormLayout.LabelRole, self.spacer)
777 self.select_stack.addWidget(self.csv_widget)
778 self.open_song_widget = QtWidgets.QWidget(self.select_page)
779 self.open_song_widget.setObjectName('OpenSongWidget')
780@@ -226,8 +223,7 @@
781 self.open_song_browse_button.setObjectName('OpenSongBrowseButton')
782 self.open_song_file_layout.addWidget(self.open_song_browse_button)
783 self.open_song_layout.addRow(self.open_song_file_label, self.open_song_file_layout)
784- self.spacers.append(QtWidgets.QSpacerItem(10, 0, QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Minimum))
785- self.open_song_layout.setItem(1, QtWidgets.QFormLayout.LabelRole, self.spacers[-1])
786+ self.open_song_layout.setItem(1, QtWidgets.QFormLayout.LabelRole, self.spacer)
787 self.select_stack.addWidget(self.open_song_widget)
788 self.web_tab_widget = QtWidgets.QTabWidget(self.select_page)
789 self.web_tab_widget.setObjectName('WebTabWidget')
790@@ -304,8 +300,7 @@
791 self.zefania_browse_button.setObjectName('ZefaniaBrowseButton')
792 self.zefania_file_layout.addWidget(self.zefania_browse_button)
793 self.zefania_layout.addRow(self.zefania_file_label, self.zefania_file_layout)
794- self.spacers.append(QtWidgets.QSpacerItem(10, 0, QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Minimum))
795- self.zefania_layout.setItem(1, QtWidgets.QFormLayout.LabelRole, self.spacers[-1])
796+ self.zefania_layout.setItem(5, QtWidgets.QFormLayout.LabelRole, self.spacer)
797 self.select_stack.addWidget(self.zefania_widget)
798 self.sword_widget = QtWidgets.QWidget(self.select_page)
799 self.sword_widget.setObjectName('SwordWidget')
800@@ -386,8 +381,7 @@
801 self.wordproject_browse_button.setObjectName('WordProjectBrowseButton')
802 self.wordproject_file_layout.addWidget(self.wordproject_browse_button)
803 self.wordproject_layout.addRow(self.wordproject_file_label, self.wordproject_file_layout)
804- self.spacers.append(QtWidgets.QSpacerItem(10, 0, QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Minimum))
805- self.wordproject_layout.setItem(1, QtWidgets.QFormLayout.LabelRole, self.spacers[-1])
806+ self.wordproject_layout.setItem(5, QtWidgets.QFormLayout.LabelRole, self.spacer)
807 self.select_stack.addWidget(self.wordproject_widget)
808 self.select_page_layout.addLayout(self.select_stack)
809 self.addPage(self.select_page)
810@@ -505,8 +499,7 @@
811 self.csv_verses_label.minimumSizeHint().width(),
812 self.open_song_file_label.minimumSizeHint().width(),
813 self.zefania_file_label.minimumSizeHint().width())
814- for spacer in self.spacers:
815- spacer.changeSize(label_width, 0, QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
816+ self.spacer.changeSize(label_width, 0, QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
817
818 def validateCurrentPage(self):
819 """
820
821=== modified file 'openlp/plugins/presentations/lib/presentationtab.py'
822--- openlp/plugins/presentations/lib/presentationtab.py 2017-05-14 10:11:10 +0000
823+++ openlp/plugins/presentations/lib/presentationtab.py 2017-05-22 19:57:32 +0000
824@@ -25,6 +25,7 @@
825 from openlp.core.common import Settings, UiStrings, translate
826 from openlp.core.lib import SettingsTab, build_icon
827 from openlp.core.lib.ui import critical_error_message_box
828+from openlp.core.ui.lib import PathEdit
829 from openlp.plugins.presentations.lib.pdfcontroller import PdfController
830
831
832@@ -88,26 +89,15 @@
833 self.pdf_program_check_box = QtWidgets.QCheckBox(self.pdf_group_box)
834 self.pdf_program_check_box.setObjectName('pdf_program_check_box')
835 self.pdf_layout.addRow(self.pdf_program_check_box)
836- self.pdf_program_path_layout = QtWidgets.QHBoxLayout()
837- self.pdf_program_path_layout.setObjectName('pdf_program_path_layout')
838- self.pdf_program_path = QtWidgets.QLineEdit(self.pdf_group_box)
839- self.pdf_program_path.setObjectName('pdf_program_path')
840- self.pdf_program_path.setReadOnly(True)
841- self.pdf_program_path.setPalette(self.get_grey_text_palette(True))
842- self.pdf_program_path_layout.addWidget(self.pdf_program_path)
843- self.pdf_program_browse_button = QtWidgets.QToolButton(self.pdf_group_box)
844- self.pdf_program_browse_button.setObjectName('pdf_program_browse_button')
845- self.pdf_program_browse_button.setIcon(build_icon(':/general/general_open.png'))
846- self.pdf_program_browse_button.setEnabled(False)
847- self.pdf_program_path_layout.addWidget(self.pdf_program_browse_button)
848- self.pdf_layout.addRow(self.pdf_program_path_layout)
849+ self.program_path_edit = PathEdit(self.pdf_group_box)
850+ self.pdf_layout.addRow(self.program_path_edit)
851 self.left_layout.addWidget(self.pdf_group_box)
852 self.left_layout.addStretch()
853 self.right_column.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred)
854 self.right_layout.addStretch()
855 # Signals and slots
856- self.pdf_program_browse_button.clicked.connect(self.on_pdf_program_browse_button_clicked)
857- self.pdf_program_check_box.clicked.connect(self.on_pdf_program_check_box_clicked)
858+ self.program_path_edit.pathChanged.connect(self.on_program_path_edit_path_changed)
859+ self.pdf_program_check_box.clicked.connect(self.program_path_edit.setEnabled)
860
861 def retranslateUi(self):
862 """
863@@ -132,6 +122,8 @@
864 '(This may fix PowerPoint scaling issues in Windows 8 and 10)'))
865 self.pdf_program_check_box.setText(
866 translate('PresentationPlugin.PresentationTab', 'Use given full path for mudraw or ghostscript binary:'))
867+ self.program_path_edit.dialog_caption = translate('PresentationPlugin.PresentationTab',
868+ 'Select mudraw or ghostscript binary')
869
870 def set_controller_text(self, checkbox, controller):
871 if checkbox.isEnabled():
872@@ -161,11 +153,10 @@
873 # load pdf-program settings
874 enable_pdf_program = Settings().value(self.settings_section + '/enable_pdf_program')
875 self.pdf_program_check_box.setChecked(enable_pdf_program)
876- self.pdf_program_path.setPalette(self.get_grey_text_palette(not enable_pdf_program))
877- self.pdf_program_browse_button.setEnabled(enable_pdf_program)
878+ self.program_path_edit.setEnabled(enable_pdf_program)
879 pdf_program = Settings().value(self.settings_section + '/pdf_program')
880 if pdf_program:
881- self.pdf_program_path.setText(pdf_program)
882+ self.program_path_edit.path = pdf_program
883
884 def save(self):
885 """
886@@ -201,7 +192,7 @@
887 Settings().setValue(setting_key, self.ppt_window_check_box.checkState())
888 changed = True
889 # Save pdf-settings
890- pdf_program = self.pdf_program_path.text()
891+ pdf_program = self.program_path_edit.path
892 enable_pdf_program = self.pdf_program_check_box.checkState()
893 # If the given program is blank disable using the program
894 if pdf_program == '':
895@@ -228,42 +219,12 @@
896 checkbox.setEnabled(controller.is_available())
897 self.set_controller_text(checkbox, controller)
898
899- def on_pdf_program_browse_button_clicked(self):
900+ def on_program_path_edit_path_changed(self, filename):
901 """
902 Select the mudraw or ghostscript binary that should be used.
903 """
904- filename, filter_used = QtWidgets.QFileDialog.getOpenFileName(
905- self, translate('PresentationPlugin.PresentationTab', 'Select mudraw or ghostscript binary.'),
906- self.pdf_program_path.text())
907 if filename:
908- program_type = PdfController.process_check_binary(filename)
909- if not program_type:
910+ if not PdfController.process_check_binary(filename):
911 critical_error_message_box(UiStrings().Error,
912 translate('PresentationPlugin.PresentationTab',
913 'The program is not ghostscript or mudraw which is required.'))
914- else:
915- self.pdf_program_path.setText(filename)
916-
917- def on_pdf_program_check_box_clicked(self, checked):
918- """
919- When checkbox for manual entering pdf-program is clicked,
920- enable or disable the textbox for the programpath and the browse-button.
921-
922- :param checked: If the box is checked or not.
923- """
924- self.pdf_program_path.setPalette(self.get_grey_text_palette(not checked))
925- self.pdf_program_browse_button.setEnabled(checked)
926-
927- def get_grey_text_palette(self, greyed):
928- """
929- Returns a QPalette with greyed out text as used for placeholderText.
930-
931- :param greyed: Determines whether the palette should be grayed.
932- :return: The created palette.
933- """
934- palette = QtGui.QPalette()
935- color = self.palette().color(QtGui.QPalette.Active, QtGui.QPalette.Text)
936- if greyed:
937- color.setAlpha(128)
938- palette.setColor(QtGui.QPalette.Active, QtGui.QPalette.Text, color)
939- return palette
940
941=== modified file 'openlp/plugins/presentations/presentationplugin.py'
942--- openlp/plugins/presentations/presentationplugin.py 2017-05-15 10:09:59 +0000
943+++ openlp/plugins/presentations/presentationplugin.py 2017-05-22 19:57:32 +0000
944@@ -1,4 +1,4 @@
945-# -*- coding: utf-8 -*-
946+ # -*- coding: utf-8 -*-
947 # vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
948
949 ###############################################################################
950
951=== modified file 'openlp/plugins/songusage/forms/songusagedetaildialog.py'
952--- openlp/plugins/songusage/forms/songusagedetaildialog.py 2016-12-31 11:01:36 +0000
953+++ openlp/plugins/songusage/forms/songusagedetaildialog.py 2017-05-22 19:57:32 +0000
954@@ -25,6 +25,7 @@
955 from openlp.core.common import translate
956 from openlp.core.lib import build_icon
957 from openlp.core.lib.ui import create_button_box
958+from openlp.core.ui.lib import PathEdit, PathType
959
960
961 class Ui_SongUsageDetailDialog(object):
962@@ -68,20 +69,13 @@
963 self.file_horizontal_layout.setSpacing(8)
964 self.file_horizontal_layout.setContentsMargins(8, 8, 8, 8)
965 self.file_horizontal_layout.setObjectName('file_horizontal_layout')
966- self.file_line_edit = QtWidgets.QLineEdit(self.file_group_box)
967- self.file_line_edit.setObjectName('file_line_edit')
968- self.file_line_edit.setReadOnly(True)
969- self.file_horizontal_layout.addWidget(self.file_line_edit)
970- self.save_file_push_button = QtWidgets.QPushButton(self.file_group_box)
971- self.save_file_push_button.setMaximumWidth(self.save_file_push_button.size().height())
972- self.save_file_push_button.setIcon(build_icon(':/general/general_open.png'))
973- self.save_file_push_button.setObjectName('save_file_push_button')
974- self.file_horizontal_layout.addWidget(self.save_file_push_button)
975+ self.report_path_edit = PathEdit(self.file_group_box, path_type = PathType.Directories, show_revert=False)
976+ self.file_horizontal_layout.addWidget(self.report_path_edit)
977 self.vertical_layout.addWidget(self.file_group_box)
978 self.button_box = create_button_box(song_usage_detail_dialog, 'button_box', ['cancel', 'ok'])
979 self.vertical_layout.addWidget(self.button_box)
980 self.retranslateUi(song_usage_detail_dialog)
981- self.save_file_push_button.clicked.connect(song_usage_detail_dialog.define_output_location)
982+ self.report_path_edit.pathChanged.connect(song_usage_detail_dialog.on_report_path_edit_path_changed)
983
984 def retranslateUi(self, song_usage_detail_dialog):
985 """
986
987=== modified file 'openlp/plugins/songusage/forms/songusagedetailform.py'
988--- openlp/plugins/songusage/forms/songusagedetailform.py 2016-12-31 11:01:36 +0000
989+++ openlp/plugins/songusage/forms/songusagedetailform.py 2017-05-22 19:57:32 +0000
990@@ -54,25 +54,20 @@
991 """
992 self.from_date_calendar.setSelectedDate(Settings().value(self.plugin.settings_section + '/from date'))
993 self.to_date_calendar.setSelectedDate(Settings().value(self.plugin.settings_section + '/to date'))
994- self.file_line_edit.setText(Settings().value(self.plugin.settings_section + '/last directory export'))
995+ self.report_path_edit.path = Settings().value(self.plugin.settings_section + '/last directory export')
996
997- def define_output_location(self):
998+ def on_report_path_edit_path_changed(self, file_path):
999 """
1000 Triggered when the Directory selection button is clicked
1001 """
1002- path = QtWidgets.QFileDialog.getExistingDirectory(
1003- self, translate('SongUsagePlugin.SongUsageDetailForm', 'Output File Location'),
1004- Settings().value(self.plugin.settings_section + '/last directory export'))
1005- if path:
1006- Settings().setValue(self.plugin.settings_section + '/last directory export', path)
1007- self.file_line_edit.setText(path)
1008+ Settings().setValue(self.plugin.settings_section + '/last directory export', file_path)
1009
1010 def accept(self):
1011 """
1012 Ok was triggered so lets save the data and run the report
1013 """
1014 log.debug('accept')
1015- path = self.file_line_edit.text()
1016+ path = self.report_path_edit.path
1017 if not path:
1018 self.main_window.error_message(
1019 translate('SongUsagePlugin.SongUsageDetailForm', 'Output Path Not Selected'),
1020
1021=== modified file 'tests/functional/openlp_core_ui/test_themeform.py'
1022--- tests/functional/openlp_core_ui/test_themeform.py 2017-04-24 05:17:55 +0000
1023+++ tests/functional/openlp_core_ui/test_themeform.py 2017-05-22 19:57:32 +0000
1024@@ -32,60 +32,21 @@
1025 """
1026 Test the functions in the ThemeManager Class
1027 """
1028- def test_select_image_file_dialog_cancelled(self):
1029- """
1030- Test the select image file dialog when the user presses cancel
1031- """
1032- # GIVEN: An instance of Theme Form and mocked QFileDialog which returns an empty string (similating a user
1033- # pressing cancel)
1034- with patch('openlp.core.ui.ThemeForm._setup'),\
1035- patch('openlp.core.ui.themeform.get_images_filter',
1036- **{'return_value': 'Image Files (*.bmp; *.gif)(*.bmp *.gif)'}),\
1037- patch('openlp.core.ui.themeform.QtWidgets.QFileDialog.getOpenFileName',
1038- **{'return_value': ('', '')}) as mocked_get_open_file_name,\
1039- patch('openlp.core.ui.themeform.translate', **{'return_value': 'Translated String'}),\
1040- patch('openlp.core.ui.ThemeForm.set_background_page_values') as mocked_set_background_page_values:
1041- instance = ThemeForm(None)
1042- mocked_image_file_edit = MagicMock()
1043- mocked_image_file_edit.text.return_value = '/original_path/file.ext'
1044- instance.image_file_edit = mocked_image_file_edit
1045-
1046- # WHEN: on_image_browse_button is clicked
1047- instance.on_image_browse_button_clicked()
1048-
1049- # THEN: The QFileDialog getOpenFileName and set_background_page_values moethods should have been called
1050- # with known arguments
1051- mocked_get_open_file_name.assert_called_once_with(instance, 'Translated String', '/original_path/file.ext',
1052- 'Image Files (*.bmp; *.gif)(*.bmp *.gif);;'
1053- 'All Files (*.*)')
1054+ def setUp(self):
1055+ with patch('openlp.core.ui.ThemeForm._setup'):
1056+ self.instance = ThemeForm(None)
1057+
1058+ def test_on_image_path_edit_path_changed(self):
1059+ """
1060+ Test the `image_path_edit.pathChanged` handler
1061+ """
1062+ # GIVEN: An instance of Theme Form
1063+ with patch.object(self.instance, 'set_background_page_values') as mocked_set_background_page_values:
1064+ self.instance.theme = MagicMock()
1065+
1066+ # WHEN: `on_image_path_edit_path_changed` is clicked
1067+ self.instance.on_image_path_edit_path_changed('/new/pat.h')
1068+
1069+ # THEN: The theme background file should be set and `set_background_page_values` should have been called
1070+ self.assertEqual(self.instance.theme.background_filename, '/new/pat.h')
1071 mocked_set_background_page_values.assert_called_once_with()
1072-
1073- def test_select_image_file_dialog_new_file(self):
1074- """
1075- Test the select image file dialog when the user presses ok
1076- """
1077- # GIVEN: An instance of Theme Form and mocked QFileDialog which returns a file path
1078- with patch('openlp.core.ui.ThemeForm._setup'),\
1079- patch('openlp.core.ui.themeform.get_images_filter',
1080- **{'return_value': 'Image Files (*.bmp; *.gif)(*.bmp *.gif)'}),\
1081- patch('openlp.core.ui.themeform.QtWidgets.QFileDialog.getOpenFileName',
1082- **{'return_value': ('/new_path/file.ext', '')}) as mocked_get_open_file_name,\
1083- patch('openlp.core.ui.themeform.translate', **{'return_value': 'Translated String'}),\
1084- patch('openlp.core.ui.ThemeForm.set_background_page_values') as mocked_background_page_values:
1085- instance = ThemeForm(None)
1086- mocked_image_file_edit = MagicMock()
1087- mocked_image_file_edit.text.return_value = '/original_path/file.ext'
1088- instance.image_file_edit = mocked_image_file_edit
1089- instance.theme = MagicMock()
1090-
1091- # WHEN: on_image_browse_button is clicked
1092- instance.on_image_browse_button_clicked()
1093-
1094- # THEN: The QFileDialog getOpenFileName and set_background_page_values moethods should have been called
1095- # with known arguments and theme.background_filename should be set
1096- mocked_get_open_file_name.assert_called_once_with(instance, 'Translated String', '/original_path/file.ext',
1097- 'Image Files (*.bmp; *.gif)(*.bmp *.gif);;'
1098- 'All Files (*.*)')
1099- self.assertEqual(instance.theme.background_filename, '/new_path/file.ext',
1100- 'theme.background_filename should be set to the path that the file dialog returns')
1101- mocked_background_page_values.assert_called_once_with()
1102
1103=== modified file 'tests/functional/openlp_core_ui_lib/test_color_button.py'
1104--- tests/functional/openlp_core_ui_lib/test_color_button.py 2017-04-24 05:17:55 +0000
1105+++ tests/functional/openlp_core_ui_lib/test_color_button.py 2017-05-22 19:57:32 +0000
1106@@ -20,12 +20,12 @@
1107 # Temple Place, Suite 330, Boston, MA 02111-1307 USA #
1108 ###############################################################################
1109 """
1110-This module contains tests for the openlp.core.lib.filedialog module
1111+This module contains tests for the openlp.core.ui.lib.colorbutton module
1112 """
1113 from unittest import TestCase
1114 from unittest.mock import MagicMock, call, patch
1115
1116-from openlp.core.ui.lib.colorbutton import ColorButton
1117+from openlp.core.ui.lib import ColorButton
1118
1119
1120 class TestColorDialog(TestCase):
1121@@ -148,11 +148,10 @@
1122 widget.on_clicked()
1123
1124 # THEN: change_color should not have been called and the colorChanged signal should not have been emitted
1125- self.assertEqual(
1126- self.mocked_change_color.call_count, 0, 'change_color should not have been called with an invalid color')
1127- self.assertEqual(
1128- self.mocked_color_changed.emit.call_count, 0,
1129- 'colorChange signal should not have been emitted with an invalid color')
1130+ self.assertFalse(self.mocked_change_color.called,
1131+ 'change_color should not have been called with an invalid color')
1132+ self.assertFalse(self.mocked_color_changed.emit.called,
1133+ 'colorChange signal should not have been emitted with an invalid color')
1134
1135 def test_on_clicked_same_color(self):
1136 """
1137@@ -171,12 +170,10 @@
1138 widget.on_clicked()
1139
1140 # THEN: change_color should not have been called and the colorChanged signal should not have been emitted
1141- self.assertEqual(
1142- self.mocked_change_color.call_count, 0,
1143- 'change_color should not have been called when the color has not changed')
1144- self.assertEqual(
1145- self.mocked_color_changed.emit.call_count, 0,
1146- 'colorChange signal should not have been emitted when the color has not changed')
1147+ self.assertFalse(self.mocked_change_color.called,
1148+ 'change_color should not have been called when the color has not changed')
1149+ self.assertFalse(self.mocked_color_changed.emit.called,
1150+ 'colorChange signal should not have been emitted when the color has not changed')
1151
1152 def test_on_clicked_new_color(self):
1153 """
1154
1155=== added file 'tests/functional/openlp_core_ui_lib/test_path_edit.py'
1156--- tests/functional/openlp_core_ui_lib/test_path_edit.py 1970-01-01 00:00:00 +0000
1157+++ tests/functional/openlp_core_ui_lib/test_path_edit.py 2017-05-22 19:57:32 +0000
1158@@ -0,0 +1,311 @@
1159+# -*- coding: utf-8 -*-
1160+# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
1161+
1162+###############################################################################
1163+# OpenLP - Open Source Lyrics Projection #
1164+# --------------------------------------------------------------------------- #
1165+# Copyright (c) 2008-2017 OpenLP Developers #
1166+# --------------------------------------------------------------------------- #
1167+# This program is free software; you can redistribute it and/or modify it #
1168+# under the terms of the GNU General Public License as published by the Free #
1169+# Software Foundation; version 2 of the License. #
1170+# #
1171+# This program is distributed in the hope that it will be useful, but WITHOUT #
1172+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
1173+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
1174+# more details. #
1175+# #
1176+# You should have received a copy of the GNU General Public License along #
1177+# with this program; if not, write to the Free Software Foundation, Inc., 59 #
1178+# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
1179+###############################################################################
1180+"""
1181+This module contains tests for the openlp.core.ui.lib.pathedit module
1182+"""
1183+from unittest import TestCase
1184+
1185+from PyQt5 import QtWidgets
1186+
1187+from openlp.core.ui.lib import PathEdit, PathType
1188+from unittest.mock import MagicMock, PropertyMock, patch
1189+
1190+
1191+class TestPathEdit(TestCase):
1192+ """
1193+ Test the :class:`~openlp.core.lib.pathedit.PathEdit` class
1194+ """
1195+ def setUp(self):
1196+ with patch('openlp.core.ui.lib.pathedit.PathEdit._setup'):
1197+ self.widget = PathEdit()
1198+
1199+ def test_path_getter(self):
1200+ """
1201+ Test the `path` property getter.
1202+ """
1203+ # GIVEN: An instance of PathEdit with the `_path` instance variable set
1204+ self.widget._path = 'getter/test/pat.h'
1205+
1206+ # WHEN: Reading the `path` property
1207+ # THEN: The value that we set should be returned
1208+ self.assertEqual(self.widget.path, 'getter/test/pat.h')
1209+
1210+ def test_path_setter(self):
1211+ """
1212+ Test the `path` property setter.
1213+ """
1214+ # GIVEN: An instance of the PathEdit object and a mocked `line_edit`
1215+ self.widget.line_edit = MagicMock()
1216+
1217+ # WHEN: Writing to the `path` property
1218+ self.widget.path = 'setter/test/pat.h'
1219+
1220+ # THEN: The `_path` instance variable should be set with the test data. The `line_edit` text and tooltip
1221+ # should have also been set.
1222+ self.assertEqual(self.widget._path, 'setter/test/pat.h')
1223+ self.widget.line_edit.setToolTip.assert_called_once_with('setter/test/pat.h')
1224+ self.widget.line_edit.setText.assert_called_once_with('setter/test/pat.h')
1225+
1226+ def test_path_type_getter(self):
1227+ """
1228+ Test the `path_type` property getter.
1229+ """
1230+ # GIVEN: An instance of PathEdit
1231+ # WHEN: Reading the `path` property
1232+ # THEN: The default value should be returned
1233+ self.assertEqual(self.widget.path_type, PathType.Files)
1234+
1235+ def test_path_type_setter(self):
1236+ """
1237+ Test the `path_type` property setter.
1238+ """
1239+ # GIVEN: An instance of the PathEdit object and a mocked `update_button_tool_tips` method.
1240+ with patch.object(self.widget, 'update_button_tool_tips') as mocked_update_button_tool_tips:
1241+
1242+ # WHEN: Writing to a different value than default to the `path_type` property
1243+ self.widget.path_type = PathType.Directories
1244+
1245+ # THEN: The `_path_type` instance variable should be set with the test data and not the default. The
1246+ # update_button_tool_tips should have been called.
1247+ self.assertEqual(self.widget._path_type, PathType.Directories)
1248+ mocked_update_button_tool_tips.assert_called_once_with()
1249+
1250+ def test_update_button_tool_tips_directories(self):
1251+ """
1252+ Test the `update_button_tool_tips` method.
1253+ """
1254+ # GIVEN: An instance of PathEdit with the `path_type` set to `Directories`
1255+ self.widget.browse_button = MagicMock()
1256+ self.widget.revert_button = MagicMock()
1257+ self.widget._path_type = PathType.Directories
1258+
1259+ # WHEN: Calling update_button_tool_tips
1260+ self.widget.update_button_tool_tips()
1261+
1262+ self.widget.browse_button.setToolTip.assert_called_once_with('Browse for directory.')
1263+ self.widget.revert_button.setToolTip.assert_called_once_with('Revert to default directory.')
1264+
1265+ def test_update_button_tool_tips_files(self):
1266+ """
1267+ Test the `update_button_tool_tips` method.
1268+ """
1269+ # GIVEN: An instance of PathEdit with the `path_type` set to `Files`
1270+ self.widget.browse_button = MagicMock()
1271+ self.widget.revert_button = MagicMock()
1272+ self.widget._path_type = PathType.Files
1273+
1274+ # WHEN: Calling update_button_tool_tips
1275+ self.widget.update_button_tool_tips()
1276+
1277+ self.widget.browse_button.setToolTip.assert_called_once_with('Browse for file.')
1278+ self.widget.revert_button.setToolTip.assert_called_once_with('Revert to default file.')
1279+
1280+ def test_on_browse_button_clicked_directory(self):
1281+ """
1282+ Test the `browse_button` `clicked` handler on_browse_button_clicked when the `path_type` is set to Directories.
1283+ """
1284+ # GIVEN: An instance of PathEdit with the `path_type` set to `Directories` and a mocked
1285+ # QFileDialog.getExistingDirectory
1286+ with patch('openlp.core.ui.lib.pathedit.QtWidgets.QFileDialog.getExistingDirectory', return_value='') as \
1287+ mocked_get_existing_directory, \
1288+ patch('openlp.core.ui.lib.pathedit.QtWidgets.QFileDialog.getOpenFileName') as \
1289+ mocked_get_open_file_name, \
1290+ patch('openlp.core.ui.lib.pathedit.os.path.normpath') as mocked_normpath:
1291+ self.widget._path_type = PathType.Directories
1292+ self.widget._path = 'test/path/'
1293+
1294+ # WHEN: Calling on_browse_button_clicked
1295+ self.widget.on_browse_button_clicked()
1296+
1297+ # THEN: The FileDialog.getExistingDirectory should have been called with the default caption
1298+ mocked_get_existing_directory.assert_called_once_with(self.widget, 'Select Directory', 'test/path/',
1299+ QtWidgets.QFileDialog.ShowDirsOnly)
1300+ self.assertFalse(mocked_get_open_file_name.called)
1301+ self.assertFalse(mocked_normpath.called)
1302+
1303+ def test_on_browse_button_clicked_directory_custom_caption(self):
1304+ """
1305+ Test the `browse_button` `clicked` handler on_browse_button_clicked when the `path_type` is set to Directories,
1306+ and `dialog_caption` is set.
1307+ """
1308+ # GIVEN: An instance of PathEdit with the `path_type` set to `Directories` and a mocked
1309+ # QFileDialog.getExistingDirectory with `default_caption` set.
1310+ with patch('openlp.core.ui.lib.pathedit.QtWidgets.QFileDialog.getExistingDirectory', return_value='') as \
1311+ mocked_get_existing_directory, \
1312+ patch('openlp.core.ui.lib.pathedit.QtWidgets.QFileDialog.getOpenFileName') as \
1313+ mocked_get_open_file_name, \
1314+ patch('openlp.core.ui.lib.pathedit.os.path.normpath') as mocked_normpath:
1315+ self.widget._path_type = PathType.Directories
1316+ self.widget._path = 'test/path/'
1317+ self.widget.dialog_caption = 'Directory Caption'
1318+
1319+ # WHEN: Calling on_browse_button_clicked
1320+ self.widget.on_browse_button_clicked()
1321+
1322+ # THEN: The FileDialog.getExistingDirectory should have been called with the custom caption
1323+ mocked_get_existing_directory.assert_called_once_with(self.widget, 'Directory Caption', 'test/path/',
1324+ QtWidgets.QFileDialog.ShowDirsOnly)
1325+ self.assertFalse(mocked_get_open_file_name.called)
1326+ self.assertFalse(mocked_normpath.called)
1327+
1328+ def test_on_browse_button_clicked_file(self):
1329+ """
1330+ Test the `browse_button` `clicked` handler on_browse_button_clicked when the `path_type` is set to Files.
1331+ """
1332+ # GIVEN: An instance of PathEdit with the `path_type` set to `Files` and a mocked QFileDialog.getOpenFileName
1333+ with patch('openlp.core.ui.lib.pathedit.QtWidgets.QFileDialog.getExistingDirectory') as \
1334+ mocked_get_existing_directory, \
1335+ patch('openlp.core.ui.lib.pathedit.QtWidgets.QFileDialog.getOpenFileName', return_value=('', '')) as \
1336+ mocked_get_open_file_name, \
1337+ patch('openlp.core.ui.lib.pathedit.os.path.normpath') as mocked_normpath:
1338+ self.widget._path_type = PathType.Files
1339+ self.widget._path = 'test/pat.h'
1340+
1341+ # WHEN: Calling on_browse_button_clicked
1342+ self.widget.on_browse_button_clicked()
1343+
1344+ # THEN: The FileDialog.getOpenFileName should have been called with the default caption
1345+ mocked_get_open_file_name.assert_called_once_with(self.widget, 'Select File', 'test/pat.h',
1346+ self.widget.filters)
1347+ self.assertFalse(mocked_get_existing_directory.called)
1348+ self.assertFalse(mocked_normpath.called)
1349+
1350+ def test_on_browse_button_clicked_file_custom_caption(self):
1351+ """
1352+ Test the `browse_button` `clicked` handler on_browse_button_clicked when the `path_type` is set to Files and
1353+ `dialog_caption` is set.
1354+ """
1355+ # GIVEN: An instance of PathEdit with the `path_type` set to `Files` and a mocked QFileDialog.getOpenFileName
1356+ # with `default_caption` set.
1357+ with patch('openlp.core.ui.lib.pathedit.QtWidgets.QFileDialog.getExistingDirectory') as \
1358+ mocked_get_existing_directory, \
1359+ patch('openlp.core.ui.lib.pathedit.QtWidgets.QFileDialog.getOpenFileName', return_value=('', '')) as \
1360+ mocked_get_open_file_name, \
1361+ patch('openlp.core.ui.lib.pathedit.os.path.normpath') as mocked_normpath:
1362+ self.widget._path_type = PathType.Files
1363+ self.widget._path = 'test/pat.h'
1364+ self.widget.dialog_caption = 'File Caption'
1365+
1366+ # WHEN: Calling on_browse_button_clicked
1367+ self.widget.on_browse_button_clicked()
1368+
1369+ # THEN: The FileDialog.getOpenFileName should have been called with the custom caption
1370+ mocked_get_open_file_name.assert_called_once_with(self.widget, 'File Caption', 'test/pat.h',
1371+ self.widget.filters)
1372+ self.assertFalse(mocked_get_existing_directory.called)
1373+ self.assertFalse(mocked_normpath.called)
1374+
1375+ def test_on_browse_button_clicked_user_cancels(self):
1376+ """
1377+ Test the `browse_button` `clicked` handler on_browse_button_clicked when the user cancels the FileDialog (an
1378+ empty str is returned)
1379+ """
1380+ # GIVEN: An instance of PathEdit with a mocked QFileDialog.getOpenFileName which returns an empty str for the
1381+ # file path.
1382+ with patch('openlp.core.ui.lib.pathedit.QtWidgets.QFileDialog.getOpenFileName', return_value=('', '')) as \
1383+ mocked_get_open_file_name, \
1384+ patch('openlp.core.ui.lib.pathedit.os.path.normpath') as mocked_normpath:
1385+
1386+ # WHEN: Calling on_browse_button_clicked
1387+ self.widget.on_browse_button_clicked()
1388+
1389+ # THEN: normpath should not have been called
1390+ self.assertTrue(mocked_get_open_file_name.called)
1391+ self.assertFalse(mocked_normpath.called)
1392+
1393+ def test_on_browse_button_clicked_user_accepts(self):
1394+ """
1395+ Test the `browse_button` `clicked` handler on_browse_button_clicked when the user accepts the FileDialog (a path
1396+ is returned)
1397+ """
1398+ # GIVEN: An instance of PathEdit with a mocked QFileDialog.getOpenFileName which returns a str for the file
1399+ # path.
1400+ with patch('openlp.core.ui.lib.pathedit.QtWidgets.QFileDialog.getOpenFileName',
1401+ return_value=('/test/pat.h', '')) as mocked_get_open_file_name, \
1402+ patch('openlp.core.ui.lib.pathedit.os.path.normpath') as mocked_normpath, \
1403+ patch.object(self.widget, 'on_new_path'):
1404+
1405+ # WHEN: Calling on_browse_button_clicked
1406+ self.widget.on_browse_button_clicked()
1407+
1408+ # THEN: normpath and `on_new_path` should have been called
1409+ self.assertTrue(mocked_get_open_file_name.called)
1410+ mocked_normpath.assert_called_once_with('/test/pat.h')
1411+ self.assertTrue(self.widget.on_new_path.called)
1412+
1413+ def test_on_revert_button_clicked(self):
1414+ """
1415+ Test that the default path is set as the path when the `revert_button.clicked` handler is called.
1416+ """
1417+ # GIVEN: An instance of PathEdit with a mocked `on_new_path`, and the `default_path` set.
1418+ with patch.object(self.widget, 'on_new_path') as mocked_on_new_path:
1419+ self.widget.default_path = '/default/pat.h'
1420+
1421+ # WHEN: Calling `on_revert_button_clicked`
1422+ self.widget.on_revert_button_clicked()
1423+
1424+ # THEN: on_new_path should have been called with the default path
1425+ mocked_on_new_path.assert_called_once_with('/default/pat.h')
1426+
1427+ def test_on_line_edit_editing_finished(self):
1428+ """
1429+ Test that the new path is set as the path when the `line_edit.editingFinished` handler is called.
1430+ """
1431+ # GIVEN: An instance of PathEdit with a mocked `line_edit` and `on_new_path`.
1432+ with patch.object(self.widget, 'on_new_path') as mocked_on_new_path:
1433+ self.widget.line_edit = MagicMock(**{'text.return_value': '/test/pat.h'})
1434+
1435+ # WHEN: Calling `on_line_edit_editing_finished`
1436+ self.widget.on_line_edit_editing_finished()
1437+
1438+ # THEN: on_new_path should have been called with the path enetered in `line_edit`
1439+ mocked_on_new_path.assert_called_once_with('/test/pat.h')
1440+
1441+ def test_on_new_path_no_change(self):
1442+ """
1443+ Test `on_new_path` when called with a path that is the same as the existing path.
1444+ """
1445+ # GIVEN: An instance of PathEdit with a test path and mocked `pathChanged` signal
1446+ with patch('openlp.core.ui.lib.pathedit.PathEdit.path', new_callable=PropertyMock):
1447+ self.widget._path = '/old/test/pat.h'
1448+ self.widget.pathChanged = MagicMock()
1449+
1450+ # WHEN: Calling `on_new_path` with the same path as the existing path
1451+ self.widget.on_new_path('/old/test/pat.h')
1452+
1453+ # THEN: The `pathChanged` signal should not be emitted
1454+ self.assertFalse(self.widget.pathChanged.emit.called)
1455+
1456+ def test_on_new_path_change(self):
1457+ """
1458+ Test `on_new_path` when called with a path that is the different to the existing path.
1459+ """
1460+ # GIVEN: An instance of PathEdit with a test path and mocked `pathChanged` signal
1461+ with patch('openlp.core.ui.lib.pathedit.PathEdit.path', new_callable=PropertyMock):
1462+ self.widget._path = '/old/test/pat.h'
1463+ self.widget.pathChanged = MagicMock()
1464+
1465+ # WHEN: Calling `on_new_path` with the a new path
1466+ self.widget.on_new_path('/new/test/pat.h')
1467+
1468+ # THEN: The `pathChanged` signal should be emitted
1469+ self.widget.pathChanged.emit.assert_called_once_with('/new/test/pat.h')
1470
1471=== modified file 'tests/interfaces/openlp_plugins/bibles/forms/test_bibleimportform.py'
1472--- tests/interfaces/openlp_plugins/bibles/forms/test_bibleimportform.py 2017-05-06 09:22:34 +0000
1473+++ tests/interfaces/openlp_plugins/bibles/forms/test_bibleimportform.py 2017-05-22 19:57:32 +0000
1474@@ -28,11 +28,12 @@
1475 from PyQt5 import QtWidgets
1476
1477 from openlp.core.common import Registry
1478-from openlp.plugins.bibles.forms import bibleimportform
1479+from openlp.plugins.bibles.forms.bibleimportform import BibleImportForm, PYSWORD_AVAILABLE
1480
1481 from tests.helpers.testmixin import TestMixin
1482
1483
1484+@skip('One of the QFormLayouts in the BibleImportForm is causing a segfault')
1485 class TestBibleImportForm(TestCase, TestMixin):
1486 """
1487 Test the BibleImportForm class
1488@@ -46,9 +47,9 @@
1489 self.setup_application()
1490 self.main_window = QtWidgets.QMainWindow()
1491 Registry().register('main_window', self.main_window)
1492- bibleimportform.PYSWORD_AVAILABLE = False
1493+ PYSWORD_AVAILABLE = False
1494 self.mocked_manager = MagicMock()
1495- self.form = bibleimportform.BibleImportForm(self.main_window, self.mocked_manager, MagicMock())
1496+ self.form = BibleImportForm(self.main_window, self.mocked_manager, MagicMock())
1497
1498 def tearDown(self):
1499 """