Merge lp:~tomasgroth/openlp/song-import-fixes24 into lp:openlp/2.4

Proposed by Tomas Groth
Status: Merged
Merged at revision: 2666
Proposed branch: lp:~tomasgroth/openlp/song-import-fixes24
Merge into: lp:openlp/2.4
Diff against target: 407 lines (+174/-29)
12 files modified
openlp/core/__init__.py (+38/-2)
openlp/core/lib/treewidgetwithdnd.py (+6/-1)
openlp/core/ui/slidecontroller.py (+2/-0)
openlp/plugins/songs/lib/__init__.py (+2/-2)
openlp/plugins/songs/lib/importers/easyslides.py (+12/-12)
openlp/plugins/songs/lib/importers/songbeamer.py (+7/-3)
openlp/plugins/songs/lib/importers/videopsalm.py (+4/-2)
tests/functional/openlp_plugins/songs/test_easyslidesimport.py (+2/-0)
tests/resources/easyslidessongs/Amazing Grace.json (+6/-6)
tests/resources/easyslidessongs/Export_2017-01-12_BB.json (+44/-0)
tests/resources/easyslidessongs/Export_2017-01-12_BB.xml (+50/-0)
tests/resources/videopsalmsongs/videopsalm-as-safe-a-stronghold.json (+1/-1)
To merge this branch: bzr merge lp:~tomasgroth/openlp/song-import-fixes24
Reviewer Review Type Date Requested Status
Tim Bentley Approve
Review via email: mp+315319@code.launchpad.net

Description of the change

