Merge lp:~trb143/openlp/dnd into lp:openlp

Proposed by Tim Bentley
Status: Superseded
Proposed branch: lp:~trb143/openlp/dnd
Merge into: lp:openlp
Diff against target: 371 lines (+157/-33) (has conflicts)
9 files modified
openlp.pyw (+2/-0)
openlp/core/lib/__init__.py (+5/-0)
openlp/core/lib/listwidgetwithdnd.py (+50/-0)
openlp/core/lib/mediamanageritem.py (+52/-14)
openlp/core/ui/servicemanager.py (+29/-9)
openlp/plugins/images/lib/mediaitem.py (+3/-0)
openlp/plugins/media/lib/mediaitem.py (+12/-9)
openlp/plugins/presentations/lib/mediaitem.py (+3/-0)
openlp/plugins/songusage/songusageplugin.py (+1/-1)
Text conflict in openlp/core/lib/__init__.py
To merge this branch: bzr merge lp:~trb143/openlp/dnd
Reviewer Review Type Date Requested Status
Raoul Snyman Needs Fixing
Andreas Preikschat Pending
Review via email: mp+70201@code.launchpad.net

This proposal supersedes a proposal from 2011-08-02.

This proposal has been superseded by a proposal from 2011-08-03.

Description of the change

Move all the Drag and Drop changes from the B1 tree which is stuck at present.
It is no possible to Dnd Images, Presentations and Media into the plugins as wee as dragging a otz file into the service manager.

Can import Folders now.
Remove duplicate popups now.

Servicefile load now checks for unsaved file and asks to save.

To post a comment you must log in.
Revision history for this message
Andreas Preikschat (googol-deactivatedaccount) wrote : Posted in a previous version of this proposal

A few things:

1) line 74: hasUrls should be hasUrls()
2) line 143: spelling (runn)
3) line 146-147, 165-166: wrong indents
4) Dropping a few files (e. g. images) makes the mainwindow process bar going from 0 to 100 (in one step) as many times as many files I drop (instead of increasing the bar after processing each file)
5) when I DnD a service file to the service manager without asking me to save an already opened service
6) I thought you were going to add support for folders as well (e. g. image library)
7) line 220-222, ...: I do not like this. All ListWidgets which allow dnd need to connect to the signal, thus it should be taken care of when activating the dnd. I am not sure if we should call/have an activate method. I was thinking about specifying this in the constructor or to have an attribute (like hasDnD) in the media manager.
8) When I DnD two files (e. g. "Copy of Foo" and "Foo") a dialog pops up and says that "Copy of Foo" is already in the list. I guess this will be/is fixed in your b1 branch?
9) The "duplicate error message" does not pop up once, instead it pop ups x times which can block the program (as you have to close x dialogs)

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

line 74: hasUrls should be hasUrls()

review: Needs Fixing
lp:~trb143/openlp/dnd updated
1700. By Tim Bentley

Fix missing()

1701. By Tim Bentley

Fix conflict

