Merge lp:~trb143/openlp/bug-772523 into lp:openlp

Proposed by Tim Bentley
Status: Merged
Merged at revision: 1833
Proposed branch: lp:~trb143/openlp/bug-772523
Merge into: lp:openlp
Diff against target: 349 lines (+91/-21)
11 files modified
openlp/core/lib/db.py (+8/-1)
openlp/core/lib/eventreceiver.py (+4/-0)
openlp/core/lib/serviceitem.py (+2/-0)
openlp/core/ui/maindisplay.py (+2/-2)
openlp/core/ui/servicemanager.py (+25/-6)
openlp/plugins/songs/forms/songexportform.py (+3/-0)
openlp/plugins/songs/lib/db.py (+2/-1)
openlp/plugins/songs/lib/mediaitem.py (+15/-3)
openlp/plugins/songs/lib/upgrade.py (+12/-1)
openlp/plugins/songs/lib/xml.py (+6/-7)
openlp/plugins/songs/songsplugin.py (+12/-0)
To merge this branch: bzr merge lp:~trb143/openlp/bug-772523
Reviewer Review Type Date Requested Status
Raoul Snyman Approve
Andreas Preikschat Pending
Review via email: mp+85370@code.launchpad.net

This proposal supersedes a proposal from 2011-12-12.

Description of the change

This patch changes your song database so back it up!

When a service is imported at present and we do not wish to save the songs we do not. This prevents the user from editing songs.
This change adds a "temporary" flag on the song database to allow those songs to be save and edited bit not via the plugin as the search will not show them.
On exit the songs will be deleted.

The code works until a service is loaded and then you get sqlalchemy errors.
I have no idea what is wrong but some help would be appreciated.

Amended code to add songs as per my email.

The code does set a correct value on existing databases.

To post a comment you must log in.
Revision history for this message
Raoul Snyman (raoul-snyman) wrote : Posted in a previous version of this proposal

Well, first remove your print statement.

review: Needs Fixing
Revision history for this message
Raoul Snyman (raoul-snyman) wrote : Posted in a previous version of this proposal

You will need to set the default of the new column, something like this:

110 Column(u'temporary', types.Boolean(), default=False)\
111 .create(table=tables[u'songs'])
        connection = metadata.bind.connect()
        update_statement = tables[u'songs'].update().values(temporary=False)
        connection.execute(update_statement)

Revision history for this message
Raoul Snyman (raoul-snyman) wrote : Posted in a previous version of this proposal

Are you going to add the setting of the default value of the new column?

review: Needs Information
Revision history for this message
Raoul Snyman (raoul-snyman) wrote : Posted in a previous version of this proposal

This looks fine, I'll approve it, but I haven't tested it.

review: Approve
Revision history for this message
Andreas Preikschat (googol-deactivatedaccount) wrote : Posted in a previous version of this proposal

1) delete your db
2) Open a service file ("Add missing songs ..." + "Update service...." enabled)
3) Disable "Add missing songs ..."
4) Restart OpenLP
5) Open the same service file
6) Edit the song in the media manager.

Result: Song in service manager is not updated.

review: Needs Fixing
Revision history for this message
Raoul Snyman (raoul-snyman) wrote : Posted in a previous version of this proposal

This isn't all your code, but I did just need to point it out...

    editId, self.loadItem_uuid, temporary = message.split(u':')
    self.loadItem_editId = int(editId)
    self.loadItem_temporary = str_to_bool(temporary)

Um, two naming conventions in the same variable? It should either be self.load_item_edit_id or self.loadItemEditId. Or if you need a bunch of related things, what about a dictionary?

Also, is that first line backwards compatible with existing service files?

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

Fully backwardly comparable.
I will do a rename tonight and resubmit.

Revision history for this message
Raoul Snyman (raoul-snyman) wrote : Posted in a previous version of this proposal

158 + self.load_item_editId = int(editId)

