diff --git a/openlp.pyw b/openlp.pyw index fe96ebd23..962109592 100755 --- a/openlp.pyw +++ b/openlp.pyw @@ -127,6 +127,8 @@ class OpenLP(QtGui.QApplication): # now kill the splashscreen self.splash.finish(self.mainWindow) log.debug(u'Splashscreen closed') + # make sure Qt really display the splash screen + self.processEvents() self.mainWindow.repaint() self.processEvents() if not has_run_wizard: diff --git a/openlp/core/lib/__init__.py b/openlp/core/lib/__init__.py index 620d5dafd..f83e92de7 100644 --- a/openlp/core/lib/__init__.py +++ b/openlp/core/lib/__init__.py @@ -233,9 +233,9 @@ def check_directory_exists(dir): except IOError: pass +from eventreceiver import Receiver from listwidgetwithdnd import ListWidgetWithDnD from formattingtags import FormattingTags -from eventreceiver import Receiver from spelltextedit import SpellTextEdit from settingsmanager import SettingsManager from plugin import PluginStatus, StringContent, Plugin diff --git a/openlp/core/lib/listwidgetwithdnd.py b/openlp/core/lib/listwidgetwithdnd.py index 48793c12e..69fb23092 100644 --- a/openlp/core/lib/listwidgetwithdnd.py +++ b/openlp/core/lib/listwidgetwithdnd.py @@ -27,8 +27,12 @@ """ Extend QListWidget to handle drag and drop functionality """ +import os.path + from PyQt4 import QtCore, QtGui +from openlp.core.lib import Receiver + class ListWidgetWithDnD(QtGui.QListWidget): """ Provide a list widget to store objects and handle drag and drop events @@ -41,6 +45,16 @@ class ListWidgetWithDnD(QtGui.QListWidget): self.mimeDataText = name assert(self.mimeDataText) + def activateDnD(self): + """ + Activate DnD of widget + """ + self.setAcceptDrops(True) + self.setDragDropMode(QtGui.QAbstractItemView.DragDrop) + QtCore.QObject.connect(Receiver.get_receiver(), + QtCore.SIGNAL(u'%s_dnd' % self.mimeDataText), + self.parent().loadFile) + def mouseMoveEvent(self, event): """ Drag and drop event does not care what data is selected @@ -58,3 +72,39 @@ class ListWidgetWithDnD(QtGui.QListWidget): drag.setMimeData(mimeData) mimeData.setText(self.mimeDataText) drag.start(QtCore.Qt.CopyAction) + + def dragEnterEvent(self, event): + if event.mimeData().hasUrls(): + event.accept() + else: + event.ignore() + + def dragMoveEvent(self, event): + if event.mimeData().hasUrls(): + event.setDropAction(QtCore.Qt.CopyAction) + event.accept() + else: + event.ignore() + + def dropEvent(self, event): + """ + Receive drop event check if it is a file and process it if it is. + + ``event`` + Handle of the event pint passed + """ + if event.mimeData().hasUrls(): + event.setDropAction(QtCore.Qt.CopyAction) + event.accept() + files = [] + for url in event.mimeData().urls(): + localFile = unicode(url.toLocalFile()) + if os.path.isfile(localFile): + files.append(localFile) + elif os.path.isdir(localFile): + listing = os.listdir(localFile) + for file in listing: + files.append(os.path.join(localFile,file)) + Receiver.send_message(u'%s_dnd' % self.mimeDataText,files) + else: + event.ignore() diff --git a/openlp/core/lib/mediamanageritem.py b/openlp/core/lib/mediamanageritem.py index 66bf89f49..a721fabf6 100644 --- a/openlp/core/lib/mediamanageritem.py +++ b/openlp/core/lib/mediamanageritem.py @@ -252,7 +252,6 @@ class MediaManagerItem(QtGui.QWidget): self.listView.setSelectionMode( QtGui.QAbstractItemView.ExtendedSelection) self.listView.setAlternatingRowColors(True) - self.listView.setDragEnabled(True) self.listView.setObjectName(u'%sListView' % self.plugin.name) # Add to pageLayout self.pageLayout.addWidget(self.listView) @@ -339,26 +338,65 @@ class MediaManagerItem(QtGui.QWidget): log.info(u'New files(s) %s', unicode(files)) if files: Receiver.send_message(u'cursor_busy') - names = [] - for count in range(0, self.listView.count()): - names.append(self.listView.item(count).text()) - newFiles = [] - for file in files: - filename = os.path.split(unicode(file))[1] - if filename in names: + self.validateAndLoad(files) + Receiver.send_message(u'cursor_normal') + + def loadFile(self, files): + """ + Turn file from Drag and Drop into an array so the Validate code + can run it. + + ``files`` + The list of files to be loaded + """ + newFiles = [] + errorShown = False + for file in files: + type = file.split(u'.')[-1] + if type.lower() not in self.onNewFileMasks: + if not errorShown: critical_error_message_box( - UiStrings().Duplicate, + translate('OpenLP.MediaManagerItem', + 'Invalid File Type'), unicode(translate('OpenLP.MediaManagerItem', - 'Duplicate filename %s.\nThis filename is already in ' - 'the list')) % filename) - else: - newFiles.append(file) + 'Invalid File %s.\nSuffix not supported')) + % file) + errorShown = True + else: + newFiles.append(file) + if file: + self.validateAndLoad(newFiles) + + def validateAndLoad(self, files): + """ + Process a list for files either from the File Dialog or from Drag and + Drop + + ``files`` + The files to be loaded + """ + names = [] + for count in range(0, self.listView.count()): + names.append(self.listView.item(count).text()) + newFiles = [] + duplicatesFound = False + for file in files: + filename = os.path.split(unicode(file))[1] + if filename in names: + duplicatesFound = True + else: + newFiles.append(file) + if newFiles: self.loadList(newFiles) lastDir = os.path.split(unicode(files[0]))[0] SettingsManager.set_last_dir(self.settingsSection, lastDir) SettingsManager.set_list(self.settingsSection, self.settingsSection, self.getFileList()) - Receiver.send_message(u'cursor_normal') + if duplicatesFound: + critical_error_message_box( + UiStrings().Duplicate, + unicode(translate('OpenLP.MediaManagerItem', + 'Duplicate files found on import and ignored.'))) def contextMenu(self, point): item = self.listView.itemAt(point) diff --git a/openlp/core/ui/servicemanager.py b/openlp/core/ui/servicemanager.py index 351e5bbc6..0755a0143 100644 --- a/openlp/core/ui/servicemanager.py +++ b/openlp/core/ui/servicemanager.py @@ -408,20 +408,33 @@ class ServiceManager(QtGui.QWidget): return False self.newFile() - def onLoadServiceClicked(self): + def onLoadServiceClicked(self, loadFile=None): + """ + Loads the service file and saves the existing one it there is one + unchanged + + ``loadFile`` + The service file to the loaded. Will be None is from menu so + selection will be required. + """ if self.isModified(): result = self.saveModifiedService() if result == QtGui.QMessageBox.Cancel: return False elif result == QtGui.QMessageBox.Save: self.saveFile() - fileName = unicode(QtGui.QFileDialog.getOpenFileName(self.mainwindow, - translate('OpenLP.ServiceManager', 'Open File'), - SettingsManager.get_last_dir( - self.mainwindow.serviceSettingsSection), - translate('OpenLP.ServiceManager', 'OpenLP Service Files (*.osz)'))) - if not fileName: - return False + if not loadFile: + fileName = unicode(QtGui.QFileDialog.getOpenFileName( + self.mainwindow, + translate('OpenLP.ServiceManager', 'Open File'), + SettingsManager.get_last_dir( + self.mainwindow.serviceSettingsSection), + translate('OpenLP.ServiceManager', + 'OpenLP Service Files (*.osz)'))) + if not fileName: + return False + else: + fileName = loadFile SettingsManager.set_last_dir(self.mainwindow.serviceSettingsSection, split_filename(fileName)[0]) self.loadFile(fileName) @@ -1239,7 +1252,14 @@ class ServiceManager(QtGui.QWidget): Handle of the event pint passed """ link = event.mimeData() - if link.hasText(): + if event.mimeData().hasUrls(): + event.setDropAction(QtCore.Qt.CopyAction) + event.accept() + for url in event.mimeData().urls(): + filename = unicode(url.toLocalFile()) + if filename.endswith(u'.osz'): + self.onLoadServiceClicked(filename) + elif event.mimeData().hasText(): plugin = unicode(event.mimeData().text()) item = self.serviceManagerList.itemAt(event.pos()) # ServiceManager started the drag and drop diff --git a/openlp/plugins/images/lib/mediaitem.py b/openlp/plugins/images/lib/mediaitem.py index 3c4489bbc..acd420880 100644 --- a/openlp/plugins/images/lib/mediaitem.py +++ b/openlp/plugins/images/lib/mediaitem.py @@ -52,6 +52,8 @@ class ImageMediaItem(MediaManagerItem): self.hasSearch = True QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'live_theme_changed'), self.liveThemeChanged) + # Allow DnD from the desktop + self.listView.activateDnD() def retranslateUi(self): self.onNewPrompt = translate('ImagePlugin.MediaItem', @@ -131,6 +133,7 @@ class ImageMediaItem(MediaManagerItem): icon = self.iconFromFile(imageFile, thumb) item_name = QtGui.QListWidgetItem(filename) item_name.setIcon(icon) + item_name.setToolTip(imageFile) item_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(imageFile)) self.listView.addItem(item_name) if not initialLoad: diff --git a/openlp/plugins/media/lib/mediaitem.py b/openlp/plugins/media/lib/mediaitem.py index 77f91a529..e3c36bd77 100644 --- a/openlp/plugins/media/lib/mediaitem.py +++ b/openlp/plugins/media/lib/mediaitem.py @@ -39,6 +39,8 @@ from PyQt4.phonon import Phonon log = logging.getLogger(__name__) +CLAPPERBOARD = QtGui.QPixmap(u':/media/media_video.png').toImage() + class MediaMediaItem(MediaManagerItem): """ This is the custom media manager item for Media Slides. @@ -48,8 +50,7 @@ class MediaMediaItem(MediaManagerItem): def __init__(self, parent, plugin, icon): self.IconPath = u'images/image' self.background = False - self.PreviewFunction = QtGui.QPixmap( - u':/media/media_video.png').toImage() + self.PreviewFunction = CLAPPERBOARD MediaManagerItem.__init__(self, parent, plugin, icon) self.singleServiceItem = False self.hasSearch = True @@ -60,6 +61,8 @@ class MediaMediaItem(MediaManagerItem): QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'openlp_phonon_creation'), self.createPhonon) + # Allow DnD from the desktop + self.listView.activateDnD() def retranslateUi(self): self.onNewPrompt = translate('MediaPlugin.MediaItem', 'Select Media') @@ -201,17 +204,17 @@ class MediaMediaItem(MediaManagerItem): SettingsManager.set_list(self.settingsSection, u'media', self.getFileList()) - def loadList(self, files): + def loadList(self, media): # Sort the themes by its filename considering language specific # characters. lower() is needed for windows! - files.sort(cmp=locale.strcoll, + media.sort(cmp=locale.strcoll, key=lambda filename: os.path.split(unicode(filename))[1].lower()) - for file in files: - filename = os.path.split(unicode(file))[1] + for track in media: + filename = os.path.split(unicode(track))[1] item_name = QtGui.QListWidgetItem(filename) - img = QtGui.QPixmap(u':/media/media_video.png').toImage() - item_name.setIcon(build_icon(img)) - item_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(file)) + item_name.setIcon(build_icon(CLAPPERBOARD)) + item_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(track)) + item_name.setToolTip(track) self.listView.addItem(item_name) def createPhonon(self): diff --git a/openlp/plugins/presentations/lib/mediaitem.py b/openlp/plugins/presentations/lib/mediaitem.py index 07b490d83..85721c65d 100644 --- a/openlp/plugins/presentations/lib/mediaitem.py +++ b/openlp/plugins/presentations/lib/mediaitem.py @@ -58,6 +58,8 @@ class PresentationMediaItem(MediaManagerItem): self.hasSearch = True QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'mediaitem_presentation_rebuild'), self.rebuild) + # Allow DnD from the desktop + self.listView.activateDnD() def retranslateUi(self): """ @@ -205,6 +207,7 @@ class PresentationMediaItem(MediaManagerItem): item_name = QtGui.QListWidgetItem(filename) item_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(file)) item_name.setIcon(icon) + item_name.setToolTip(file) self.listView.addItem(item_name) Receiver.send_message(u'cursor_normal') if not initialLoad: diff --git a/openlp/plugins/songusage/songusageplugin.py b/openlp/plugins/songusage/songusageplugin.py index a657d700d..4ca23aeb0 100644 --- a/openlp/plugins/songusage/songusageplugin.py +++ b/openlp/plugins/songusage/songusageplugin.py @@ -91,8 +91,8 @@ class SongUsagePlugin(Plugin): self.toolsMenu.addAction(self.songUsageMenu.menuAction()) self.songUsageMenu.addAction(self.songUsageStatus) self.songUsageMenu.addSeparator() - self.songUsageMenu.addAction(self.songUsageDelete) self.songUsageMenu.addAction(self.songUsageReport) + self.songUsageMenu.addAction(self.songUsageDelete) self.songUsageActiveButton = QtGui.QToolButton( self.formparent.statusBar) self.songUsageActiveButton.setCheckable(True)