Unmerged revisions

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'openlp.pyw'
2--- openlp.pyw 2011-07-23 22:52:34 +0000
3+++ openlp.pyw 2011-08-03 17:36:20 +0000
4@@ -127,6 +127,8 @@
5 # now kill the splashscreen
6 self.splash.finish(self.mainWindow)
7 log.debug(u'Splashscreen closed')
8+ # make sure Qt really display the splash screen
9+ self.processEvents()
10 self.mainWindow.repaint()
11 self.processEvents()
12 if not has_run_wizard:
13
14=== modified file 'openlp/core/lib/__init__.py'
15--- openlp/core/lib/__init__.py 2011-07-30 07:34:37 +0000
16+++ openlp/core/lib/__init__.py 2011-08-03 17:36:20 +0000
17@@ -233,9 +233,14 @@
18 except IOError:
19 pass
20
21+from eventreceiver import Receiver
22 from listwidgetwithdnd import ListWidgetWithDnD
23+<<<<<<< TREE
24 from formattingtags import FormattingTags
25 from eventreceiver import Receiver
26+=======
27+from displaytags import DisplayTags
28+>>>>>>> MERGE-SOURCE
29 from spelltextedit import SpellTextEdit
30 from settingsmanager import SettingsManager
31 from plugin import PluginStatus, StringContent, Plugin
32
33=== modified file 'openlp/core/lib/listwidgetwithdnd.py'
34--- openlp/core/lib/listwidgetwithdnd.py 2011-06-12 16:02:52 +0000
35+++ openlp/core/lib/listwidgetwithdnd.py 2011-08-03 17:36:20 +0000
36@@ -27,8 +27,12 @@
37 """
38 Extend QListWidget to handle drag and drop functionality
39 """
40+import os.path
41+
42 from PyQt4 import QtCore, QtGui
43
44+from openlp.core.lib import Receiver
45+
46 class ListWidgetWithDnD(QtGui.QListWidget):
47 """
48 Provide a list widget to store objects and handle drag and drop events
49@@ -41,6 +45,16 @@
50 self.mimeDataText = name
51 assert(self.mimeDataText)
52
53+ def activateDnD(self):
54+ """
55+ Activate DnD of widget
56+ """
57+ self.setAcceptDrops(True)
58+ self.setDragDropMode(QtGui.QAbstractItemView.DragDrop)
59+ QtCore.QObject.connect(Receiver.get_receiver(),
60+ QtCore.SIGNAL(u'%s_dnd' % self.mimeDataText),
61+ self.parent().loadFile)
62+
63 def mouseMoveEvent(self, event):
64 """
65 Drag and drop event does not care what data is selected
66@@ -58,3 +72,39 @@
67 drag.setMimeData(mimeData)
68 mimeData.setText(self.mimeDataText)
69 drag.start(QtCore.Qt.CopyAction)
70+
71+ def dragEnterEvent(self, event):
72+ if event.mimeData().hasUrls():
73+ event.accept()
74+ else:
75+ event.ignore()
76+
77+ def dragMoveEvent(self, event):
78+ if event.mimeData().hasUrls():
79+ event.setDropAction(QtCore.Qt.CopyAction)
80+ event.accept()
81+ else:
82+ event.ignore()
83+
84+ def dropEvent(self, event):
85+ """
86+ Receive drop event check if it is a file and process it if it is.
87+
88+ ``event``
89+ Handle of the event pint passed
90+ """
91+ if event.mimeData().hasUrls():
92+ event.setDropAction(QtCore.Qt.CopyAction)
93+ event.accept()
94+ files = []
95+ for url in event.mimeData().urls():
96+ localFile = unicode(url.toLocalFile())
97+ if os.path.isfile(localFile):
98+ files.append(localFile)
99+ elif os.path.isdir(localFile):
100+ listing = os.listdir(localFile)
101+ for file in listing:
102+ files.append(os.path.join(localFile,file))
103+ Receiver.send_message(u'%s_dnd' % self.mimeDataText,files)
104+ else:
105+ event.ignore()
106
107=== modified file 'openlp/core/lib/mediamanageritem.py'
108--- openlp/core/lib/mediamanageritem.py 2011-07-23 21:29:24 +0000
109+++ openlp/core/lib/mediamanageritem.py 2011-08-03 17:36:20 +0000
110@@ -252,7 +252,6 @@
111 self.listView.setSelectionMode(
112 QtGui.QAbstractItemView.ExtendedSelection)
113 self.listView.setAlternatingRowColors(True)
114- self.listView.setDragEnabled(True)
115 self.listView.setObjectName(u'%sListView' % self.plugin.name)
116 # Add to pageLayout
117 self.pageLayout.addWidget(self.listView)
118@@ -339,26 +338,65 @@
119 log.info(u'New files(s) %s', unicode(files))
120 if files:
121 Receiver.send_message(u'cursor_busy')
122- names = []
123- for count in range(0, self.listView.count()):
124- names.append(self.listView.item(count).text())
125- newFiles = []
126- for file in files:
127- filename = os.path.split(unicode(file))[1]
128- if filename in names:
129+ self.validateAndLoad(files)
130+ Receiver.send_message(u'cursor_normal')
131+
132+ def loadFile(self, files):
133+ """
134+ Turn file from Drag and Drop into an array so the Validate code
135+ can run it.
136+
137+ ``files``
138+ The list of files to be loaded
139+ """
140+ newFiles = []
141+ errorShown = False
142+ for file in files:
143+ type = file.split(u'.')[-1]
144+ if type.lower() not in self.onNewFileMasks:
145+ if not errorShown:
146 critical_error_message_box(
147- UiStrings().Duplicate,
148+ translate('OpenLP.MediaManagerItem',
149+ 'Invalid File Type'),
150 unicode(translate('OpenLP.MediaManagerItem',
151- 'Duplicate filename %s.\nThis filename is already in '
152- 'the list')) % filename)
153- else:
154- newFiles.append(file)
155+ 'Invalid File %s.\nSuffix not supported'))
156+ % file)
157+ errorShown = True
158+ else:
159+ newFiles.append(file)
160+ if file:
161+ self.validateAndLoad(newFiles)
162+
163+ def validateAndLoad(self, files):
164+ """
165+ Process a list for files either from the File Dialog or from Drag and
166+ Drop
167+
168+ ``files``
169+ The files to be loaded
170+ """
171+ names = []
172+ for count in range(0, self.listView.count()):
173+ names.append(self.listView.item(count).text())
174+ newFiles = []
175+ duplicatesFound = False
176+ for file in files:
177+ filename = os.path.split(unicode(file))[1]
178+ if filename in names:
179+ duplicatesFound = True
180+ else:
181+ newFiles.append(file)
182+ if newFiles:
183 self.loadList(newFiles)
184 lastDir = os.path.split(unicode(files[0]))[0]
185 SettingsManager.set_last_dir(self.settingsSection, lastDir)
186 SettingsManager.set_list(self.settingsSection,
187 self.settingsSection, self.getFileList())
188- Receiver.send_message(u'cursor_normal')
189+ if duplicatesFound:
190+ critical_error_message_box(
191+ UiStrings().Duplicate,
192+ unicode(translate('OpenLP.MediaManagerItem',
193+ 'Duplicate files found on import and ignored.')))
194
195 def contextMenu(self, point):
196 item = self.listView.itemAt(point)
197
198=== modified file 'openlp/core/ui/servicemanager.py'
199--- openlp/core/ui/servicemanager.py 2011-07-24 17:52:53 +0000
200+++ openlp/core/ui/servicemanager.py 2011-08-03 17:36:20 +0000
201@@ -408,20 +408,33 @@
202 return False
203 self.newFile()
204
205- def onLoadServiceClicked(self):
206+ def onLoadServiceClicked(self, loadFile=None):
207+ """
208+ Loads the service file and saves the existing one it there is one
209+ unchanged
210+
211+ ``loadFile``
212+ The service file to the loaded. Will be None is from menu so
213+ selection will be required.
214+ """
215 if self.isModified():
216 result = self.saveModifiedService()
217 if result == QtGui.QMessageBox.Cancel:
218 return False
219 elif result == QtGui.QMessageBox.Save:
220 self.saveFile()
221- fileName = unicode(QtGui.QFileDialog.getOpenFileName(self.mainwindow,
222- translate('OpenLP.ServiceManager', 'Open File'),
223- SettingsManager.get_last_dir(
224- self.mainwindow.serviceSettingsSection),
225- translate('OpenLP.ServiceManager', 'OpenLP Service Files (*.osz)')))
226- if not fileName:
227- return False
228+ if not loadFile:
229+ fileName = unicode(QtGui.QFileDialog.getOpenFileName(
230+ self.mainwindow,
231+ translate('OpenLP.ServiceManager', 'Open File'),
232+ SettingsManager.get_last_dir(
233+ self.mainwindow.serviceSettingsSection),
234+ translate('OpenLP.ServiceManager',
235+ 'OpenLP Service Files (*.osz)')))
236+ if not fileName:
237+ return False
238+ else:
239+ fileName = loadFile
240 SettingsManager.set_last_dir(self.mainwindow.serviceSettingsSection,
241 split_filename(fileName)[0])
242 self.loadFile(fileName)
243@@ -1239,7 +1252,14 @@
244 Handle of the event pint passed
245 """
246 link = event.mimeData()
247- if link.hasText():
248+ if event.mimeData().hasUrls():
249+ event.setDropAction(QtCore.Qt.CopyAction)
250+ event.accept()
251+ for url in event.mimeData().urls():
252+ filename = unicode(url.toLocalFile())
253+ if filename.endswith(u'.osz'):
254+ self.onLoadServiceClicked(filename)
255+ elif event.mimeData().hasText():
256 plugin = unicode(event.mimeData().text())
257 item = self.serviceManagerList.itemAt(event.pos())
258 # ServiceManager started the drag and drop
259
260=== modified file 'openlp/plugins/images/lib/mediaitem.py'
261--- openlp/plugins/images/lib/mediaitem.py 2011-07-03 08:13:48 +0000
262+++ openlp/plugins/images/lib/mediaitem.py 2011-08-03 17:36:20 +0000
263@@ -52,6 +52,8 @@
264 self.hasSearch = True
265 QtCore.QObject.connect(Receiver.get_receiver(),
266 QtCore.SIGNAL(u'live_theme_changed'), self.liveThemeChanged)
267+ # Allow DnD from the desktop
268+ self.listView.activateDnD()
269
270 def retranslateUi(self):
271 self.onNewPrompt = translate('ImagePlugin.MediaItem',
272@@ -131,6 +133,7 @@
273 icon = self.iconFromFile(imageFile, thumb)
274 item_name = QtGui.QListWidgetItem(filename)
275 item_name.setIcon(icon)
276+ item_name.setToolTip(imageFile)
277 item_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(imageFile))
278 self.listView.addItem(item_name)
279 if not initialLoad:
280
281=== modified file 'openlp/plugins/media/lib/mediaitem.py'
282--- openlp/plugins/media/lib/mediaitem.py 2011-07-03 08:13:48 +0000
283+++ openlp/plugins/media/lib/mediaitem.py 2011-08-03 17:36:20 +0000
284@@ -39,6 +39,8 @@
285
286 log = logging.getLogger(__name__)
287
288+CLAPPERBOARD = QtGui.QPixmap(u':/media/media_video.png').toImage()
289+
290 class MediaMediaItem(MediaManagerItem):
291 """
292 This is the custom media manager item for Media Slides.
293@@ -48,8 +50,7 @@
294 def __init__(self, parent, plugin, icon):
295 self.IconPath = u'images/image'
296 self.background = False
297- self.PreviewFunction = QtGui.QPixmap(
298- u':/media/media_video.png').toImage()
299+ self.PreviewFunction = CLAPPERBOARD
300 MediaManagerItem.__init__(self, parent, plugin, icon)
301 self.singleServiceItem = False
302 self.hasSearch = True
303@@ -60,6 +61,8 @@
304 QtCore.QObject.connect(Receiver.get_receiver(),
305 QtCore.SIGNAL(u'openlp_phonon_creation'),
306 self.createPhonon)
307+ # Allow DnD from the desktop
308+ self.listView.activateDnD()
309
310 def retranslateUi(self):
311 self.onNewPrompt = translate('MediaPlugin.MediaItem', 'Select Media')
312@@ -201,17 +204,17 @@
313 SettingsManager.set_list(self.settingsSection,
314 u'media', self.getFileList())
315
316- def loadList(self, files):
317+ def loadList(self, media):
318 # Sort the themes by its filename considering language specific
319 # characters. lower() is needed for windows!
320- files.sort(cmp=locale.strcoll,
321+ media.sort(cmp=locale.strcoll,
322 key=lambda filename: os.path.split(unicode(filename))[1].lower())
323- for file in files:
324- filename = os.path.split(unicode(file))[1]
325+ for track in media:
326+ filename = os.path.split(unicode(track))[1]
327 item_name = QtGui.QListWidgetItem(filename)
328- img = QtGui.QPixmap(u':/media/media_video.png').toImage()
329- item_name.setIcon(build_icon(img))
330- item_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(file))
331+ item_name.setIcon(build_icon(CLAPPERBOARD))
332+ item_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(track))
333+ item_name.setToolTip(track)
334 self.listView.addItem(item_name)
335
336 def createPhonon(self):
337
338=== modified file 'openlp/plugins/presentations/lib/mediaitem.py'
339--- openlp/plugins/presentations/lib/mediaitem.py 2011-06-12 17:56:11 +0000
340+++ openlp/plugins/presentations/lib/mediaitem.py 2011-08-03 17:36:20 +0000
341@@ -58,6 +58,8 @@
342 self.hasSearch = True
343 QtCore.QObject.connect(Receiver.get_receiver(),
344 QtCore.SIGNAL(u'mediaitem_presentation_rebuild'), self.rebuild)
345+ # Allow DnD from the desktop
346+ self.listView.activateDnD()
347
348 def retranslateUi(self):
349 """
350@@ -205,6 +207,7 @@
351 item_name = QtGui.QListWidgetItem(filename)
352 item_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(file))
353 item_name.setIcon(icon)
354+ item_name.setToolTip(file)
355 self.listView.addItem(item_name)
356 Receiver.send_message(u'cursor_normal')
357 if not initialLoad:
358
359=== modified file 'openlp/plugins/songusage/songusageplugin.py'
360--- openlp/plugins/songusage/songusageplugin.py 2011-07-23 21:29:24 +0000
361+++ openlp/plugins/songusage/songusageplugin.py 2011-08-03 17:36:20 +0000
362@@ -91,8 +91,8 @@
363 self.toolsMenu.addAction(self.songUsageMenu.menuAction())
364 self.songUsageMenu.addAction(self.songUsageStatus)
365 self.songUsageMenu.addSeparator()
366+ self.songUsageMenu.addAction(self.songUsageReport)
367 self.songUsageMenu.addAction(self.songUsageDelete)
368- self.songUsageMenu.addAction(self.songUsageReport)
369 self.songUsageActiveButton = QtGui.QToolButton(
370 self.formparent.statusBar)
371 self.songUsageActiveButton.setCheckable(True)