Sorry, this one still has that "editId" instead of "edit_id".

review: Needs Fixing
Revision history for this message
Raoul Snyman (raoul-snyman) wrote :

Looks good.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'openlp/core/lib/db.py'
2--- openlp/core/lib/db.py 2011-12-03 12:51:40 +0000
3+++ openlp/core/lib/db.py 2011-12-12 18:05:26 +0000
4@@ -358,10 +358,17 @@
5
6 def delete_all_objects(self, object_class, filter_clause=None):
7 """
8- Delete all object records
9+ Delete all object records.
10+ This method should only be used for simple tables and not ones with
11+ relationships. The relationships are not deleted from the database and
12+ this will lead to database corruptions.
13
14 ``object_class``
15 The type of object to delete
16+
17+ ``filter_clause``
18+ The filter governing selection of objects to return. Defaults to
19+ None.
20 """
21 try:
22 query = self.session.query(object_class)
23
24=== modified file 'openlp/core/lib/eventreceiver.py'
25--- openlp/core/lib/eventreceiver.py 2011-10-22 11:28:47 +0000
26+++ openlp/core/lib/eventreceiver.py 2011-12-12 18:05:26 +0000
27@@ -115,8 +115,12 @@
28 ``slidecontroller_live_stop_loop``
29 Stop the loop on the main display.
30
31+
32 **Servicemanager related signals**
33
34+ ``servicemanager_new_service``
35+ A new service is being loaded or created.
36+
37 ``servicemanager_previous_item``
38 Display the previous item in the service.
39
40
41=== modified file 'openlp/core/lib/serviceitem.py'
42--- openlp/core/lib/serviceitem.py 2011-11-13 08:57:29 +0000
43+++ openlp/core/lib/serviceitem.py 2011-12-12 18:05:26 +0000
44@@ -119,6 +119,7 @@
45 self.image_border = u'#000000'
46 self.background_audio = []
47 self.theme_overwritten = False
48+ self.temporary_edit = False
49 self._new_item()
50
51 def _new_item(self):
52@@ -365,6 +366,7 @@
53 """
54 self._uuid = other._uuid
55 self.notes = other.notes
56+ self.temporary_edit = other.temporary_edit
57 # Copy theme over if present.
58 if other.theme is not None:
59 self.theme = other.theme
60
61=== modified file 'openlp/core/ui/maindisplay.py'
62--- openlp/core/ui/maindisplay.py 2011-12-02 20:17:57 +0000
63+++ openlp/core/ui/maindisplay.py 2011-12-12 18:05:26 +0000
64@@ -45,7 +45,7 @@
65
66 class Display(QtGui.QGraphicsView):
67 """
68- This is a general display screen class. Here the general display settings
69+ This is a general display screen class. Here the general display settings
70 will done. It will be used as specialized classes by Main Display and
71 Preview display.
72 """
73@@ -66,7 +66,7 @@
74 """
75 Set up and build the screen base
76 """
77- log.debug(u'Start Display base setup (live = %s)' % self.isLive)
78+ log.debug(u'Start Display base setup (live = %s)' % self.isLive)
79 self.setGeometry(self.screen[u'size'])
80 log.debug(u'Setup webView')
81 self.webView = QtWebKit.QWebView(self)
82
83=== modified file 'openlp/core/ui/servicemanager.py'
84--- openlp/core/ui/servicemanager.py 2011-12-09 11:50:25 +0000
85+++ openlp/core/ui/servicemanager.py 2011-12-12 18:05:26 +0000
86@@ -37,7 +37,7 @@
87 from PyQt4 import QtCore, QtGui
88
89 from openlp.core.lib import OpenLPToolbar, ServiceItem, Receiver, build_icon, \
90- ItemCapabilities, SettingsManager, translate
91+ ItemCapabilities, SettingsManager, translate, str_to_bool
92 from openlp.core.lib.theme import ThemeLevel
93 from openlp.core.lib.ui import UiStrings, critical_error_message_box, \
94 context_menu_action, context_menu_separator, find_and_set_in_combo_box
95@@ -465,6 +465,7 @@
96 self.setModified(False)
97 QtCore.QSettings(). \
98 setValue(u'servicemanager/last file',QtCore.QVariant(u''))
99+ Receiver.send_message(u'servicemanager_new_service')
100
101 def saveFile(self):
102 """
103@@ -663,13 +664,14 @@
104 serviceItem.renderer = self.mainwindow.renderer
105 serviceItem.set_from_service(item, self.servicePath)
106 self.validateItem(serviceItem)
107- self.loadItem_uuid = 0
108+ self.load_item_uuid = 0
109 if serviceItem.is_capable(ItemCapabilities.OnLoadUpdate):
110 Receiver.send_message(u'%s_service_load' %
111 serviceItem.name.lower(), serviceItem)
112 # if the item has been processed
113- if serviceItem._uuid == self.loadItem_uuid:
114- serviceItem.edit_id = int(self.loadItem_editId)
115+ if serviceItem._uuid == self.load_item_uuid:
116+ serviceItem.edit_id = int(self.load_item_edit_id)
117+ serviceItem.temporary_edit = self.load_item_temporary
118 self.addServiceItem(serviceItem, repaint=False)
119 delete_file(p_file)
120 self.setFileName(fileName)
121@@ -999,6 +1001,17 @@
122 painter.drawImage(0, 0, overlay)
123 painter.end()
124 treewidgetitem.setIcon(0, build_icon(icon))
125+ elif serviceitem.temporary_edit:
126+ icon = QtGui.QImage(serviceitem.icon)
127+ icon = icon.scaled(80, 80, QtCore.Qt.KeepAspectRatio,
128+ QtCore.Qt.SmoothTransformation)
129+ overlay = QtGui.QImage(':/general/general_export.png')
130+ overlay = overlay.scaled(40, 40, QtCore.Qt.KeepAspectRatio,
131+ QtCore.Qt.SmoothTransformation)
132+ painter = QtGui.QPainter(icon)
133+ painter.drawImage(40, 0, overlay)
134+ painter.end()
135+ treewidgetitem.setIcon(0, build_icon(icon))
136 else:
137 treewidgetitem.setIcon(0, serviceitem.iconic_representation)
138 else:
139@@ -1006,6 +1019,11 @@
140 build_icon(u':/general/general_delete.png'))
141 treewidgetitem.setText(0, serviceitem.get_display_title())
142 tips = []
143+ if serviceitem.temporary_edit:
144+ tips.append(u'<strong>%s:</strong> <em>%s</em>' %
145+ (unicode(translate('OpenLP.ServiceManager', 'Edit')),
146+ (unicode(translate('OpenLP.ServiceManager',
147+ 'Service copy only')))))
148 if serviceitem.theme and serviceitem.theme != -1:
149 tips.append(u'<strong>%s:</strong> <em>%s</em>' %
150 (unicode(translate('OpenLP.ServiceManager', 'Slide theme')),
151@@ -1127,8 +1145,9 @@
152 Triggered from plugins to update service items.
153 Save the values as they will be used as part of the service load
154 """
155- editId, self.loadItem_uuid = message.split(u':')
156- self.loadItem_editId = int(editId)
157+ edit_id, self.load_item_uuid, temporary = message.split(u':')
158+ self.load_item_edit_id = int(edit_id)
159+ self.load_item_temporary = str_to_bool(temporary)
160
161 def replaceServiceItem(self, newItem):
162 """
163
164=== modified file 'openlp/plugins/songs/forms/songexportform.py'
165--- openlp/plugins/songs/forms/songexportform.py 2011-08-26 15:48:58 +0000
166+++ openlp/plugins/songs/forms/songexportform.py 2011-12-12 18:05:26 +0000
167@@ -252,6 +252,9 @@
168 songs = self.plugin.manager.get_all_objects(Song)
169 songs.sort(cmp=locale.strcoll, key=lambda song: song.title.lower())
170 for song in songs:
171+ # No need to export temporary songs.
172+ if song.temporary:
173+ continue
174 authors = u', '.join([author.display_name
175 for author in song.authors])
176 title = u'%s (%s)' % (unicode(song.title), authors)
177
178=== modified file 'openlp/plugins/songs/lib/db.py'
179--- openlp/plugins/songs/lib/db.py 2011-08-26 23:04:54 +0000
180+++ openlp/plugins/songs/lib/db.py 2011-12-12 18:05:26 +0000
181@@ -199,7 +199,8 @@
182 Column(u'search_lyrics', types.UnicodeText, nullable=False),
183 Column(u'create_date', types.DateTime(), default=func.now()),
184 Column(u'last_modified', types.DateTime(), default=func.now(),
185- onupdate=func.now())
186+ onupdate=func.now()),
187+ Column(u'temporary', types.Boolean(), default=False)
188 )
189
190 # Definition of the "topics" table
191
192=== modified file 'openlp/plugins/songs/lib/mediaitem.py'
193--- openlp/plugins/songs/lib/mediaitem.py 2011-11-24 22:34:27 +0000
194+++ openlp/plugins/songs/lib/mediaitem.py 2011-12-12 18:05:26 +0000
195@@ -270,6 +270,9 @@
196 searchresults.sort(
197 cmp=locale.strcoll, key=lambda song: song.title.lower())
198 for song in searchresults:
199+ # Do not display temporary songs
200+ if song.temporary:
201+ continue
202 author_list = [author.display_name for author in song.authors]
203 song_title = unicode(song.title)
204 song_detail = u'%s (%s)' % (song_title, u', '.join(author_list))
205@@ -286,6 +289,9 @@
206 self.listView.clear()
207 for author in searchresults:
208 for song in author.songs:
209+ # Do not display temporary songs
210+ if song.temporary:
211+ continue
212 song_detail = u'%s (%s)' % (author.display_name, song.title)
213 song_name = QtGui.QListWidgetItem(song_detail)
214 song_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(song.id))
215@@ -534,6 +540,7 @@
216 Song.search_title.asc())
217 editId = 0
218 add_song = True
219+ temporary = False
220 if search_results:
221 for song in search_results:
222 author_list = item.data_string[u'authors']
223@@ -559,13 +566,18 @@
224 self._updateBackgroundAudio(song, item)
225 editId = song.id
226 self.onSearchTextButtonClick()
227- else:
228+ elif add_song and not self.addSongFromService:
229 # Make sure we temporary import formatting tags.
230- self.openLyrics.xml_to_song(item.xml_version, True)
231+ song = self.openLyrics.xml_to_song(item.xml_version, True)
232+ # If there's any backing tracks, copy them over.
233+ if len(item.background_audio) > 0:
234+ self._updateBackgroundAudio(song, item)
235+ editId = song.id
236+ temporary = True
237 # Update service with correct song id.
238 if editId:
239 Receiver.send_message(u'service_item_update',
240- u'%s:%s' % (editId, item._uuid))
241+ u'%s:%s:%s' % (editId, item._uuid, temporary))
242
243 def search(self, string):
244 """
245
246=== modified file 'openlp/plugins/songs/lib/upgrade.py'
247--- openlp/plugins/songs/lib/upgrade.py 2011-12-02 20:17:57 +0000
248+++ openlp/plugins/songs/lib/upgrade.py 2011-12-12 18:05:26 +0000
249@@ -33,7 +33,9 @@
250 from sqlalchemy.sql.expression import func
251 from migrate.changeset.constraint import ForeignKeyConstraint
252
253-__version__ = 2
254+from openlp.plugins.songs.lib.db import Song
255+
256+__version__ = 3
257
258 def upgrade_setup(metadata):
259 """
260@@ -86,3 +88,12 @@
261 Column(u'last_modified', types.DateTime(), default=func.now())\
262 .create(table=tables[u'songs'])
263
264+def upgrade_3(session, metadata, tables):
265+ """
266+ Version 3 upgrade.
267+
268+ This upgrade adds a temporary song flag to the songs table
269+ """
270+ Column(u'temporary', types.Boolean(), default=False)\
271+ .create(table=tables[u'songs'])
272+
273
274=== modified file 'openlp/plugins/songs/lib/xml.py'
275--- openlp/plugins/songs/lib/xml.py 2011-10-09 19:51:44 +0000
276+++ openlp/plugins/songs/lib/xml.py 2011-12-12 18:05:26 +0000
277@@ -346,7 +346,7 @@
278 lines_element.set(u'break', u'optional')
279 return self._extract_xml(song_xml)
280
281- def xml_to_song(self, xml, parse_and_not_save=False):
282+ def xml_to_song(self, xml, parse_and_temporary_save=False):
283 """
284 Create and save a song from OpenLyrics format xml to the database. Since
285 we also export XML from external sources (e. g. OpenLyrics import), we
286@@ -355,9 +355,9 @@
287 ``xml``
288 The XML to parse (unicode).
289
290- ``parse_and_not_save``
291- Switch to skip processing the whole song and to prevent storing the
292- songs to the database. Defaults to ``False``.
293+ ``parse_and_temporary_save``
294+ Switch to skip processing the whole song and storing the songs in
295+ the database with a temporary flag. Defaults to ``False``.
296 """
297 # No xml get out of here.
298 if not xml:
299@@ -371,14 +371,13 @@
300 return None
301 # Formatting tags are new in OpenLyrics 0.8
302 if float(song_xml.get(u'version')) > 0.7:
303- self._process_formatting_tags(song_xml, parse_and_not_save)
304- if parse_and_not_save:
305- return
306+ self._process_formatting_tags(song_xml, parse_and_temporary_save)
307 song = Song()
308 # Values will be set when cleaning the song.
309 song.search_lyrics = u''
310 song.verse_order = u''
311 song.search_title = u''
312+ song.temporary = parse_and_temporary_save
313 self._process_copyright(properties, song)
314 self._process_cclinumber(properties, song)
315 self._process_titles(properties, song)
316
317=== modified file 'openlp/plugins/songs/songsplugin.py'
318--- openlp/plugins/songs/songsplugin.py 2011-12-09 12:35:18 +0000
319+++ openlp/plugins/songs/songsplugin.py 2011-12-12 18:05:26 +0000
320@@ -78,6 +78,10 @@
321 action_list.add_action(self.songExportItem, unicode(UiStrings().Export))
322 action_list.add_action(self.toolsReindexItem,
323 unicode(UiStrings().Tools))
324+ QtCore.QObject.connect(Receiver.get_receiver(),
325+ QtCore.SIGNAL(u'servicemanager_new_service'),
326+ self.clearTemporarySongs)
327+
328
329 def addImportMenuItem(self, import_menu):
330 """
331@@ -265,6 +269,8 @@
332 Time to tidy up on exit
333 """
334 log.info(u'Songs Finalising')
335+ self.clearTemporarySongs()
336+ # Clean up files and connections
337 self.manager.finalise()
338 self.songImportItem.setVisible(False)
339 self.songExportItem.setVisible(False)
340@@ -277,3 +283,9 @@
341 action_list.remove_action(self.toolsReindexItem,
342 unicode(UiStrings().Tools))
343 Plugin.finalise(self)
344+
345+ def clearTemporarySongs(self):
346+ # Remove temporary songs
347+ songs = self.manager.get_all_objects(Song, Song.temporary == True)
348+ for song in songs:
349+ self.manager.delete_object(Song, song.id)