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

Proposed by Phill
Status: Superseded
Proposed branch: lp:~phill-ridout/openlp/path_edit
Merge into: lp:openlp
Diff against target: 1483 lines (+628/-345)
17 files modified
openlp/core/common/__init__.py (+1/-1)
openlp/core/lib/theme.py (+1/-1)
openlp/core/ui/advancedtab.py (+13/-78)
openlp/core/ui/generaltab.py (+11/-41)
openlp/core/ui/lib/__init__.py (+8/-6)
openlp/core/ui/lib/colorbutton.py (+1/-1)
openlp/core/ui/lib/pathedit.py (+197/-0)
openlp/core/ui/themeform.py (+18/-39)
openlp/core/ui/themewizard.py (+7/-21)
openlp/plugins/bibles/forms/bibleimportform.py (+8/-15)
openlp/plugins/presentations/lib/presentationtab.py (+12/-51)
openlp/plugins/songusage/forms/songusagedetaildialog.py (+5/-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 Needs Fixing
Review via email: mp+324018@code.launchpad.net

This proposal has been superseded by a proposal from 2017-05-14.

Description of the change

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 2736)
[SUCCESS] https://ci.openlp.io/job/Branch-01-Pull/2001/
[SUCCESS] https://ci.openlp.io/job/Branch-02-Functional-Tests/1911/
[SUCCESS] https://ci.openlp.io/job/Branch-03-Interface-Tests/1847/
[SUCCESS] https://ci.openlp.io/job/Branch-04a-Code_Analysis/1227/
[SUCCESS] https://ci.openlp.io/job/Branch-04b-Test_Coverage/1089/
[SUCCESS] https://ci.openlp.io/job/Branch-04c-Code_Analysis2/218/
[FAILURE] https://ci.openlp.io/job/Branch-05-AppVeyor-Tests/66/
Stopping after failure

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

You tracking head as you have conflicts!

review: Needs Fixing
lp:~phill-ridout/openlp/path_edit updated
2737. By Phill

HEAD

2738. By Phill

Changed the allfiles filter from *.* to *

2739. By Phill

Added some extra params to the constructor

2740. By Phill

Head

2741. By Phill

More all file filters

Unmerged revisions

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