Fixes:
Bug #1487788: Importing photos does not give focus to OpenLP
Bug #1512040: Loop tooltip gets stuck to "Stop playing..."
Bug #1624661: Missing DB in unmounted disk results in Traceback
Clean search lyrics for formatting tags. Fixes bug #1655988.
Fix an issue with easyslide import not handling verse order correctly. Fixes bug #1655985.
Improve the songbeamer encoding detection. Fixes bug #1530597.
Handle a few videopsalm quirks. Fixes bug #1652851.

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

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'openlp/core/__init__.py'
2--- openlp/core/__init__.py 2016-12-31 11:05:48 +0000
3+++ openlp/core/__init__.py 2017-01-22 20:24:55 +0000
4@@ -177,6 +177,38 @@
5 self.shared_memory.create(1)
6 return False
7
8+ def is_data_path_missing(self):
9+ """
10+ Check if the data folder path exists.
11+ """
12+ data_folder_path = AppLocation.get_data_path()
13+ if not os.path.exists(data_folder_path):
14+ log.critical('Database was not found in: ' + data_folder_path)
15+ status = QtWidgets.QMessageBox.critical(None, translate('OpenLP', 'Data Directory Error'),
16+ translate('OpenLP', 'OpenLP data folder was not found in:\n\n{path}'
17+ '\n\nThe location of the data folder was '
18+ 'previously changed from the OpenLP\'s '
19+ 'default location. If the data was stored on '
20+ 'removable device, that device needs to be '
21+ 'made available.\n\nYou may reset the data '
22+ 'location back to the default location, '
23+ 'or you can try to make the current location '
24+ 'available.\n\nDo you want to reset to the '
25+ 'default data location? If not, OpenLP will be '
26+ 'closed so you can try to fix the the problem.')
27+ .format(path=data_folder_path),
28+ QtWidgets.QMessageBox.StandardButtons(QtWidgets.QMessageBox.Yes |
29+ QtWidgets.QMessageBox.No),
30+ QtWidgets.QMessageBox.No)
31+ if status == QtWidgets.QMessageBox.No:
32+ # If answer was "No", return "True", it will shutdown OpenLP in def main
33+ log.info('User requested termination')
34+ return True
35+ # If answer was "Yes", remove the custom data path thus resetting the default location.
36+ Settings().remove('advanced/data path')
37+ log.info('Database location has been reset to the default settings.')
38+ return False
39+
40 def hook_exception(self, exc_type, value, traceback):
41 """
42 Add an exception hook so that any uncaught exceptions are displayed in this window rather than somewhere where
43@@ -213,7 +245,7 @@
44 Settings().setValue('core/application version', openlp_version)
45 # If data_version is different from the current version ask if we should backup the data folder
46 elif data_version != openlp_version:
47- if self.splash.isVisible():
48+ if can_show_splash and self.splash.isVisible():
49 self.splash.hide()
50 if QtWidgets.QMessageBox.question(None, translate('OpenLP', 'Backup'),
51 translate('OpenLP', 'OpenLP has been upgraded, do you want to create '
52@@ -378,9 +410,13 @@
53 Registry.create()
54 Registry().register('application', application)
55 application.setApplicationVersion(get_application_version()['version'])
56- # Instance check
57+ # Check if an instance of OpenLP is already running. Quit if there is a running instance and the user only wants one
58 if application.is_already_running():
59 sys.exit()
60+ # If the custom data path is missing and the user wants to restore the data path, quit OpenLP.
61+ if application.is_data_path_missing():
62+ application.shared_memory.detach()
63+ sys.exit()
64 # Remove/convert obsolete settings.
65 Settings().remove_obsolete_settings()
66 # First time checks in settings
67
68=== modified file 'openlp/core/lib/treewidgetwithdnd.py'
69--- openlp/core/lib/treewidgetwithdnd.py 2016-12-31 11:05:48 +0000
70+++ openlp/core/lib/treewidgetwithdnd.py 2017-01-22 20:24:55 +0000
71@@ -26,7 +26,7 @@
72
73 from PyQt5 import QtCore, QtGui, QtWidgets
74
75-from openlp.core.common import Registry
76+from openlp.core.common import Registry, is_win
77
78
79 class TreeWidgetWithDnD(QtWidgets.QTreeWidget):
80@@ -108,6 +108,11 @@
81
82 :param event: Handle of the event pint passed
83 """
84+ # If we are on Windows, OpenLP window will not be set on top. For example, user can drag images to Library and
85+ # the folder stays on top of the group creation box. This piece of code fixes this issue.
86+ if is_win():
87+ self.setWindowState(self.windowState() & ~QtCore.Qt.WindowMinimized | QtCore.Qt.WindowActive)
88+ self.setWindowState(QtCore.Qt.WindowNoState)
89 if event.mimeData().hasUrls():
90 event.setDropAction(QtCore.Qt.CopyAction)
91 event.accept()
92
93=== modified file 'openlp/core/ui/slidecontroller.py'
94--- openlp/core/ui/slidecontroller.py 2016-12-31 11:05:48 +0000
95+++ openlp/core/ui/slidecontroller.py 2017-01-22 20:24:55 +0000
96@@ -714,8 +714,10 @@
97 # Reset the button
98 self.play_slides_once.setChecked(False)
99 self.play_slides_once.setIcon(build_icon(':/media/media_time.png'))
100+ self.play_slides_once.setText(UiStrings().PlaySlidesToEnd)
101 self.play_slides_loop.setChecked(False)
102 self.play_slides_loop.setIcon(build_icon(':/media/media_time.png'))
103+ self.play_slides_loop.setText(UiStrings().PlaySlidesInLoop)
104 if item.is_text():
105 if (Settings().value(self.main_window.songs_settings_section + '/display songbar') and
106 not self.song_menu.menu().isEmpty()):
107
108=== modified file 'openlp/plugins/songs/lib/__init__.py'
109--- openlp/plugins/songs/lib/__init__.py 2016-12-31 11:05:48 +0000
110+++ openlp/plugins/songs/lib/__init__.py 2017-01-22 20:24:55 +0000
111@@ -30,7 +30,7 @@
112 from PyQt5 import QtWidgets
113
114 from openlp.core.common import AppLocation
115-from openlp.core.lib import translate
116+from openlp.core.lib import translate, clean_tags
117 from openlp.core.utils import CONTROL_CHARS
118 from openlp.plugins.songs.lib.db import Author, MediaFile, Song, Topic
119 from openlp.plugins.songs.lib.ui import SongStrings
120@@ -381,7 +381,7 @@
121 if isinstance(song.lyrics, bytes):
122 song.lyrics = str(song.lyrics, encoding='utf8')
123 verses = SongXML().get_verses(song.lyrics)
124- song.search_lyrics = ' '.join([clean_string(verse[1]) for verse in verses])
125+ song.search_lyrics = ' '.join([clean_string(clean_tags(verse[1])) for verse in verses])
126 # The song does not have any author, add one.
127 if not song.authors_songs:
128 name = SongStrings.AuthorUnknown
129
130=== modified file 'openlp/plugins/songs/lib/importers/easyslides.py'
131--- openlp/plugins/songs/lib/importers/easyslides.py 2016-12-31 11:05:48 +0000
132+++ openlp/plugins/songs/lib/importers/easyslides.py 2017-01-22 20:24:55 +0000
133@@ -179,7 +179,7 @@
134 reg = default_region
135 verses[reg] = {}
136 # instance differentiates occurrences of same verse tag
137- vt = 'V'
138+ vt = 'v'
139 vn = '1'
140 inst = 1
141 for line in lines:
142@@ -192,14 +192,14 @@
143 inst += 1
144 else:
145 # separators are not used, so empty line starts a new verse
146- vt = 'V'
147+ vt = 'v'
148 vn = len(verses[reg].get(vt, {})) + 1
149 inst = 1
150 elif line[0:7] == '[region':
151 reg = self._extract_region(line)
152 verses.setdefault(reg, {})
153 if not regions_in_verses:
154- vt = 'V'
155+ vt = 'v'
156 vn = '1'
157 inst = 1
158 elif line[0] == '[':
159@@ -212,7 +212,7 @@
160 if match:
161 marker = match.group(1).strip()
162 vn = match.group(2)
163- vt = MarkTypes.get(marker, 'O') if marker else 'V'
164+ vt = MarkTypes.get(marker, 'o') if marker else 'v'
165 if regions_in_verses:
166 region = default_region
167 inst = 1
168@@ -237,13 +237,13 @@
169 lines = '\n'.join(verses[reg][vt][vn][inst])
170 self.add_verse(lines, versetag)
171 SeqTypes = {
172- 'p': 'P1',
173- 'q': 'P2',
174- 'c': 'C1',
175- 't': 'C2',
176- 'b': 'B1',
177- 'w': 'B2',
178- 'e': 'E1'}
179+ 'p': 'p1',
180+ 'q': 'p2',
181+ 'c': 'c1',
182+ 't': 'c2',
183+ 'b': 'b1',
184+ 'w': 'b2',
185+ 'e': 'e1'}
186 # Make use of Sequence data, determining the order of verses
187 try:
188 order = str(song.Sequence).strip().split(',')
189@@ -251,7 +251,7 @@
190 if not tag:
191 continue
192 elif tag[0].isdigit():
193- tag = 'V' + tag
194+ tag = 'v' + tag
195 elif tag.lower() in SeqTypes:
196 tag = SeqTypes[tag.lower()]
197 else:
198
199=== modified file 'openlp/plugins/songs/lib/importers/songbeamer.py'
200--- openlp/plugins/songs/lib/importers/songbeamer.py 2016-12-31 11:05:48 +0000
201+++ openlp/plugins/songs/lib/importers/songbeamer.py 2017-01-22 20:24:55 +0000
202@@ -115,11 +115,15 @@
203 if os.path.isfile(import_file):
204 # First open in binary mode to detect the encoding
205 detect_file = open(import_file, 'rb')
206- details = chardet.detect(detect_file.read())
207+ self.input_file_encoding = chardet.detect(detect_file.read())['encoding']
208 detect_file.close()
209- infile = codecs.open(import_file, 'r', details['encoding'])
210+ # The encoding should only be ANSI (cp1252), UTF-8, Unicode, Big-Endian-Unicode.
211+ # So if it doesn't start with 'u' we default to cp1252. See:
212+ # https://forum.songbeamer.com/viewtopic.php?p=419&sid=ca4814924e37c11e4438b7272a98b6f2
213+ if self.input_file_encoding.lower().startswith('u'):
214+ self.input_file_encoding = 'cp1252'
215+ infile = open(import_file, 'rt', encoding=self.input_file_encoding)
216 song_data = infile.readlines()
217- infile.close()
218 else:
219 continue
220 self.title = file_name.split('.sng')[0]
221
222=== modified file 'openlp/plugins/songs/lib/importers/videopsalm.py'
223--- openlp/plugins/songs/lib/importers/videopsalm.py 2016-12-31 11:05:48 +0000
224+++ openlp/plugins/songs/lib/importers/videopsalm.py 2017-01-22 20:24:55 +0000
225@@ -65,8 +65,8 @@
226 if c == '\n':
227 if inside_quotes:
228 processed_content += '\\n'
229- # Put keys in quotes
230- elif c.isalnum() and not inside_quotes:
231+ # Put keys in quotes. The '-' is for handling nagative numbers
232+ elif (c.isalnum() or c == '-') and not inside_quotes:
233 processed_content += '"' + c
234 c = next(file_content_it)
235 while c.isalnum():
236@@ -121,6 +121,8 @@
237 if 'Memo3' in song:
238 self.add_comment(song['Memo3'])
239 for verse in song['Verses']:
240+ if 'Text' not in verse:
241+ continue
242 self.add_verse(verse['Text'], 'v')
243 if not self.finish():
244 self.log_error('Could not import %s' % self.title)
245
246=== modified file 'tests/functional/openlp_plugins/songs/test_easyslidesimport.py'
247--- tests/functional/openlp_plugins/songs/test_easyslidesimport.py 2016-12-31 11:05:48 +0000
248+++ tests/functional/openlp_plugins/songs/test_easyslidesimport.py 2017-01-22 20:24:55 +0000
249@@ -43,3 +43,5 @@
250 """
251 self.file_import(os.path.join(TEST_PATH, 'amazing-grace.xml'),
252 self.load_external_result_data(os.path.join(TEST_PATH, 'Amazing Grace.json')))
253+ self.file_import(os.path.join(TEST_PATH, 'Export_2017-01-12_BB.xml'),
254+ self.load_external_result_data(os.path.join(TEST_PATH, 'Export_2017-01-12_BB.json')))
255
256=== modified file 'tests/resources/easyslidessongs/Amazing Grace.json'
257--- tests/resources/easyslidessongs/Amazing Grace.json 2016-01-08 21:42:36 +0000
258+++ tests/resources/easyslidessongs/Amazing Grace.json 2017-01-22 20:24:55 +0000
259@@ -6,27 +6,27 @@
260 "verses": [
261 [
262 "Amazing grace! How sweet the sound\nThat saved a wretch like me;\nI once was lost, but now am found,\nWas blind, but now I see.",
263- "V1"
264+ "v1"
265 ],
266 [
267 "'Twas grace that taught my heart to fear,\nAnd grace my fears relieved;\nHow precious did that grace appear,\nThe hour I first believed!",
268- "V2"
269+ "v2"
270 ],
271 [
272 "Through many dangers, toils and snares\nI have already come;\n'Tis grace that brought me safe thus far,\nAnd grace will lead me home.",
273- "V3"
274+ "v3"
275 ],
276 [
277 "The Lord has promised good to me,\nHis word my hope secures;\nHe will my shield and portion be\nAs long as life endures.",
278- "V4"
279+ "v4"
280 ],
281 [
282 "Yes, when this heart and flesh shall fail,\nAnd mortal life shall cease,\nI shall possess within the veil\nA life of joy and peace.",
283- "V5"
284+ "v5"
285 ],
286 [
287 "When we've been there a thousand years,\nBright shining as the sun,\nWe've no less days to sing God's praise\nThan when we first begun.",
288- "V6"
289+ "v6"
290 ]
291 ]
292 }
293
294=== added file 'tests/resources/easyslidessongs/Export_2017-01-12_BB.json'
295--- tests/resources/easyslidessongs/Export_2017-01-12_BB.json 1970-01-01 00:00:00 +0000
296+++ tests/resources/easyslidessongs/Export_2017-01-12_BB.json 2017-01-22 20:24:55 +0000
297@@ -0,0 +1,44 @@
298+{
299+ "title": "BBBBBBBBB",
300+ "authors": [
301+ "John Newton (1725-1807)"
302+ ],
303+ "verses": [
304+ [
305+ "V1V1V1V1V1V1\nV1V1V1V1V1V1",
306+ "v1"
307+ ],
308+ [
309+ "V2V2V2V2V2V2\nV2V2V2V2V2V2",
310+ "v2"
311+ ],
312+ [
313+ "C1C1C1C1C1C1\nC1C1C1C1C1C1",
314+ "c1"
315+ ],
316+ [
317+ "C2C2C2C2C2C2\nC2C2C2C2C2C2",
318+ "c2"
319+ ],
320+ [
321+ "B1B1B1B1B1B1\nB1B1B1B1B1B1",
322+ "b1"
323+ ],
324+ [
325+ "B2B2B2B2B2B2\nB2B2B2B2B2B2",
326+ "b2"
327+ ],
328+ [
329+ "PRE1PRE1PRE1\nPRE1PRE1PRE1",
330+ "p1"
331+ ],
332+ [
333+ "PRE2PRE2PRE2\nPRE2PRE2PRE2",
334+ "p2"
335+ ],
336+ [
337+ "ENDENDENDEND\nENDENDENDEND",
338+ "e1"
339+ ]
340+ ]
341+}
342
343=== added file 'tests/resources/easyslidessongs/Export_2017-01-12_BB.xml'
344--- tests/resources/easyslidessongs/Export_2017-01-12_BB.xml 1970-01-01 00:00:00 +0000
345+++ tests/resources/easyslidessongs/Export_2017-01-12_BB.xml 2017-01-22 20:24:55 +0000
346@@ -0,0 +1,50 @@
347+<?xml version="1.0" encoding="utf-8"?>
348+<EasiSlides>
349+ <Item>
350+ <Title1>BBBBBBBBB</Title1>
351+ <Title2 />
352+ <Folder>NAGY</Folder>
353+ <SongNumber>0</SongNumber>
354+ <Contents>[1]
355+V1V1V1V1V1V1
356+V1V1V1V1V1V1
357+[2]
358+V2V2V2V2V2V2
359+V2V2V2V2V2V2
360+[chorus]
361+C1C1C1C1C1C1
362+C1C1C1C1C1C1
363+[chorus 2]
364+C2C2C2C2C2C2
365+C2C2C2C2C2C2
366+[bridge]
367+B1B1B1B1B1B1
368+B1B1B1B1B1B1
369+[bridge 2]
370+B2B2B2B2B2B2
371+B2B2B2B2B2B2
372+[prechorus]
373+PRE1PRE1PRE1
374+PRE1PRE1PRE1
375+[prechorus 2]
376+PRE2PRE2PRE2
377+PRE2PRE2PRE2
378+[ending]
379+ENDENDENDEND
380+ENDENDENDEND</Contents>
381+ <Notations />
382+ <Sequence>1,2,c,t,b,w,p,q,e</Sequence>
383+ <Writer />
384+ <Copyright />
385+ <Category />
386+ <Timing />
387+ <MusicKey />
388+ <Capo>-1</Capo>
389+ <LicenceAdmin1 />
390+ <LicenceAdmin2 />
391+ <BookReference />
392+ <UserReference />
393+ <FormatData />
394+ <Settings>10=&gt;</Settings>
395+ </Item>
396+</EasiSlides>
397\ No newline at end of file
398
399=== modified file 'tests/resources/videopsalmsongs/videopsalm-as-safe-a-stronghold.json'
400--- tests/resources/videopsalmsongs/videopsalm-as-safe-a-stronghold.json 2015-12-17 21:39:52 +0000
401+++ tests/resources/videopsalmsongs/videopsalm-as-safe-a-stronghold.json 2017-01-22 20:24:55 +0000
402@@ -1,4 +1,4 @@
403-{Abbreviation:"SB1",Copyright:"Public domain",Songs:[{ID:3,Composer:"Unknown",Author:"Martin Luther",Copyright:"Public
404+{Abbreviation:"SB1",Copyright:"Public domain",Songs:[{ID:3,Composer:"Unknown",Author:"Martin Luther",Capo:-1,Copyright:"Public
405 Domain",Theme:"tema1
406 tema2",CCLI:"12345",Alias:"A safe stronghold",Memo1:"This is
407 the first comment

Subscribers

People subscribed via source and target branches

to all changes: