openlp-core team mailing list archive
-
openlp-core team
-
Mailing list archive
-
Message #19715
[Merge] lp:~arjan-i/openlp/images_groups into lp:openlp
Arjan Schrijver has proposed merging lp:~arjan-i/openlp/images_groups into lp:openlp.
Requested reviews:
Tim Bentley (trb143)
Andreas Preikschat (googol)
Raoul Snyman (raoul-snyman)
For more details, see:
https://code.launchpad.net/~arjan-i/openlp/images_groups/+merge/151525
This branch implements the 'images groups' feature. It has the following features:
- convert old 'images files' setting to SQLite database
- existing images are loaded into a special 'Imported' group
- groups can be nested
- images can be moved between groups by drag&drop
- new images can be added directly to a group by drag&drop, or by clicking the 'Add images' button
- image groups can be used as service items with multiple images
Okay, ready for another try.
All previous comments and ideas have been implemented/fixed.
Only thing missing now is loading images in a separate thread, but maybe I can implement that post-merge?
--
https://code.launchpad.net/~arjan-i/openlp/images_groups/+merge/151525
Your team OpenLP Core is subscribed to branch lp:openlp.
=== modified file 'openlp/core/lib/__init__.py'
--- openlp/core/lib/__init__.py 2013-03-01 17:45:17 +0000
+++ openlp/core/lib/__init__.py 2013-03-04 14:42:22 +0000
@@ -391,6 +391,7 @@
from screen import ScreenList
from settings import Settings
from listwidgetwithdnd import ListWidgetWithDnD
+from treewidgetwithdnd import TreeWidgetWithDnD
from formattingtags import FormattingTags
from spelltextedit import SpellTextEdit
from plugin import PluginStatus, StringContent, Plugin
=== modified file 'openlp/core/lib/mediamanageritem.py'
--- openlp/core/lib/mediamanageritem.py 2013-02-19 09:56:36 +0000
+++ openlp/core/lib/mediamanageritem.py 2013-03-04 14:42:22 +0000
@@ -338,7 +338,7 @@
self.validateAndLoad(files)
self.application.set_normal_cursor()
- def loadFile(self, files):
+ def loadFile(self, data):
"""
Turn file from Drag and Drop into an array so the Validate code can run it.
@@ -347,7 +347,7 @@
"""
new_files = []
error_shown = False
- for file_name in files:
+ for file_name in data['files']:
file_type = file_name.split(u'.')[-1]
if file_type.lower() not in self.onNewFileMasks:
if not error_shown:
@@ -357,9 +357,15 @@
else:
new_files.append(file_name)
if new_files:
- self.validateAndLoad(new_files)
-
- def validateAndLoad(self, files):
+ self.validateAndLoad(new_files, data['target'])
+
+ def dnd_move_internal(self, target):
+ """
+ Handle internal moving of media manager items
+ """
+ pass
+
+ def validateAndLoad(self, files, target_group=None):
"""
Process a list for files either from the File Dialog or from Drag and
Drop
@@ -374,16 +380,17 @@
full_list.append(self.listView.item(count).data(QtCore.Qt.UserRole))
duplicates_found = False
files_added = False
- for file in files:
- filename = os.path.split(unicode(file))[1]
+ for file_path in files:
+ filename = os.path.split(unicode(file_path))[1]
if filename in names:
duplicates_found = True
else:
files_added = True
full_list.append(file)
if full_list and files_added:
- self.listView.clear()
- self.loadList(full_list)
+ if target_group is None:
+ self.listView.clear()
+ self.loadList(full_list, target_group)
last_dir = os.path.split(unicode(files[0]))[0]
Settings().setValue(self.settingsSection + u'/last directory', last_dir)
Settings().setValue(u'%s/%s files' % (self.settingsSection, self.settingsSection), self.getFileList())
@@ -416,7 +423,7 @@
count += 1
return file_list
- def loadList(self, list):
+ def loadList(self, list, target_group):
"""
Load a list. Needs to be implemented by the plugin.
"""
=== modified file 'openlp/core/lib/plugin.py'
--- openlp/core/lib/plugin.py 2013-02-07 08:42:17 +0000
+++ openlp/core/lib/plugin.py 2013-03-04 14:42:22 +0000
@@ -216,6 +216,12 @@
if self.mediaItemClass:
self.mediaItem = self.mediaItemClass(self.main_window.mediaDockManager.media_dock, self, self.icon)
+ def upgrade_settings(self, settings):
+ """
+ Upgrade the settings of this plugin.
+ """
+ pass
+
def addImportMenuItem(self, importMenu):
"""
Create a menu item and add it to the "Import" menu.
@@ -300,24 +306,10 @@
# FIXME: Remove after 2.2 release.
# This is needed to load the list of images/media/presentation from the config saved
# before the settings rewrite.
- if self.mediaItemClass is not None:
- # We need QSettings instead of Settings here to bypass our central settings dict.
- # Do NOT do this anywhere else!
- settings = QtCore.QSettings()
- settings.beginGroup(self.settingsSection)
- if settings.contains(u'%s count' % self.name):
- list_count = int(settings.value(u'%s count' % self.name, 0))
- loaded_list = []
- if list_count:
- for counter in range(list_count):
- item = settings.value(u'%s %d' % (self.name, counter), u'')
- if item:
- loaded_list.append(item)
- settings.remove(u'%s %d' % (self.name, counter))
- settings.remove(u'%s count' % self.name)
- # Now save the list to the config using our Settings class.
- Settings().setValue(u'%s/%s files' % (self.settingsSection, self.name), loaded_list)
- settings.endGroup()
+ if self.mediaItemClass is not None and self.name != u'images':
+ loaded_list = Settings().get_files_from_config(self)
+ # Now save the list to the config using our Settings class.
+ Settings().setValue(u'%s/%s files' % (self.settingsSection, self.name), loaded_list)
def usesTheme(self, theme):
"""
=== modified file 'openlp/core/lib/pluginmanager.py'
--- openlp/core/lib/pluginmanager.py 2013-02-22 07:15:07 +0000
+++ openlp/core/lib/pluginmanager.py 2013-03-04 14:42:22 +0000
@@ -183,6 +183,17 @@
if plugin.status is not PluginStatus.Disabled:
plugin.addToolsMenuItem(self.main_window.tools_menu)
+ def hook_upgrade_plugin_settings(self, settings):
+ """
+ Loop through all the plugins and give them an opportunity to upgrade their settings.
+
+ ``settings``
+ The Settings object containing the old settings.
+ """
+ for plugin in self.plugins:
+ if plugin.status is not PluginStatus.Disabled:
+ plugin.upgrade_settings(settings)
+
def initialise_plugins(self):
"""
Loop through all the plugins and give them an opportunity to
=== modified file 'openlp/core/lib/settings.py'
--- openlp/core/lib/settings.py 2013-02-21 21:26:24 +0000
+++ openlp/core/lib/settings.py 2013-03-04 14:42:22 +0000
@@ -439,3 +439,32 @@
if isinstance(default_value, int):
return int(setting)
return setting
+
+ def get_files_from_config(self, plugin):
+ """
+ This removes the settings needed for old way we saved files (e. g. the image paths for the image plugin). A list
+ of file paths are returned.
+
+ **Note**: Only a list of paths is returned; this does not convert anything!
+
+ ``plugin``
+ The Plugin object.The caller has to convert/save the list himself; o
+ """
+ files_list = []
+ # We need QSettings instead of Settings here to bypass our central settings dict.
+ # Do NOT do this anywhere else!
+ settings = QtCore.QSettings(self.fileName(), Settings.IniFormat)
+ settings.beginGroup(plugin.settingsSection)
+ if settings.contains(u'%s count' % plugin.name):
+ # Get the count.
+ list_count = int(settings.value(u'%s count' % plugin.name, 0))
+ if list_count:
+ for counter in range(list_count):
+ # The keys were named e. g.: "image 0"
+ item = settings.value(u'%s %d' % (plugin.name, counter), u'')
+ if item:
+ files_list.append(item)
+ settings.remove(u'%s %d' % (plugin.name, counter))
+ settings.remove(u'%s count' % plugin.name)
+ settings.endGroup()
+ return files_list
=== added file 'openlp/core/lib/treewidgetwithdnd.py'
--- openlp/core/lib/treewidgetwithdnd.py 1970-01-01 00:00:00 +0000
+++ openlp/core/lib/treewidgetwithdnd.py 2013-03-04 14:42:22 +0000
@@ -0,0 +1,137 @@
+# -*- coding: utf-8 -*-
+# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
+
+###############################################################################
+# OpenLP - Open Source Lyrics Projection #
+# --------------------------------------------------------------------------- #
+# Copyright (c) 2008-2013 Raoul Snyman #
+# Portions copyright (c) 2008-2013 Tim Bentley, Gerald Britton, Jonathan #
+# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, #
+# Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer. #
+# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru, #
+# Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, #
+# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Dave Warnock, #
+# Frode Woldsund, Martin Zibricky, Patrick Zimmermann #
+# --------------------------------------------------------------------------- #
+# This program is free software; you can redistribute it and/or modify it #
+# under the terms of the GNU General Public License as published by the Free #
+# Software Foundation; version 2 of the License. #
+# #
+# This program is distributed in the hope that it will be useful, but WITHOUT #
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
+# more details. #
+# #
+# You should have received a copy of the GNU General Public License along #
+# with this program; if not, write to the Free Software Foundation, Inc., 59 #
+# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
+###############################################################################
+"""
+Extend QTreeWidget to handle drag and drop functionality
+"""
+import os
+
+from PyQt4 import QtCore, QtGui
+
+from openlp.core.lib import Registry
+
+
+class TreeWidgetWithDnD(QtGui.QTreeWidget):
+ """
+ Provide a tree widget to store objects and handle drag and drop events
+ """
+ def __init__(self, parent=None, name=u''):
+ """
+ Initialise the tree widget
+ """
+ QtGui.QTreeWidget.__init__(self, parent)
+ self.mimeDataText = name
+ self.allow_internal_dnd = False
+ self.header().close()
+ self.defaultIndentation = self.indentation()
+ self.setIndentation(0)
+ self.setAnimated(True)
+ assert(self.mimeDataText)
+
+ def activateDnD(self):
+ """
+ Activate DnD of widget
+ """
+ self.setAcceptDrops(True)
+ self.setDragDropMode(QtGui.QAbstractItemView.DragDrop)
+ Registry().register_function((u'%s_dnd' % self.mimeDataText), self.parent().loadFile)
+ Registry().register_function((u'%s_dnd_internal' % self.mimeDataText), self.parent().dnd_move_internal)
+
+ def mouseMoveEvent(self, event):
+ """
+ Drag and drop event does not care what data is selected
+ as the recipient will use events to request the data move
+ just tell it what plugin to call
+ """
+ if event.buttons() != QtCore.Qt.LeftButton:
+ event.ignore()
+ return
+ if not self.selectedItems():
+ event.ignore()
+ return
+ drag = QtGui.QDrag(self)
+ mimeData = QtCore.QMimeData()
+ drag.setMimeData(mimeData)
+ mimeData.setText(self.mimeDataText)
+ drag.start(QtCore.Qt.CopyAction)
+
+ def dragEnterEvent(self, event):
+ if event.mimeData().hasUrls():
+ event.accept()
+ elif self.allow_internal_dnd:
+ event.accept()
+ else:
+ event.ignore()
+
+ def dragMoveEvent(self, event):
+ QtGui.QTreeWidget.dragMoveEvent(self, event)
+ if event.mimeData().hasUrls():
+ event.setDropAction(QtCore.Qt.CopyAction)
+ event.accept()
+ elif self.allow_internal_dnd:
+ event.setDropAction(QtCore.Qt.CopyAction)
+ event.accept()
+ else:
+ event.ignore()
+
+ def dropEvent(self, event):
+ """
+ Receive drop event, check if it is a file or internal object 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 = url.toLocalFile()
+ if os.path.isfile(localFile):
+ files.append(localFile)
+ elif os.path.isdir(localFile):
+ listing = os.listdir(localFile)
+ for file_name in listing:
+ files.append(os.path.join(localFile, file_name))
+ Registry().execute(u'%s_dnd' % self.mimeDataText, {'files': files, 'target': self.itemAt(event.pos())})
+ elif self.allow_internal_dnd:
+ event.setDropAction(QtCore.Qt.CopyAction)
+ event.accept()
+ Registry().execute(u'%s_dnd_internal' % self.mimeDataText, self.itemAt(event.pos()))
+ else:
+ event.ignore()
+
+ # Convenience methods for emulating a QListWidget. This helps keeping MediaManagerItem simple.
+ def addItem(self, item):
+ self.addTopLevelItem(item)
+
+ def count(self):
+ return self.topLevelItemCount()
+
+ def item(self, index):
+ return self.topLevelItem(index)
=== modified file 'openlp/core/lib/uistrings.py'
--- openlp/core/lib/uistrings.py 2013-02-01 19:58:18 +0000
+++ openlp/core/lib/uistrings.py 2013-03-04 14:42:22 +0000
@@ -58,6 +58,7 @@
"""
self.About = translate('OpenLP.Ui', 'About')
self.Add = translate('OpenLP.Ui', '&Add')
+ self.AddGroup = translate('OpenLP.Ui', 'Add group')
self.Advanced = translate('OpenLP.Ui', 'Advanced')
self.AllFiles = translate('OpenLP.Ui', 'All Files')
self.Automatic = translate('OpenLP.Ui', 'Automatic')
=== modified file 'openlp/core/resources.py'
--- openlp/core/resources.py 2012-12-29 20:56:56 +0000
+++ openlp/core/resources.py 2013-03-04 14:42:22 +0000
@@ -54736,6 +54736,156 @@
\x89\x3e\x62\x80\x70\x10\xc3\x84\x9d\xb0\x11\x66\xa2\x8b\xe8\x6c\
\x7e\xaa\x0f\xd9\x9d\x89\x07\xa1\xb5\x4b\xa0\x00\x00\x00\x00\x49\
\x45\x4e\x44\xae\x42\x60\x82\
+\x00\x00\x06\x1a\
+\x89\
+\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
+\x00\x00\x20\x00\x00\x00\x20\x08\x06\x00\x00\x00\x73\x7a\x7a\xf4\
+\x00\x00\x00\x01\x73\x52\x47\x42\x00\xae\xce\x1c\xe9\x00\x00\x00\
+\x06\x62\x4b\x47\x44\x00\xff\x00\xff\x00\xff\xa0\xbd\xa7\x93\x00\
+\x00\x00\x09\x70\x48\x59\x73\x00\x00\x0d\xd7\x00\x00\x0d\xd7\x01\
+\x42\x28\x9b\x78\x00\x00\x00\x07\x74\x49\x4d\x45\x07\xdb\x04\x1e\
+\x15\x05\x2e\x4a\x27\x58\x31\x00\x00\x05\x9a\x49\x44\x41\x54\x58\
+\xc3\xed\x97\x3d\xa8\x6d\x57\x11\xc7\x7f\xb3\xd6\xda\xfb\xdc\xeb\
+\x7b\xde\x24\x48\x22\x1a\x7d\x88\x36\x0a\x06\x21\x29\x83\x4d\x0a\
+\x31\x58\xa4\x30\xa4\xb1\x10\x3b\x1b\x4b\x8b\x80\x8d\x8d\x76\xd6\
+\x16\x06\xb4\x13\x2c\x6d\x44\x50\xb1\x08\x04\x12\x25\x8f\x18\x62\
+\x11\xcd\xcb\x33\x79\x1f\xbe\xfb\xee\xbb\x79\xf7\x9e\x8f\xfd\xb1\
+\x66\x2c\x66\xd6\xdd\xe7\x11\x04\x0b\x25\x8d\x07\x0e\x7b\x9f\x75\
+\x67\xad\x99\xf9\xcf\x7f\xfe\x6b\x2e\x7c\xd4\x9f\x17\x5e\xfc\xdd\
+\x7f\x6c\xfb\xfc\x0f\x7e\xff\x5f\xf7\x2f\x00\xcf\xbf\xf8\x87\xd7\
+\x86\x71\xf7\x94\x98\xa0\xe2\x8b\x19\x98\x01\xc1\x48\x29\xd3\x77\
+\xe5\x2f\xbf\xfa\xd1\x33\x4f\xfc\x4f\x02\xf8\xda\x77\x7f\x69\xdf\
+\xfe\xd6\x37\xb8\x75\x67\x64\xae\xa0\x06\x25\xf9\x5f\x0f\x8a\x60\
+\xba\xe1\xb7\x7f\x7c\xdd\x72\x29\x82\x08\x02\x18\x60\xe6\x36\x62\
+\x60\x02\x28\x68\x1c\x2a\xe2\xe7\x08\x90\x80\x1a\x4f\xff\x18\x66\
+\xc3\xb3\xbf\xfe\xc9\x73\xbf\x29\x00\xc3\x70\x9f\x57\xdf\x3c\xe5\
+\x9f\xa7\x5b\x4a\x1c\x2e\xe2\x0e\x0c\xf8\xec\x27\x7b\xbe\xfc\xc4\
+\x57\xa4\x64\xc1\x30\xb2\xb8\xc3\x92\x05\x80\x94\x84\x2c\x20\x22\
+\x74\xc9\xf7\x20\x42\x4e\x90\x04\x04\x7f\x37\x20\x27\xa8\x92\xec\
+\xe5\x57\xde\xf8\x1e\xe0\x01\xe8\xbc\xe5\xde\xe9\x39\xd9\x26\x66\
+\x15\x77\x1e\x99\x18\x70\xfd\xe6\x8e\x69\xae\xd4\x71\xc3\x6e\xd8\
+\xa1\xb5\xe2\x38\x84\xb3\x28\x15\x91\x29\x0a\x29\x81\xa9\x41\xf2\
+\xcc\x67\x83\x2c\x50\xab\xf0\xa9\xc7\x1e\x92\x5b\x37\xaf\xf5\x00\
+\x05\xc0\x52\x66\x33\x6c\x40\xf5\x02\xd6\xe4\xe7\xf8\x66\x55\xe6\
+\xdd\x39\xc7\x77\xde\xe3\xf8\xd6\x0d\xc6\x71\x70\x38\x5b\xa0\x06\
+\xd6\x42\x12\x2e\x02\x13\x96\xf7\x8b\x48\x13\xdc\xbc\xf6\x71\xee\
+\xdf\x7b\x6f\xba\x08\x60\x7b\x7e\xc6\xbd\xe3\xf7\x31\x53\x72\x38\
+\x6e\x28\x60\x80\x56\xce\xcf\x3e\xe0\xc6\xbb\x6f\xf3\xf3\x97\x7e\
+\x48\xea\x0a\x27\x67\x20\xe9\xdf\x30\xcb\x3e\xcc\xb4\x07\x02\x52\
+\xc0\x78\xf6\xee\xc9\x8f\x5f\x2b\x00\xff\x78\xe7\x2d\xee\x1c\xaf\
+\x31\x53\xa4\x65\xd0\x08\x06\xa8\x29\x75\x1c\x78\xec\xd1\x47\xf8\
+\x60\x53\xf8\xf3\x55\x63\x00\xfa\x46\xc6\xe6\x27\x08\x99\x62\xad\
+\xe2\xb0\xcf\xe6\x99\x2a\x0b\x49\x53\x16\xce\x8e\xaf\x3f\x55\xbe\
+\xff\xb3\x3f\xfd\xed\xab\x4f\x3f\x69\xd3\xc4\x42\xef\x7d\xec\xf6\
+\xd6\xd6\x6b\xb8\xfa\x57\x85\x64\x94\x60\xbe\x98\x13\x2d\x1b\x4c\
+\x41\x4e\x0c\xaa\x2c\x9d\xd2\x08\x88\x41\xd7\xce\x96\xcc\xe9\xc9\
+\x6d\xca\xdb\xd7\xee\x7f\xfe\xd2\x0a\xd6\xb3\xd2\x45\xc6\x3b\x83\
+\x55\x23\x54\x64\x61\x06\x2a\x70\x98\x8d\xd9\x84\x3e\x81\x6a\xb4\
+\x97\xc1\x18\x4f\x42\x3f\x52\x20\x31\x0b\x88\x7a\x5b\x57\xf3\xaf\
+\x02\x1d\x30\x6e\xd7\x94\x79\xda\x52\x13\xf4\xd9\xfb\x76\x06\xfa\
+\x88\xb2\xc6\x7b\xb5\xa5\x8e\x93\x09\x09\xd8\xd5\x05\x28\x88\x00\
+\x80\x12\x90\x27\x1c\x19\x0b\xcc\xc7\xba\x00\xaa\xc0\x60\x5e\xda\
+\x92\x80\x5a\x61\xae\xae\x7e\x29\x04\x44\x81\x95\xc0\xa4\xd0\x27\
+\x18\x14\x0e\xc5\x9f\xb6\x87\x4c\x8d\xa0\x4b\x70\x20\x05\xc9\x7a\
+\x81\xad\xfa\x99\x35\x02\x9b\x82\x0b\x86\x97\x22\x1b\x94\x6a\x0b\
+\x5c\xd5\xa0\x33\x18\xcd\x0f\xab\xea\xb5\x5c\xcf\x70\x00\x6c\x65\
+\xc9\x0c\xf5\x92\x68\x70\x00\x83\x09\x18\xe2\xf0\x4d\x38\x6b\x28\
+\xcc\xb1\xae\xc1\x8b\x39\x92\x49\x62\x30\xab\x1b\xa9\xc2\x4e\xdd\
+\xb0\x6a\x1c\xee\x9c\x63\x17\x81\xaa\xfa\xdf\x30\x18\x23\x43\x55\
+\x0f\xfa\x80\x65\x1d\xf5\x73\x35\x6c\xab\xb9\xe3\xaa\xfe\x2c\x16\
+\x92\xdf\x7a\x7e\xa7\xd6\x74\x82\x5d\x75\xd2\x98\x3e\xd8\x3a\x16\
+\xc8\x0c\xba\x68\xfc\x2e\xea\x71\x39\xc1\x46\x97\x0b\x46\x81\x83\
+\x58\x6b\x5c\x19\xcd\xcb\x71\x98\x22\x51\x33\x0a\x06\xd3\xec\x3b\
+\x2c\x36\xf6\x51\x8e\x29\xd8\xdb\xca\xb1\xdf\xa5\x29\xd8\x7e\x88\
+\x97\xe2\x6c\x0e\x1d\x08\xc8\x33\x8e\xc4\x7e\x57\x2b\x70\x20\xb0\
+\x9b\x21\x97\x40\x55\x82\x91\xad\x47\x25\xe0\x9e\xc3\xb9\x9a\x93\
+\x34\xc5\xcd\x36\x86\xad\x0a\xf4\x61\x3b\x05\x52\xd9\x9c\xcc\x12\
+\xb6\x35\x6c\x4d\x7c\xbf\x85\xed\x8c\xb7\x66\x6a\x25\xb8\x94\x60\
+\x3b\x39\x4b\xa7\x80\xb4\x34\xb2\xd8\xc2\x70\x31\x38\xcc\x8e\x58\
+\x0d\xdb\x96\xe1\x4a\x3c\x91\xdc\xa4\x37\x04\x48\x15\x74\xf6\x00\
+\xa7\x38\xb7\x8f\x8e\x50\x85\x64\x06\x75\x8e\x0b\x45\x9d\x48\x16\
+\x41\xec\x14\x56\xc9\x37\xd5\x20\xd7\x34\x7b\xe4\x35\x6c\x5b\x07\
+\x6d\xd4\xed\xba\xa8\x93\x2a\x8c\xcd\xd6\xbc\xac\x5d\x70\x60\xab\
+\x0e\x7d\x0f\x94\x24\x89\x22\x60\x25\x5f\xd4\xec\xa1\xe4\xd1\xae\
+\x22\xbb\x51\x96\x16\xc2\xa0\xcb\x4b\x7d\x2f\x25\x6f\xbd\x23\x60\
+\x4b\x74\x4e\x5a\xa4\x7c\x15\x02\x56\xcd\x33\xcf\x02\x97\x81\x41\
+\x60\x22\x21\x57\x5e\xf8\xa9\xe5\xf2\x09\xa6\xb8\x88\x9a\x1e\xb4\
+\xcb\xe3\xe2\x82\x0b\x58\x1b\x7c\xd2\x32\x8d\xf1\xed\xa2\x53\x62\
+\x5d\x42\x03\xaa\x2d\x17\x95\xed\xdd\x92\x39\x65\xb6\xf7\xae\x53\
+\x1e\x7f\xe4\x88\xd5\xd1\x97\x28\x36\x2f\x63\xd6\xfe\xf5\x1d\x07\
+\xda\x5e\x20\xcd\x20\x45\xab\xee\xdf\xbe\x79\x6f\x14\xab\xb1\x37\
+\x45\x77\xec\x8f\x6c\x2a\x99\xd3\xdd\x6d\x8a\xaa\x32\x0d\x03\xa3\
+\xd5\xc5\x09\x0f\x0e\x24\xda\xe4\xb3\x21\xc1\xa2\x80\x31\xf4\x7c\
+\xc8\xb6\x44\x7b\xb6\x69\xa8\x49\x71\x17\xa8\xe4\x94\x18\xe7\x4a\
+\xf9\xe2\x95\xcf\xf0\x85\x2b\x4f\x82\x98\xf7\x6f\xe8\xbf\x8a\x6b\
+\xff\x5a\x21\x37\x41\xcf\x20\xd5\x33\x6f\x53\xb3\x6a\x9b\xfb\xfc\
+\x3b\xed\x4d\xa0\xa2\xb0\xca\x4e\xd8\x91\xa5\xcd\x27\x83\x55\x16\
+\xfe\x7e\x79\x4d\xb9\x79\x77\xcd\xd1\x25\x98\x6c\x66\x32\xc8\x0a\
+\xa5\x38\xc9\xba\xbd\x8c\x14\xbf\x94\x74\xef\x9e\x50\x85\x2e\x39\
+\x49\x53\x75\x67\x63\x68\x44\x8a\xc9\xda\x22\xc8\xa6\xb2\x43\xe8\
+\x47\x97\x0b\x37\x6e\x9f\x53\xcc\x60\xb0\x13\x36\xb5\xba\xf0\xc4\
+\xa6\x55\xf2\x20\xe6\xa8\x49\x1f\xbf\x53\x82\xf3\x1a\xec\x4e\xfe\
+\x2d\x0a\xb9\x77\x2d\x69\xce\x15\xa8\x09\x76\x53\x8c\xe8\x91\x40\
+\xae\xa0\x1d\xec\xa6\x84\xa1\x94\x92\xba\xf7\xc7\xfb\x77\x1f\xcf\
+\xa2\x58\x0e\x19\xed\x84\xd3\x31\x7a\x35\xb9\xba\xad\x81\xbe\x73\
+\x1d\x38\xc0\xe7\xc1\x41\xe1\xa0\x87\xcd\xe8\x0e\x4a\x81\x3a\x04\
+\xfc\x02\xab\xe2\xea\xd3\x65\x17\xa9\x2a\xce\xb2\x71\x0d\x86\x72\
+\xf4\xf0\xa7\xaf\x3a\xa7\x1f\xfe\xdc\x77\x48\xf9\x63\xbe\xd5\x04\
+\xc3\x87\x2b\xd3\xb4\xc7\xfd\x84\x59\x0a\x24\xc5\xdf\x2d\x61\x26\
+\x48\x52\x04\x05\x31\x84\xea\xd5\xc7\x30\x0c\x11\xbf\x47\x93\xe8\
+\xc5\x6f\x41\x31\xdd\x70\xf2\xce\x2f\xe0\xeb\x1f\xe1\x3f\xa6\xdf\
+\xe4\xff\x1f\xfe\x05\xfe\x09\x43\x47\xb1\x8e\x8c\x2b\x00\x00\x00\
+\x00\x49\x45\x4e\x44\xae\x42\x60\x82\
+\x00\x00\x02\xfa\
+\x89\
+\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
+\x00\x00\x10\x00\x00\x00\x10\x08\x06\x00\x00\x00\x1f\xf3\xff\x61\
+\x00\x00\x00\x01\x73\x52\x47\x42\x00\xae\xce\x1c\xe9\x00\x00\x00\
+\x06\x62\x4b\x47\x44\x00\xff\x00\xff\x00\xff\xa0\xbd\xa7\x93\x00\
+\x00\x00\x09\x70\x48\x59\x73\x00\x00\x0d\xd7\x00\x00\x0d\xd7\x01\
+\x42\x28\x9b\x78\x00\x00\x00\x07\x74\x49\x4d\x45\x07\xdb\x05\x08\
+\x12\x0c\x27\xaf\x64\x6c\xaa\x00\x00\x02\x7a\x49\x44\x41\x54\x38\
+\xcb\x75\x93\x4b\x48\x94\x51\x14\xc7\x7f\xe7\x7e\xd7\xc9\xc7\x44\
+\x0f\xe8\x81\x15\x11\xd4\x2a\x2b\xe8\xe1\xae\xd2\x4a\x43\x82\x28\
+\x1a\x83\x08\x6a\xd5\xaa\x5d\x41\x24\x04\x6d\x02\x0b\x5a\x44\x11\
+\xb4\xab\x55\xf4\x58\x48\x60\x14\x49\x2e\x4c\xa4\xa0\x24\x7a\x40\
+\x0a\x16\xbd\x4c\x1c\x2b\xc7\x79\x98\xf3\x7d\xf7\x9e\x16\xdf\x8c\
+\x8c\x50\x77\x73\xe1\xc0\xf9\xfd\x7f\xe7\x70\x2f\xfc\xe7\xa4\xce\
+\x77\xcf\x2d\x5c\xe2\x50\x53\x77\xf3\x87\xa3\xcf\x8e\xba\xa6\xee\
+\xe6\x21\x2e\x71\x08\x40\x52\xe7\x1f\xbe\x70\x62\x1a\x51\x10\x00\
+\x15\x6c\x22\x78\x7f\xef\x5c\x4b\xc3\x6c\xf3\x55\x0e\xb4\x6c\x6d\
+\xe9\xda\xb5\x64\x8b\x9e\x5d\xdb\x29\x17\x47\x3a\xb4\x77\xfc\x95\
+\xf4\x0c\xf4\xa4\xa4\xed\xd4\x6d\x6d\xdd\xdb\x86\xba\x10\x63\x84\
+\x20\xb0\x3c\xee\xed\xd3\x44\x22\x21\x88\x61\x9e\x5b\xc0\xdd\x55\
+\xad\x34\xac\x4c\xea\xc2\xdc\xa8\xf4\xb5\x2b\x3b\xee\x0b\x93\xc9\
+\x7a\x7d\x3b\x36\x3a\x6c\x73\x99\x09\xa6\x0b\x53\xbc\x1e\x99\xc0\
+\x60\x58\xb3\xac\x86\x9d\x8d\x9b\xc4\x23\x28\x50\xab\x4b\xb8\x33\
+\x3c\xc5\x9b\x13\x19\x29\x0b\xf5\xb5\x2b\x80\xc8\x65\x59\x67\xa7\
+\x7e\x8d\x91\xc9\xe6\x89\xa6\xf3\x04\x06\x86\x3e\x67\x71\xa1\x23\
+\x9d\xfe\x46\x2e\x33\x49\x55\x34\x1f\xda\x40\x6e\x08\x75\xbf\x21\
+\xd7\xa1\x24\x3b\x85\xfc\x22\x60\x0d\xc3\x36\x33\x31\xca\x9b\xc1\
+\x17\x7c\xfc\x9a\x26\x30\x02\x08\x7f\xa6\xb3\xec\xdb\xbd\x99\x83\
+\xfb\x0f\x22\xde\xf0\x34\x6b\xb8\xf0\xe5\x18\xf9\x92\x41\x7e\x11\
+\xb0\x02\x52\xe6\x54\x5a\x52\x1d\x37\xf5\xf4\xc9\x23\x64\x0b\x33\
+\x18\x13\x5b\xaa\x0a\x33\x33\x45\x86\x47\x7e\x13\x46\x4a\x35\xb5\
+\x0c\x26\x1f\x70\xdb\x9f\x21\xfc\x91\x23\x51\x9f\xe4\x78\xcd\x35\
+\xd2\xb7\x3e\x61\x35\xa8\xa5\xff\xe5\x0f\xa2\x62\x31\x6e\x2e\xa5\
+\x18\x11\x34\x80\x2a\x81\x22\x05\x36\xe4\xdb\xb8\xa2\x87\xb1\x0b\
+\x12\x44\xf9\x19\xbc\x73\xf4\x98\xeb\x58\x55\xc1\x08\x50\x4a\x0f\
+\x00\x57\x06\x79\x28\x02\x16\x25\x24\x24\xe4\x57\x09\xaf\x54\xf9\
+\x3a\x50\xb0\xaa\x10\x79\xc5\x79\x45\x80\x08\x30\x80\x53\x10\x89\
+\xdf\x46\xb1\x04\x34\x65\xb0\x82\xf5\x4a\xa4\x8a\x55\x55\xbc\x53\
+\x22\x17\x03\xca\x63\x28\x71\xb3\xaf\x78\x8c\x5a\x31\x62\xe4\x3c\
+\xea\x15\x2b\x22\x18\x13\x10\x18\x3f\x3b\x42\x39\xcd\x97\x6e\xa9\
+\x80\xc5\x75\xc5\x04\x01\x06\xc1\x8e\xfd\xcc\xf0\xe8\xf9\x3b\xd4\
+\x47\x73\x92\x4c\x85\x85\xfe\xe3\xaf\xd8\x44\x0d\xdf\xbe\x8f\x63\
+\x57\x2f\x5f\xcc\xa6\x8d\xeb\x71\x51\x38\x9b\x54\xa9\x5a\x59\xf3\
+\x15\xe0\xc4\xbc\x1a\x06\xc6\x9f\x63\xa7\x0a\xc5\x27\xc5\xd0\xb7\
+\x46\xa1\x22\x02\x5e\xe3\x45\x56\x11\x2f\xb1\xac\x14\x96\x40\x56\
+\x00\x55\x1c\x8e\x42\xa8\x5d\xc2\xd2\x6d\x7b\x88\xc2\xed\x80\xa0\
+\x6a\x10\x04\x55\x99\x1d\x5f\x15\x44\x4a\x02\x12\xcb\x89\x78\x14\
+\xa5\xba\xb6\xff\x2f\x62\x10\x26\x9d\x60\xcb\xdf\xa1\x00\x00\x00\
+\x00\x49\x45\x4e\x44\xae\x42\x60\x82\
\x00\x00\x0a\x90\
\x89\
\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
@@ -71235,6 +71385,10 @@
\x00\x69\
\x00\x63\x00\x6f\x00\x6e\
\x00\x06\
+\x07\x03\x7d\xc3\
+\x00\x69\
+\x00\x6d\x00\x61\x00\x67\x00\x65\x00\x73\
+\x00\x06\
\x06\x8f\x92\xc3\
\x00\x62\
\x00\x69\x00\x62\x00\x6c\x00\x65\x00\x73\
@@ -71366,6 +71520,15 @@
\x00\x62\
\x00\x69\x00\x62\x00\x6c\x00\x65\x00\x73\x00\x5f\x00\x73\x00\x65\x00\x61\x00\x72\x00\x63\x00\x68\x00\x5f\x00\x75\x00\x6e\x00\x6c\
\x00\x6f\x00\x63\x00\x6b\x00\x2e\x00\x70\x00\x6e\x00\x67\
+\x00\x0f\
+\x09\x74\x2a\xa7\
+\x00\x69\
+\x00\x6d\x00\x61\x00\x67\x00\x65\x00\x5f\x00\x67\x00\x72\x00\x6f\x00\x75\x00\x70\x00\x2e\x00\x70\x00\x6e\x00\x67\
+\x00\x13\
+\x0f\x86\x85\x67\
+\x00\x69\
+\x00\x6d\x00\x61\x00\x67\x00\x65\x00\x5f\x00\x6e\x00\x65\x00\x77\x00\x5f\x00\x67\x00\x72\x00\x6f\x00\x75\x00\x70\x00\x2e\x00\x70\
+\x00\x6e\x00\x67\
\x00\x15\
\x00\x76\xd9\xc7\
\x00\x6f\
@@ -71833,148 +71996,151 @@
"
qt_resource_struct = "\
-\x00\x00\x00\x00\x00\x02\x00\x00\x00\x12\x00\x00\x00\x01\
-\x00\x00\x00\xe6\x00\x02\x00\x00\x00\x06\x00\x00\x00\x88\
-\x00\x00\x00\x00\x00\x02\x00\x00\x00\x04\x00\x00\x00\x84\
-\x00\x00\x00\xb4\x00\x02\x00\x00\x00\x08\x00\x00\x00\x7c\
-\x00\x00\x00\xd6\x00\x02\x00\x00\x00\x14\x00\x00\x00\x68\
-\x00\x00\x00\x2c\x00\x02\x00\x00\x00\x02\x00\x00\x00\x66\
-\x00\x00\x00\x14\x00\x02\x00\x00\x00\x02\x00\x00\x00\x64\
-\x00\x00\x00\xf4\x00\x02\x00\x00\x00\x05\x00\x00\x00\x5f\
-\x00\x00\x01\x2e\x00\x02\x00\x00\x00\x09\x00\x00\x00\x56\
-\x00\x00\x00\x8c\x00\x02\x00\x00\x00\x0a\x00\x00\x00\x4c\
-\x00\x00\x00\xc4\x00\x02\x00\x00\x00\x03\x00\x00\x00\x49\
-\x00\x00\x00\x3c\x00\x02\x00\x00\x00\x10\x00\x00\x00\x39\
-\x00\x00\x00\x62\x00\x02\x00\x00\x00\x03\x00\x00\x00\x36\
-\x00\x00\x00\x78\x00\x02\x00\x00\x00\x01\x00\x00\x00\x35\
-\x00\x00\x01\x42\x00\x02\x00\x00\x00\x03\x00\x00\x00\x32\
-\x00\x00\x00\x9e\x00\x02\x00\x00\x00\x08\x00\x00\x00\x2a\
-\x00\x00\x01\x1a\x00\x02\x00\x00\x00\x01\x00\x00\x00\x29\
-\x00\x00\x00\x4e\x00\x02\x00\x00\x00\x11\x00\x00\x00\x18\
-\x00\x00\x01\x06\x00\x02\x00\x00\x00\x05\x00\x00\x00\x13\
-\x00\x00\x04\x4c\x00\x00\x00\x00\x00\x01\x00\x0a\xa7\x31\
-\x00\x00\x03\x8a\x00\x00\x00\x00\x00\x01\x00\x00\x23\xa9\
-\x00\x00\x03\xec\x00\x00\x00\x00\x00\x01\x00\x05\x65\x6d\
-\x00\x00\x04\x1a\x00\x00\x00\x00\x00\x01\x00\x08\x06\x4f\
-\x00\x00\x03\xbc\x00\x00\x00\x00\x00\x01\x00\x02\xc4\x8b\
-\x00\x00\x10\x18\x00\x00\x00\x00\x00\x01\x00\x10\xd7\x23\
-\x00\x00\x10\x88\x00\x00\x00\x00\x00\x01\x00\x10\xde\x6e\
-\x00\x00\x0f\xc8\x00\x00\x00\x00\x00\x01\x00\x10\xd1\xc7\
-\x00\x00\x11\x66\x00\x00\x00\x00\x00\x01\x00\x10\xf0\xec\
-\x00\x00\x10\xe8\x00\x00\x00\x00\x00\x01\x00\x10\xe6\x84\
-\x00\x00\x0f\x70\x00\x00\x00\x00\x00\x01\x00\x10\xca\x90\
-\x00\x00\x11\xb8\x00\x00\x00\x00\x00\x01\x00\x10\xf6\xf3\
-\x00\x00\x10\xb0\x00\x00\x00\x00\x00\x01\x00\x10\xe1\xe2\
-\x00\x00\x12\x06\x00\x00\x00\x00\x00\x01\x00\x10\xfc\x1f\
-\x00\x00\x0f\x9a\x00\x00\x00\x00\x00\x01\x00\x10\xcd\x2e\
-\x00\x00\x11\x92\x00\x00\x00\x00\x00\x01\x00\x10\xf4\x1f\
-\x00\x00\x11\x3c\x00\x00\x00\x00\x00\x01\x00\x10\xee\x74\
-\x00\x00\x0f\xee\x00\x00\x00\x00\x00\x01\x00\x10\xd4\xa1\
-\x00\x00\x11\xe2\x00\x00\x00\x00\x00\x01\x00\x10\xf9\xd8\
-\x00\x00\x11\x10\x00\x00\x00\x00\x00\x01\x00\x10\xe9\xc9\
-\x00\x00\x10\x64\x00\x00\x00\x00\x00\x01\x00\x10\xdb\x71\
-\x00\x00\x10\x3e\x00\x00\x00\x00\x00\x01\x00\x10\xd9\x5a\
-\x00\x00\x03\x66\x00\x00\x00\x00\x00\x01\x00\x00\x21\x92\
-\x00\x00\x0c\x30\x00\x00\x00\x00\x00\x01\x00\x0f\x4c\x08\
-\x00\x00\x0c\xb0\x00\x00\x00\x00\x00\x01\x00\x0f\x52\xce\
-\x00\x00\x0b\xb4\x00\x00\x00\x00\x00\x01\x00\x0f\x45\x04\
-\x00\x00\x0c\x58\x00\x00\x00\x00\x00\x01\x00\x0f\x4e\xa8\
-\x00\x00\x0c\xda\x00\x00\x00\x00\x00\x01\x00\x0f\x55\x99\
-\x00\x00\x0b\xfe\x00\x00\x00\x00\x00\x01\x00\x0f\x4a\x1e\
-\x00\x00\x0b\xd8\x00\x00\x00\x00\x00\x01\x00\x0f\x47\xab\
-\x00\x00\x0c\x8e\x00\x00\x00\x00\x00\x01\x00\x0f\x50\x2a\
-\x00\x00\x01\x5c\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\
-\x00\x00\x01\xc2\x00\x00\x00\x00\x00\x01\x00\x00\x05\xe6\
-\x00\x00\x01\x8e\x00\x00\x00\x00\x00\x01\x00\x00\x02\xfe\
-\x00\x00\x0e\xc0\x00\x00\x00\x00\x00\x01\x00\x0f\x70\xe7\
-\x00\x00\x0e\xea\x00\x00\x00\x00\x00\x01\x00\x0f\x76\x51\
-\x00\x00\x0f\x1a\x00\x00\x00\x00\x00\x01\x00\x0f\xe4\xda\
-\x00\x00\x0f\x3a\x00\x00\x00\x00\x00\x01\x00\x0f\xeb\x8b\
-\x00\x00\x12\x88\x00\x00\x00\x00\x00\x01\x00\x11\x03\x33\
-\x00\x00\x12\x2e\x00\x00\x00\x00\x00\x01\x00\x10\xfe\x32\
-\x00\x00\x14\xa4\x00\x00\x00\x00\x00\x01\x00\x11\x2d\x38\
-\x00\x00\x13\x2e\x00\x00\x00\x00\x00\x01\x00\x11\x0b\x3d\
-\x00\x00\x12\xca\x00\x00\x00\x00\x00\x01\x00\x11\x06\x86\
-\x00\x00\x12\x54\x00\x00\x00\x00\x00\x01\x00\x11\x01\x63\
-\x00\x00\x13\xf6\x00\x00\x00\x00\x00\x01\x00\x11\x1e\x13\
-\x00\x00\x13\x94\x00\x00\x00\x00\x00\x01\x00\x11\x15\xe3\
-\x00\x00\x14\xca\x00\x00\x00\x00\x00\x01\x00\x11\x30\x1a\
-\x00\x00\x14\x70\x00\x00\x00\x00\x00\x01\x00\x11\x29\x5b\
-\x00\x00\x13\xc0\x00\x00\x00\x00\x00\x01\x00\x11\x1a\xef\
-\x00\x00\x14\xfc\x00\x00\x00\x00\x00\x01\x00\x11\x33\xd7\
-\x00\x00\x14\x18\x00\x00\x00\x00\x00\x01\x00\x11\x22\x82\
-\x00\x00\x13\x5c\x00\x00\x00\x00\x00\x01\x00\x11\x13\x6d\
-\x00\x00\x14\x46\x00\x00\x00\x00\x00\x01\x00\x11\x26\xd3\
-\x00\x00\x12\xf8\x00\x00\x00\x00\x00\x01\x00\x11\x08\x8d\
-\x00\x00\x0a\x10\x00\x00\x00\x00\x00\x01\x00\x0e\xec\xf7\
-\x00\x00\x0a\x30\x00\x00\x00\x00\x00\x01\x00\x0e\xf0\xd4\
-\x00\x00\x09\xea\x00\x00\x00\x00\x00\x01\x00\x0e\xea\x59\
-\x00\x00\x0d\x9e\x00\x00\x00\x00\x00\x01\x00\x0f\x5f\xb5\
-\x00\x00\x0e\x3c\x00\x00\x00\x00\x00\x01\x00\x0f\x6a\x2a\
-\x00\x00\x0e\x96\x00\x00\x00\x00\x00\x01\x00\x0f\x6e\xe3\
-\x00\x00\x0d\x34\x00\x00\x00\x00\x00\x01\x00\x0f\x5b\xc5\
-\x00\x00\x0e\x18\x00\x00\x00\x00\x00\x01\x00\x0f\x66\xf7\
-\x00\x00\x0d\x68\x00\x00\x00\x00\x00\x01\x00\x0f\x5d\xbc\
-\x00\x00\x0d\xd2\x00\x00\x00\x00\x00\x01\x00\x0f\x61\xb3\
-\x00\x00\x0d\xf4\x00\x00\x00\x00\x00\x01\x00\x0f\x63\xc6\
-\x00\x00\x0e\x72\x00\x00\x00\x00\x00\x01\x00\x0f\x6c\x12\
-\x00\x00\x0d\x0c\x00\x00\x00\x00\x00\x01\x00\x0f\x59\x09\
-\x00\x00\x02\xee\x00\x00\x00\x00\x00\x01\x00\x00\x1b\x20\
-\x00\x00\x02\x72\x00\x00\x00\x00\x00\x01\x00\x00\x11\xc5\
-\x00\x00\x02\x16\x00\x00\x00\x00\x00\x01\x00\x00\x0c\x03\
-\x00\x00\x02\xa0\x00\x00\x00\x00\x00\x01\x00\x00\x15\x7b\
-\x00\x00\x01\xee\x00\x00\x00\x00\x00\x01\x00\x00\x09\x05\
-\x00\x00\x02\x3c\x00\x00\x00\x00\x00\x01\x00\x00\x0f\x9a\
-\x00\x00\x02\xc8\x00\x00\x00\x00\x00\x01\x00\x00\x18\xbd\
-\x00\x00\x03\x3e\x00\x00\x00\x00\x00\x01\x00\x00\x1f\x8c\
-\x00\x00\x03\x16\x00\x00\x00\x00\x00\x01\x00\x00\x1d\x72\
-\x00\x00\x04\xea\x00\x00\x00\x00\x00\x01\x00\x0d\x51\x59\
-\x00\x00\x04\x7c\x00\x00\x00\x00\x00\x01\x00\x0d\x48\x13\
-\x00\x00\x04\xb8\x00\x00\x00\x00\x00\x01\x00\x0d\x50\x06\
-\x00\x00\x05\x52\x00\x00\x00\x00\x00\x01\x00\x0d\x56\x1f\
-\x00\x00\x05\x20\x00\x00\x00\x00\x00\x01\x00\x0d\x54\x57\
-\x00\x00\x15\x64\x00\x00\x00\x00\x00\x01\x00\x11\x3d\x0b\
-\x00\x00\x15\x98\x00\x00\x00\x00\x00\x01\x00\x11\x3f\xdb\
-\x00\x00\x15\x20\x00\x00\x00\x00\x00\x01\x00\x11\x37\x8a\
-\x00\x00\x15\x44\x00\x00\x00\x00\x00\x01\x00\x11\x3a\x88\
-\x00\x00\x06\xde\x00\x00\x00\x00\x00\x01\x00\x0e\xaa\x8e\
-\x00\x00\x07\xc4\x00\x00\x00\x00\x00\x01\x00\x0e\xbb\x82\
-\x00\x00\x09\xca\x00\x00\x00\x00\x00\x01\x00\x0e\xe6\x66\
-\x00\x00\x09\x98\x00\x00\x00\x00\x00\x01\x00\x0e\xdf\x50\
-\x00\x00\x08\x7e\x00\x00\x00\x00\x00\x01\x00\x0e\xc4\x50\
-\x00\x00\x09\x1e\x00\x00\x00\x00\x00\x01\x00\x0e\xd7\x0f\
-\x00\x00\x09\x48\x00\x00\x00\x00\x00\x01\x00\x0e\xd9\x44\
-\x00\x00\x08\x1e\x00\x00\x00\x00\x00\x01\x00\x0e\xc0\x33\
-\x00\x00\x08\x4c\x00\x00\x00\x00\x00\x01\x00\x0e\xc2\xb3\
-\x00\x00\x07\x52\x00\x00\x00\x00\x00\x01\x00\x0e\xb4\x35\
-\x00\x00\x07\xa4\x00\x00\x00\x00\x00\x01\x00\x0e\xb8\x76\
-\x00\x00\x07\xec\x00\x00\x00\x00\x00\x01\x00\x0e\xbe\xe0\
-\x00\x00\x08\xd0\x00\x00\x00\x00\x00\x01\x00\x0e\xca\xc5\
-\x00\x00\x08\xa4\x00\x00\x00\x00\x00\x01\x00\x0e\xc8\x62\
-\x00\x00\x09\x6a\x00\x00\x00\x00\x00\x01\x00\x0e\xdd\x48\
-\x00\x00\x06\xb0\x00\x00\x00\x00\x00\x01\x00\x0e\xa3\xd0\
-\x00\x00\x07\x02\x00\x00\x00\x00\x00\x01\x00\x0e\xad\x7a\
-\x00\x00\x07\x2e\x00\x00\x00\x00\x00\x01\x00\x0e\xb0\xbc\
-\x00\x00\x07\x82\x00\x00\x00\x00\x00\x01\x00\x0e\xb5\x2e\
-\x00\x00\x08\xee\x00\x00\x00\x00\x00\x01\x00\x0e\xcd\x67\
-\x00\x00\x0a\xc4\x00\x00\x00\x00\x00\x01\x00\x0f\x2a\x0c\
-\x00\x00\x0a\xf8\x00\x00\x00\x00\x00\x01\x00\x0f\x2d\x0f\
-\x00\x00\x0b\x6e\x00\x00\x00\x00\x00\x01\x00\x0f\x3b\x47\
-\x00\x00\x0a\x94\x00\x00\x00\x00\x00\x01\x00\x0f\x27\xb3\
-\x00\x00\x0b\x3e\x00\x00\x00\x00\x00\x01\x00\x0f\x38\x14\
-\x00\x00\x0b\x90\x00\x00\x00\x00\x00\x01\x00\x0f\x3e\x1d\
-\x00\x00\x0a\x52\x00\x00\x00\x00\x00\x01\x00\x0e\xf4\x0e\
-\x00\x00\x0b\x1a\x00\x00\x00\x00\x00\x01\x00\x0f\x30\xe2\
-\x00\x00\x15\xc8\x00\x00\x00\x00\x00\x01\x00\x11\x42\xd4\
-\x00\x00\x16\x2a\x00\x00\x00\x00\x00\x01\x00\x11\x49\x4a\
-\x00\x00\x15\xfc\x00\x00\x00\x00\x00\x01\x00\x11\x46\x36\
-\x00\x00\x16\x52\x00\x00\x00\x00\x00\x01\x00\x11\x4b\xe8\
-\x00\x00\x06\x18\x00\x00\x00\x00\x00\x01\x00\x0d\x91\xaf\
-\x00\x00\x05\xb8\x00\x00\x00\x00\x00\x01\x00\x0d\x62\x6f\
-\x00\x00\x05\x88\x00\x00\x00\x00\x00\x01\x00\x0d\x57\xdb\
-\x00\x00\x05\xe8\x00\x00\x00\x00\x00\x01\x00\x0d\x77\xa4\
-\x00\x00\x06\x48\x00\x00\x00\x00\x00\x01\x00\x0d\x95\xcc\
-\x00\x00\x06\x7c\x00\x00\x00\x00\x00\x01\x00\x0e\x5e\x65\
+\x00\x00\x00\x00\x00\x02\x00\x00\x00\x13\x00\x00\x00\x01\
+\x00\x00\x00\xe6\x00\x02\x00\x00\x00\x06\x00\x00\x00\x8b\
+\x00\x00\x00\x00\x00\x02\x00\x00\x00\x04\x00\x00\x00\x87\
+\x00\x00\x00\xb4\x00\x02\x00\x00\x00\x08\x00\x00\x00\x7f\
+\x00\x00\x00\xd6\x00\x02\x00\x00\x00\x14\x00\x00\x00\x6b\
+\x00\x00\x00\x2c\x00\x02\x00\x00\x00\x02\x00\x00\x00\x69\
+\x00\x00\x00\x14\x00\x02\x00\x00\x00\x02\x00\x00\x00\x67\
+\x00\x00\x01\x06\x00\x02\x00\x00\x00\x05\x00\x00\x00\x62\
+\x00\x00\x00\xf4\x00\x02\x00\x00\x00\x02\x00\x00\x00\x60\
+\x00\x00\x01\x40\x00\x02\x00\x00\x00\x09\x00\x00\x00\x57\
+\x00\x00\x00\x8c\x00\x02\x00\x00\x00\x0a\x00\x00\x00\x4d\
+\x00\x00\x00\xc4\x00\x02\x00\x00\x00\x03\x00\x00\x00\x4a\
+\x00\x00\x00\x3c\x00\x02\x00\x00\x00\x10\x00\x00\x00\x3a\
+\x00\x00\x00\x62\x00\x02\x00\x00\x00\x03\x00\x00\x00\x37\
+\x00\x00\x00\x78\x00\x02\x00\x00\x00\x01\x00\x00\x00\x36\
+\x00\x00\x01\x54\x00\x02\x00\x00\x00\x03\x00\x00\x00\x33\
+\x00\x00\x00\x9e\x00\x02\x00\x00\x00\x08\x00\x00\x00\x2b\
+\x00\x00\x01\x2c\x00\x02\x00\x00\x00\x01\x00\x00\x00\x2a\
+\x00\x00\x00\x4e\x00\x02\x00\x00\x00\x11\x00\x00\x00\x19\
+\x00\x00\x01\x18\x00\x02\x00\x00\x00\x05\x00\x00\x00\x14\
+\x00\x00\x04\x5e\x00\x00\x00\x00\x00\x01\x00\x0a\xa7\x31\
+\x00\x00\x03\x9c\x00\x00\x00\x00\x00\x01\x00\x00\x23\xa9\
+\x00\x00\x03\xfe\x00\x00\x00\x00\x00\x01\x00\x05\x65\x6d\
+\x00\x00\x04\x2c\x00\x00\x00\x00\x00\x01\x00\x08\x06\x4f\
+\x00\x00\x03\xce\x00\x00\x00\x00\x00\x01\x00\x02\xc4\x8b\
+\x00\x00\x10\x7a\x00\x00\x00\x00\x00\x01\x00\x10\xe0\x3f\
+\x00\x00\x10\xea\x00\x00\x00\x00\x00\x01\x00\x10\xe7\x8a\
+\x00\x00\x10\x2a\x00\x00\x00\x00\x00\x01\x00\x10\xda\xe3\
+\x00\x00\x11\xc8\x00\x00\x00\x00\x00\x01\x00\x10\xfa\x08\
+\x00\x00\x11\x4a\x00\x00\x00\x00\x00\x01\x00\x10\xef\xa0\
+\x00\x00\x0f\xd2\x00\x00\x00\x00\x00\x01\x00\x10\xd3\xac\
+\x00\x00\x12\x1a\x00\x00\x00\x00\x00\x01\x00\x11\x00\x0f\
+\x00\x00\x11\x12\x00\x00\x00\x00\x00\x01\x00\x10\xea\xfe\
+\x00\x00\x12\x68\x00\x00\x00\x00\x00\x01\x00\x11\x05\x3b\
+\x00\x00\x0f\xfc\x00\x00\x00\x00\x00\x01\x00\x10\xd6\x4a\
+\x00\x00\x11\xf4\x00\x00\x00\x00\x00\x01\x00\x10\xfd\x3b\
+\x00\x00\x11\x9e\x00\x00\x00\x00\x00\x01\x00\x10\xf7\x90\
+\x00\x00\x10\x50\x00\x00\x00\x00\x00\x01\x00\x10\xdd\xbd\
+\x00\x00\x12\x44\x00\x00\x00\x00\x00\x01\x00\x11\x02\xf4\
+\x00\x00\x11\x72\x00\x00\x00\x00\x00\x01\x00\x10\xf2\xe5\
+\x00\x00\x10\xc6\x00\x00\x00\x00\x00\x01\x00\x10\xe4\x8d\
+\x00\x00\x10\xa0\x00\x00\x00\x00\x00\x01\x00\x10\xe2\x76\
+\x00\x00\x03\x78\x00\x00\x00\x00\x00\x01\x00\x00\x21\x92\
+\x00\x00\x0c\x92\x00\x00\x00\x00\x00\x01\x00\x0f\x55\x24\
+\x00\x00\x0d\x12\x00\x00\x00\x00\x00\x01\x00\x0f\x5b\xea\
+\x00\x00\x0c\x16\x00\x00\x00\x00\x00\x01\x00\x0f\x4e\x20\
+\x00\x00\x0c\xba\x00\x00\x00\x00\x00\x01\x00\x0f\x57\xc4\
+\x00\x00\x0d\x3c\x00\x00\x00\x00\x00\x01\x00\x0f\x5e\xb5\
+\x00\x00\x0c\x60\x00\x00\x00\x00\x00\x01\x00\x0f\x53\x3a\
+\x00\x00\x0c\x3a\x00\x00\x00\x00\x00\x01\x00\x0f\x50\xc7\
+\x00\x00\x0c\xf0\x00\x00\x00\x00\x00\x01\x00\x0f\x59\x46\
+\x00\x00\x01\x6e\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\
+\x00\x00\x01\xd4\x00\x00\x00\x00\x00\x01\x00\x00\x05\xe6\
+\x00\x00\x01\xa0\x00\x00\x00\x00\x00\x01\x00\x00\x02\xfe\
+\x00\x00\x0f\x22\x00\x00\x00\x00\x00\x01\x00\x0f\x7a\x03\
+\x00\x00\x0f\x4c\x00\x00\x00\x00\x00\x01\x00\x0f\x7f\x6d\
+\x00\x00\x0f\x7c\x00\x00\x00\x00\x00\x01\x00\x0f\xed\xf6\
+\x00\x00\x0f\x9c\x00\x00\x00\x00\x00\x01\x00\x0f\xf4\xa7\
+\x00\x00\x12\xea\x00\x00\x00\x00\x00\x01\x00\x11\x0c\x4f\
+\x00\x00\x12\x90\x00\x00\x00\x00\x00\x01\x00\x11\x07\x4e\
+\x00\x00\x15\x06\x00\x00\x00\x00\x00\x01\x00\x11\x36\x54\
+\x00\x00\x13\x90\x00\x00\x00\x00\x00\x01\x00\x11\x14\x59\
+\x00\x00\x13\x2c\x00\x00\x00\x00\x00\x01\x00\x11\x0f\xa2\
+\x00\x00\x12\xb6\x00\x00\x00\x00\x00\x01\x00\x11\x0a\x7f\
+\x00\x00\x14\x58\x00\x00\x00\x00\x00\x01\x00\x11\x27\x2f\
+\x00\x00\x13\xf6\x00\x00\x00\x00\x00\x01\x00\x11\x1e\xff\
+\x00\x00\x15\x2c\x00\x00\x00\x00\x00\x01\x00\x11\x39\x36\
+\x00\x00\x14\xd2\x00\x00\x00\x00\x00\x01\x00\x11\x32\x77\
+\x00\x00\x14\x22\x00\x00\x00\x00\x00\x01\x00\x11\x24\x0b\
+\x00\x00\x15\x5e\x00\x00\x00\x00\x00\x01\x00\x11\x3c\xf3\
+\x00\x00\x14\x7a\x00\x00\x00\x00\x00\x01\x00\x11\x2b\x9e\
+\x00\x00\x13\xbe\x00\x00\x00\x00\x00\x01\x00\x11\x1c\x89\
+\x00\x00\x14\xa8\x00\x00\x00\x00\x00\x01\x00\x11\x2f\xef\
+\x00\x00\x13\x5a\x00\x00\x00\x00\x00\x01\x00\x11\x11\xa9\
+\x00\x00\x0a\x72\x00\x00\x00\x00\x00\x01\x00\x0e\xf6\x13\
+\x00\x00\x0a\x92\x00\x00\x00\x00\x00\x01\x00\x0e\xf9\xf0\
+\x00\x00\x0a\x4c\x00\x00\x00\x00\x00\x01\x00\x0e\xf3\x75\
+\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x01\x00\x0f\x68\xd1\
+\x00\x00\x0e\x9e\x00\x00\x00\x00\x00\x01\x00\x0f\x73\x46\
+\x00\x00\x0e\xf8\x00\x00\x00\x00\x00\x01\x00\x0f\x77\xff\
+\x00\x00\x0d\x96\x00\x00\x00\x00\x00\x01\x00\x0f\x64\xe1\
+\x00\x00\x0e\x7a\x00\x00\x00\x00\x00\x01\x00\x0f\x70\x13\
+\x00\x00\x0d\xca\x00\x00\x00\x00\x00\x01\x00\x0f\x66\xd8\
+\x00\x00\x0e\x34\x00\x00\x00\x00\x00\x01\x00\x0f\x6a\xcf\
+\x00\x00\x0e\x56\x00\x00\x00\x00\x00\x01\x00\x0f\x6c\xe2\
+\x00\x00\x0e\xd4\x00\x00\x00\x00\x00\x01\x00\x0f\x75\x2e\
+\x00\x00\x0d\x6e\x00\x00\x00\x00\x00\x01\x00\x0f\x62\x25\
+\x00\x00\x03\x00\x00\x00\x00\x00\x00\x01\x00\x00\x1b\x20\
+\x00\x00\x02\x84\x00\x00\x00\x00\x00\x01\x00\x00\x11\xc5\
+\x00\x00\x02\x28\x00\x00\x00\x00\x00\x01\x00\x00\x0c\x03\
+\x00\x00\x02\xb2\x00\x00\x00\x00\x00\x01\x00\x00\x15\x7b\
+\x00\x00\x02\x00\x00\x00\x00\x00\x00\x01\x00\x00\x09\x05\
+\x00\x00\x02\x4e\x00\x00\x00\x00\x00\x01\x00\x00\x0f\x9a\
+\x00\x00\x02\xda\x00\x00\x00\x00\x00\x01\x00\x00\x18\xbd\
+\x00\x00\x03\x50\x00\x00\x00\x00\x00\x01\x00\x00\x1f\x8c\
+\x00\x00\x03\x28\x00\x00\x00\x00\x00\x01\x00\x00\x1d\x72\
+\x00\x00\x05\x9a\x00\x00\x00\x00\x00\x01\x00\x0d\x57\xdb\
+\x00\x00\x05\xbe\x00\x00\x00\x00\x00\x01\x00\x0d\x5d\xf9\
+\x00\x00\x04\xfc\x00\x00\x00\x00\x00\x01\x00\x0d\x51\x59\
+\x00\x00\x04\x8e\x00\x00\x00\x00\x00\x01\x00\x0d\x48\x13\
+\x00\x00\x04\xca\x00\x00\x00\x00\x00\x01\x00\x0d\x50\x06\
+\x00\x00\x05\x64\x00\x00\x00\x00\x00\x01\x00\x0d\x56\x1f\
+\x00\x00\x05\x32\x00\x00\x00\x00\x00\x01\x00\x0d\x54\x57\
+\x00\x00\x15\xc6\x00\x00\x00\x00\x00\x01\x00\x11\x46\x27\
+\x00\x00\x15\xfa\x00\x00\x00\x00\x00\x01\x00\x11\x48\xf7\
+\x00\x00\x15\x82\x00\x00\x00\x00\x00\x01\x00\x11\x40\xa6\
+\x00\x00\x15\xa6\x00\x00\x00\x00\x00\x01\x00\x11\x43\xa4\
+\x00\x00\x07\x40\x00\x00\x00\x00\x00\x01\x00\x0e\xb3\xaa\
+\x00\x00\x08\x26\x00\x00\x00\x00\x00\x01\x00\x0e\xc4\x9e\
+\x00\x00\x0a\x2c\x00\x00\x00\x00\x00\x01\x00\x0e\xef\x82\
+\x00\x00\x09\xfa\x00\x00\x00\x00\x00\x01\x00\x0e\xe8\x6c\
+\x00\x00\x08\xe0\x00\x00\x00\x00\x00\x01\x00\x0e\xcd\x6c\
+\x00\x00\x09\x80\x00\x00\x00\x00\x00\x01\x00\x0e\xe0\x2b\
+\x00\x00\x09\xaa\x00\x00\x00\x00\x00\x01\x00\x0e\xe2\x60\
+\x00\x00\x08\x80\x00\x00\x00\x00\x00\x01\x00\x0e\xc9\x4f\
+\x00\x00\x08\xae\x00\x00\x00\x00\x00\x01\x00\x0e\xcb\xcf\
+\x00\x00\x07\xb4\x00\x00\x00\x00\x00\x01\x00\x0e\xbd\x51\
+\x00\x00\x08\x06\x00\x00\x00\x00\x00\x01\x00\x0e\xc1\x92\
+\x00\x00\x08\x4e\x00\x00\x00\x00\x00\x01\x00\x0e\xc7\xfc\
+\x00\x00\x09\x32\x00\x00\x00\x00\x00\x01\x00\x0e\xd3\xe1\
+\x00\x00\x09\x06\x00\x00\x00\x00\x00\x01\x00\x0e\xd1\x7e\
+\x00\x00\x09\xcc\x00\x00\x00\x00\x00\x01\x00\x0e\xe6\x64\
+\x00\x00\x07\x12\x00\x00\x00\x00\x00\x01\x00\x0e\xac\xec\
+\x00\x00\x07\x64\x00\x00\x00\x00\x00\x01\x00\x0e\xb6\x96\
+\x00\x00\x07\x90\x00\x00\x00\x00\x00\x01\x00\x0e\xb9\xd8\
+\x00\x00\x07\xe4\x00\x00\x00\x00\x00\x01\x00\x0e\xbe\x4a\
+\x00\x00\x09\x50\x00\x00\x00\x00\x00\x01\x00\x0e\xd6\x83\
+\x00\x00\x0b\x26\x00\x00\x00\x00\x00\x01\x00\x0f\x33\x28\
+\x00\x00\x0b\x5a\x00\x00\x00\x00\x00\x01\x00\x0f\x36\x2b\
+\x00\x00\x0b\xd0\x00\x00\x00\x00\x00\x01\x00\x0f\x44\x63\
+\x00\x00\x0a\xf6\x00\x00\x00\x00\x00\x01\x00\x0f\x30\xcf\
+\x00\x00\x0b\xa0\x00\x00\x00\x00\x00\x01\x00\x0f\x41\x30\
+\x00\x00\x0b\xf2\x00\x00\x00\x00\x00\x01\x00\x0f\x47\x39\
+\x00\x00\x0a\xb4\x00\x00\x00\x00\x00\x01\x00\x0e\xfd\x2a\
+\x00\x00\x0b\x7c\x00\x00\x00\x00\x00\x01\x00\x0f\x39\xfe\
+\x00\x00\x16\x2a\x00\x00\x00\x00\x00\x01\x00\x11\x4b\xf0\
+\x00\x00\x16\x8c\x00\x00\x00\x00\x00\x01\x00\x11\x52\x66\
+\x00\x00\x16\x5e\x00\x00\x00\x00\x00\x01\x00\x11\x4f\x52\
+\x00\x00\x16\xb4\x00\x00\x00\x00\x00\x01\x00\x11\x55\x04\
+\x00\x00\x06\x7a\x00\x00\x00\x00\x00\x01\x00\x0d\x9a\xcb\
+\x00\x00\x06\x1a\x00\x00\x00\x00\x00\x01\x00\x0d\x6b\x8b\
+\x00\x00\x05\xea\x00\x00\x00\x00\x00\x01\x00\x0d\x60\xf7\
+\x00\x00\x06\x4a\x00\x00\x00\x00\x00\x01\x00\x0d\x80\xc0\
+\x00\x00\x06\xaa\x00\x00\x00\x00\x00\x01\x00\x0d\x9e\xe8\
+\x00\x00\x06\xde\x00\x00\x00\x00\x00\x01\x00\x0e\x67\x81\
"
def qInitResources():
=== modified file 'openlp/core/ui/mainwindow.py'
--- openlp/core/ui/mainwindow.py 2013-02-26 17:27:30 +0000
+++ openlp/core/ui/mainwindow.py 2013-03-04 14:42:22 +0000
@@ -807,19 +807,11 @@
return
setting_sections = []
# Add main sections.
- setting_sections.extend([self.generalSettingsSection])
- setting_sections.extend([self.advancedSettingsSection])
- setting_sections.extend([self.uiSettingsSection])
- setting_sections.extend([self.shortcutsSettingsSection])
- setting_sections.extend([self.serviceManagerSettingsSection])
- setting_sections.extend([self.themesSettingsSection])
- setting_sections.extend([self.playersSettingsSection])
- setting_sections.extend([self.displayTagsSection])
- setting_sections.extend([self.headerSection])
- setting_sections.extend([u'crashreport'])
+ setting_sections.extend([self.generalSettingsSection, self.advancedSettingsSection, self.uiSettingsSection,
+ self.shortcutsSettingsSection, self.serviceManagerSettingsSection, self.themesSettingsSection,
+ self.playersSettingsSection, self.displayTagsSection, self.headerSection, u'crashreport'])
# Add plugin sections.
- for plugin in self.plugin_manager.plugins:
- setting_sections.extend([plugin.name])
+ setting_sections.extend([plugin.name for plugin in self.plugin_manager.plugins])
# Copy the settings file to the tmp dir, because we do not want to change the original one.
temp_directory = os.path.join(unicode(gettempdir()), u'openlp')
check_directory_exists(temp_directory)
@@ -827,11 +819,13 @@
shutil.copyfile(import_file_name, temp_config)
settings = Settings()
import_settings = Settings(temp_config, Settings.IniFormat)
+ # Convert image files
+ log.info(u'hook upgrade_plugin_settings')
+ self.plugin_manager.hook_upgrade_plugin_settings(import_settings)
# Remove/rename old settings to prepare the import.
import_settings.remove_obsolete_settings()
- # Lets do a basic sanity check. If it contains this string we can
- # assume it was created by OpenLP and so we'll load what we can
- # from it, and just silently ignore anything we don't recognise
+ # Lets do a basic sanity check. If it contains this string we can assume it was created by OpenLP and so we'll
+ # load what we can from it, and just silently ignore anything we don't recognise.
if import_settings.value(u'SettingsImport/type') != u'OpenLP_settings_export':
QtGui.QMessageBox.critical(self, translate('OpenLP.MainWindow', 'Import settings'),
translate('OpenLP.MainWindow', 'The file you have selected does not appear to be a valid OpenLP '
@@ -866,9 +860,8 @@
settings.setValue(u'file_date_imported', now.strftime("%Y-%m-%d %H:%M"))
settings.endGroup()
settings.sync()
- # We must do an immediate restart or current configuration will
- # overwrite what was just imported when application terminates
- # normally. We need to exit without saving configuration.
+ # We must do an immediate restart or current configuration will overwrite what was just imported when
+ # application terminates normally. We need to exit without saving configuration.
QtGui.QMessageBox.information(self, translate('OpenLP.MainWindow', 'Import settings'),
translate('OpenLP.MainWindow', 'OpenLP will now close. Imported settings will '
'be applied the next time you start OpenLP.'),
=== modified file 'openlp/plugins/custom/lib/mediaitem.py'
--- openlp/plugins/custom/lib/mediaitem.py 2013-02-07 08:42:17 +0000
+++ openlp/plugins/custom/lib/mediaitem.py 2013-03-04 14:42:22 +0000
@@ -96,7 +96,7 @@
self.searchTextEdit.setCurrentSearchType(Settings().value( u'%s/last search type' % self.settingsSection))
self.config_updated()
- def loadList(self, custom_slides):
+ def loadList(self, custom_slides, target_group=None):
# Sort out what custom we want to select after loading the list.
self.saveAutoSelectId()
self.listView.clear()
=== added directory 'openlp/plugins/images/forms'
=== added file 'openlp/plugins/images/forms/__init__.py'
--- openlp/plugins/images/forms/__init__.py 1970-01-01 00:00:00 +0000
+++ openlp/plugins/images/forms/__init__.py 2013-03-04 14:42:22 +0000
@@ -0,0 +1,57 @@
+# -*- coding: utf-8 -*-
+# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
+
+###############################################################################
+# OpenLP - Open Source Lyrics Projection #
+# --------------------------------------------------------------------------- #
+# Copyright (c) 2008-2013 Raoul Snyman #
+# Portions copyright (c) 2008-2013 Tim Bentley, Gerald Britton, Jonathan #
+# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, #
+# Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer. #
+# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru, #
+# Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, #
+# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Dave Warnock, #
+# Frode Woldsund, Martin Zibricky, Patrick Zimmermann #
+# --------------------------------------------------------------------------- #
+# This program is free software; you can redistribute it and/or modify it #
+# under the terms of the GNU General Public License as published by the Free #
+# Software Foundation; version 2 of the License. #
+# #
+# This program is distributed in the hope that it will be useful, but WITHOUT #
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
+# more details. #
+# #
+# You should have received a copy of the GNU General Public License along #
+# with this program; if not, write to the Free Software Foundation, Inc., 59 #
+# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
+###############################################################################
+"""
+Forms in OpenLP are made up of two classes. One class holds all the graphical
+elements, like buttons and lists, and the other class holds all the functional
+code, like slots and loading and saving.
+
+The first class, commonly known as the **Dialog** class, is typically named
+``Ui_<name>Dialog``. It is a slightly modified version of the class that the
+``pyuic4`` command produces from Qt4's .ui file. Typical modifications will be
+converting most strings from "" to u'' and using OpenLP's ``translate()``
+function for translating strings.
+
+The second class, commonly known as the **Form** class, is typically named
+``<name>Form``. This class is the one which is instantiated and used. It uses
+dual inheritance to inherit from (usually) QtGui.QDialog and the Ui class
+mentioned above, like so::
+
+ class AuthorsForm(QtGui.QDialog, Ui_AuthorsDialog):
+
+ def __init__(self, parent=None):
+ QtGui.QDialog.__init__(self, parent)
+ self.setupUi(self)
+
+This allows OpenLP to use ``self.object`` for all the GUI elements while keeping
+them separate from the functionality, so that it is easier to recreate the GUI
+from the .ui files later if necessary.
+"""
+
+from addgroupform import AddGroupForm
+from choosegroupform import ChooseGroupForm
=== added file 'openlp/plugins/images/forms/addgroupdialog.py'
--- openlp/plugins/images/forms/addgroupdialog.py 1970-01-01 00:00:00 +0000
+++ openlp/plugins/images/forms/addgroupdialog.py 2013-03-04 14:42:22 +0000
@@ -0,0 +1,64 @@
+# -*- coding: utf-8 -*-
+# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
+
+###############################################################################
+# OpenLP - Open Source Lyrics Projection #
+# --------------------------------------------------------------------------- #
+# Copyright (c) 2008-2013 Raoul Snyman #
+# Portions copyright (c) 2008-2013 Tim Bentley, Gerald Britton, Jonathan #
+# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, #
+# Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer. #
+# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru, #
+# Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, #
+# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Dave Warnock, #
+# Frode Woldsund, Martin Zibricky, Patrick Zimmermann #
+# --------------------------------------------------------------------------- #
+# This program is free software; you can redistribute it and/or modify it #
+# under the terms of the GNU General Public License as published by the Free #
+# Software Foundation; version 2 of the License. #
+# #
+# This program is distributed in the hope that it will be useful, but WITHOUT #
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
+# more details. #
+# #
+# You should have received a copy of the GNU General Public License along #
+# with this program; if not, write to the Free Software Foundation, Inc., 59 #
+# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
+###############################################################################
+
+from PyQt4 import QtGui
+
+from openlp.core.lib import translate
+from openlp.core.lib.ui import create_button_box
+
+
+class Ui_AddGroupDialog(object):
+ def setupUi(self, add_group_dialog):
+ add_group_dialog.setObjectName(u'add_group_dialog')
+ add_group_dialog.resize(300, 10)
+ self.dialog_layout = QtGui.QVBoxLayout(add_group_dialog)
+ self.dialog_layout.setObjectName(u'dialog_layout')
+ self.name_layout = QtGui.QFormLayout()
+ self.name_layout.setObjectName(u'name_layout')
+ self.parent_group_label = QtGui.QLabel(add_group_dialog)
+ self.parent_group_label.setObjectName(u'parent_group_label')
+ self.parent_group_combobox = QtGui.QComboBox(add_group_dialog)
+ self.parent_group_combobox.setObjectName(u'parent_group_combobox')
+ self.name_layout.addRow(self.parent_group_label, self.parent_group_combobox)
+ self.name_label = QtGui.QLabel(add_group_dialog)
+ self.name_label.setObjectName(u'name_label')
+ self.name_edit = QtGui.QLineEdit(add_group_dialog)
+ self.name_edit.setObjectName(u'name_edit')
+ self.name_label.setBuddy(self.name_edit)
+ self.name_layout.addRow(self.name_label, self.name_edit)
+ self.dialog_layout.addLayout(self.name_layout)
+ self.button_box = create_button_box(add_group_dialog, u'button_box', [u'cancel', u'save'])
+ self.dialog_layout.addWidget(self.button_box)
+ self.retranslateUi(add_group_dialog)
+ add_group_dialog.setMaximumHeight(add_group_dialog.sizeHint().height())
+
+ def retranslateUi(self, add_group_dialog):
+ add_group_dialog.setWindowTitle(translate('ImagePlugin.AddGroupForm', 'Add group'))
+ self.parent_group_label.setText(translate('ImagePlugin.AddGroupForm', 'Parent group:'))
+ self.name_label.setText(translate('ImagePlugin.AddGroupForm', 'Group name:'))
=== added file 'openlp/plugins/images/forms/addgroupform.py'
--- openlp/plugins/images/forms/addgroupform.py 1970-01-01 00:00:00 +0000
+++ openlp/plugins/images/forms/addgroupform.py 2013-03-04 14:42:22 +0000
@@ -0,0 +1,68 @@
+# -*- coding: utf-8 -*-
+# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
+
+###############################################################################
+# OpenLP - Open Source Lyrics Projection #
+# --------------------------------------------------------------------------- #
+# Copyright (c) 2008-2013 Raoul Snyman #
+# Portions copyright (c) 2008-2013 Tim Bentley, Gerald Britton, Jonathan #
+# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, #
+# Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer. #
+# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru, #
+# Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, #
+# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Dave Warnock, #
+# Frode Woldsund, Martin Zibricky, Patrick Zimmermann #
+# --------------------------------------------------------------------------- #
+# This program is free software; you can redistribute it and/or modify it #
+# under the terms of the GNU General Public License as published by the Free #
+# Software Foundation; version 2 of the License. #
+# #
+# This program is distributed in the hope that it will be useful, but WITHOUT #
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
+# more details. #
+# #
+# You should have received a copy of the GNU General Public License along #
+# with this program; if not, write to the Free Software Foundation, Inc., 59 #
+# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
+###############################################################################
+
+from PyQt4 import QtGui
+
+from openlp.core.lib import translate
+from openlp.core.lib.ui import critical_error_message_box
+from openlp.plugins.images.forms.addgroupdialog import Ui_AddGroupDialog
+
+
+class AddGroupForm(QtGui.QDialog, Ui_AddGroupDialog):
+ """
+ Class documentation goes here.
+ """
+ def __init__(self, parent=None):
+ """
+ Constructor
+ """
+ QtGui.QDialog.__init__(self, parent)
+ self.setupUi(self)
+
+ def exec_(self, clear=True, show_top_level_group=False, selected_group=None):
+ if clear:
+ self.name_edit.clear()
+ self.name_edit.setFocus()
+ if show_top_level_group and not self.parent_group_combobox.top_level_group_added:
+ self.parent_group_combobox.insertItem(0, translate('ImagePlugin.MediaItem', '-- Top-level group --'), 0)
+ self.parent_group_combobox.top_level_group_added = True
+ if selected_group is not None:
+ for i in range(self.parent_group_combobox.count()):
+ if self.parent_group_combobox.itemData(i) == selected_group:
+ self.parent_group_combobox.setCurrentIndex(i)
+ return QtGui.QDialog.exec_(self)
+
+ def accept(self):
+ if not self.name_edit.text():
+ critical_error_message_box(message=translate('ImagePlugin.AddGroupForm',
+ 'You need to type in a group name.'))
+ self.name_edit.setFocus()
+ return False
+ else:
+ return QtGui.QDialog.accept(self)
=== added file 'openlp/plugins/images/forms/choosegroupdialog.py'
--- openlp/plugins/images/forms/choosegroupdialog.py 1970-01-01 00:00:00 +0000
+++ openlp/plugins/images/forms/choosegroupdialog.py 2013-03-04 14:42:22 +0000
@@ -0,0 +1,94 @@
+# -*- coding: utf-8 -*-
+# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
+
+###############################################################################
+# OpenLP - Open Source Lyrics Projection #
+# --------------------------------------------------------------------------- #
+# Copyright (c) 2008-2013 Raoul Snyman #
+# Portions copyright (c) 2008-2013 Tim Bentley, Gerald Britton, Jonathan #
+# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, #
+# Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer. #
+# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru, #
+# Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, #
+# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Dave Warnock, #
+# Frode Woldsund, Martin Zibricky, Patrick Zimmermann #
+# --------------------------------------------------------------------------- #
+# This program is free software; you can redistribute it and/or modify it #
+# under the terms of the GNU General Public License as published by the Free #
+# Software Foundation; version 2 of the License. #
+# #
+# This program is distributed in the hope that it will be useful, but WITHOUT #
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
+# more details. #
+# #
+# You should have received a copy of the GNU General Public License along #
+# with this program; if not, write to the Free Software Foundation, Inc., 59 #
+# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
+###############################################################################
+
+from PyQt4 import QtCore, QtGui
+
+from openlp.core.lib import translate
+from openlp.core.lib.ui import create_button_box
+
+
+class Ui_ChooseGroupDialog(object):
+ """
+ The UI for the "Choose Image Group" form.
+ """
+ def setupUi(self, choose_group_dialog):
+ """
+ Set up the UI.
+
+ ``choose_group_dialog``
+ The form object (not the class).
+ """
+ choose_group_dialog.setObjectName(u'choose_group_dialog')
+ choose_group_dialog.resize(399, 119)
+ self.choose_group_layout = QtGui.QFormLayout(choose_group_dialog)
+ self.choose_group_layout.setFieldGrowthPolicy(QtGui.QFormLayout.ExpandingFieldsGrow)
+ self.choose_group_layout.setMargin(8)
+ self.choose_group_layout.setSpacing(8)
+ self.choose_group_layout.setLabelAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter)
+ self.choose_group_layout.setObjectName(u'choose_group_layout')
+ self.group_question_label = QtGui.QLabel(choose_group_dialog)
+ self.group_question_label.setWordWrap(True)
+ self.group_question_label.setObjectName(u'group_question_label')
+ self.choose_group_layout.setWidget(1, QtGui.QFormLayout.SpanningRole, self.group_question_label)
+ self.nogroup_radio_button = QtGui.QRadioButton(choose_group_dialog)
+ self.nogroup_radio_button.setChecked(True)
+ self.nogroup_radio_button.setObjectName(u'nogroup_radio_button')
+ self.choose_group_layout.setWidget(2, QtGui.QFormLayout.LabelRole, self.nogroup_radio_button)
+ self.existing_radio_button = QtGui.QRadioButton(choose_group_dialog)
+ self.existing_radio_button.setChecked(False)
+ self.existing_radio_button.setObjectName(u'existing_radio_button')
+ self.choose_group_layout.setWidget(3, QtGui.QFormLayout.LabelRole, self.existing_radio_button)
+ self.group_combobox = QtGui.QComboBox(choose_group_dialog)
+ self.group_combobox.setObjectName(u'group_combobox')
+ self.choose_group_layout.setWidget(3, QtGui.QFormLayout.FieldRole, self.group_combobox)
+ self.new_radio_button = QtGui.QRadioButton(choose_group_dialog)
+ self.new_radio_button.setChecked(False)
+ self.new_radio_button.setObjectName(u'new_radio_button')
+ self.choose_group_layout.setWidget(4, QtGui.QFormLayout.LabelRole, self.new_radio_button)
+ self.new_group_edit = QtGui.QLineEdit(choose_group_dialog)
+ self.new_group_edit.setObjectName(u'new_group_edit')
+ self.choose_group_layout.setWidget(4, QtGui.QFormLayout.FieldRole, self.new_group_edit)
+ self.group_button_box = create_button_box(choose_group_dialog, u'buttonBox', [u'ok'])
+ self.choose_group_layout.setWidget(5, QtGui.QFormLayout.FieldRole, self.group_button_box)
+
+ self.retranslateUi(choose_group_dialog)
+ QtCore.QMetaObject.connectSlotsByName(choose_group_dialog)
+
+ def retranslateUi(self, choose_group_dialog):
+ """
+ Translate the UI on the fly.
+
+ ``choose_group_dialog``
+ The form object (not the class).
+ """
+ choose_group_dialog.setWindowTitle(translate('ImagePlugin.ChooseGroupForm', 'Select Image Group'))
+ self.group_question_label.setText(translate('ImagePlugin.ChooseGroupForm', 'Add images to group:'))
+ self.nogroup_radio_button.setText(translate('ImagePlugin.ChooseGroupForm', 'No group'))
+ self.existing_radio_button.setText(translate('ImagePlugin.ChooseGroupForm', 'Existing group'))
+ self.new_radio_button.setText(translate('ImagePlugin.ChooseGroupForm', 'New group'))
=== added file 'openlp/plugins/images/forms/choosegroupform.py'
--- openlp/plugins/images/forms/choosegroupform.py 1970-01-01 00:00:00 +0000
+++ openlp/plugins/images/forms/choosegroupform.py 2013-03-04 14:42:22 +0000
@@ -0,0 +1,51 @@
+# -*- coding: utf-8 -*-
+# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
+
+###############################################################################
+# OpenLP - Open Source Lyrics Projection #
+# --------------------------------------------------------------------------- #
+# Copyright (c) 2008-2013 Raoul Snyman #
+# Portions copyright (c) 2008-2013 Tim Bentley, Gerald Britton, Jonathan #
+# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, #
+# Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer. #
+# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru, #
+# Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, #
+# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Dave Warnock, #
+# Frode Woldsund, Martin Zibricky, Patrick Zimmermann #
+# --------------------------------------------------------------------------- #
+# This program is free software; you can redistribute it and/or modify it #
+# under the terms of the GNU General Public License as published by the Free #
+# Software Foundation; version 2 of the License. #
+# #
+# This program is distributed in the hope that it will be useful, but WITHOUT #
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
+# more details. #
+# #
+# You should have received a copy of the GNU General Public License along #
+# with this program; if not, write to the Free Software Foundation, Inc., 59 #
+# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
+###############################################################################
+
+from PyQt4 import QtGui
+
+from openlp.plugins.images.forms.choosegroupdialog import Ui_ChooseGroupDialog
+
+
+class ChooseGroupForm(QtGui.QDialog, Ui_ChooseGroupDialog):
+ """
+ Class documentation goes here.
+ """
+ def __init__(self, parent=None):
+ """
+ Constructor
+ """
+ QtGui.QDialog.__init__(self, parent)
+ self.setupUi(self)
+
+ def exec_(self, selected_group=None):
+ if selected_group is not None:
+ for i in range(self.group_combobox.count()):
+ if self.group_combobox.itemData(i) == selected_group:
+ self.group_combobox.setCurrentIndex(i)
+ return QtGui.QDialog.exec_(self)
=== modified file 'openlp/plugins/images/imageplugin.py'
--- openlp/plugins/images/imageplugin.py 2013-02-16 18:24:31 +0000
+++ openlp/plugins/images/imageplugin.py 2013-03-04 14:42:22 +0000
@@ -32,13 +32,16 @@
import logging
from openlp.core.lib import Plugin, StringContent, Registry, ImageSource, Settings, build_icon, translate
+from openlp.core.lib.db import Manager
from openlp.plugins.images.lib import ImageMediaItem, ImageTab
+from openlp.plugins.images.lib.db import init_schema, ImageFilenames
log = logging.getLogger(__name__)
__default_settings__ = {
- u'images/images files': []
- }
+ u'images/db type': u'sqlite',
+ u'images/background color': u'#000000',
+}
class ImagePlugin(Plugin):
@@ -46,6 +49,7 @@
def __init__(self):
Plugin.__init__(self, u'images', __default_settings__, ImageMediaItem, ImageTab)
+ self.manager = Manager(u'images', init_schema)
self.weight = -7
self.iconPath = u':/plugins/plugin_images.png'
self.icon = build_icon(self.iconPath)
@@ -65,6 +69,26 @@
'provided by the theme.')
return about_text
+ def app_startup(self):
+ """
+ Perform tasks on application startup
+ """
+ Plugin.app_startup(self)
+ # Convert old settings-based image list to the database
+ files_from_config = Settings().get_files_from_config(self)
+ if len(files_from_config) > 0:
+ log.debug(u'Importing images list from old config: %s' % files_from_config)
+ self.mediaItem.save_new_images_list(files_from_config)
+
+ def upgrade_settings(self, settings):
+ """
+ Upgrade the settings of this plugin.
+ """
+ files_from_config = settings.get_files_from_config(self)
+ if len(files_from_config) > 0:
+ log.debug(u'Importing images list from old config: %s' % files_from_config)
+ self.mediaItem.save_new_images_list(files_from_config)
+
def setPluginTextStrings(self):
"""
Called to define all translatable texts of the plugin
@@ -75,8 +99,7 @@
u'plural': translate('ImagePlugin', 'Images', 'name plural')
}
## Name for MediaDockManager, SettingsManager ##
- self.textStrings[StringContent.VisibleName] = {u'title': translate('ImagePlugin', 'Images', 'container title')
- }
+ self.textStrings[StringContent.VisibleName] = {u'title': translate('ImagePlugin', 'Images', 'container title')}
# Middle Header Bar
tooltips = {
u'load': translate('ImagePlugin', 'Load a new image.'),
=== added file 'openlp/plugins/images/lib/db.py'
--- openlp/plugins/images/lib/db.py 1970-01-01 00:00:00 +0000
+++ openlp/plugins/images/lib/db.py 2013-03-04 14:42:22 +0000
@@ -0,0 +1,99 @@
+# -*- coding: utf-8 -*-
+# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
+
+###############################################################################
+# OpenLP - Open Source Lyrics Projection #
+# --------------------------------------------------------------------------- #
+# Copyright (c) 2008-2013 Raoul Snyman #
+# Portions copyright (c) 2008-2013 Tim Bentley, Gerald Britton, Jonathan #
+# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, #
+# Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer. #
+# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru, #
+# Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, #
+# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Dave Warnock, #
+# Frode Woldsund, Martin Zibricky, Patrick Zimmermann #
+# --------------------------------------------------------------------------- #
+# This program is free software; you can redistribute it and/or modify it #
+# under the terms of the GNU General Public License as published by the Free #
+# Software Foundation; version 2 of the License. #
+# #
+# This program is distributed in the hope that it will be useful, but WITHOUT #
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
+# more details. #
+# #
+# You should have received a copy of the GNU General Public License along #
+# with this program; if not, write to the Free Software Foundation, Inc., 59 #
+# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
+###############################################################################
+"""
+The :mod:`db` module provides the database and schema that is the backend for the Images plugin
+"""
+
+from sqlalchemy import Column, ForeignKey, Table, types
+from sqlalchemy.orm import mapper, relation, reconstructor
+
+from openlp.core.lib.db import BaseModel, init_db
+
+
+class ImageGroups(BaseModel):
+ """
+ ImageGroups model
+ """
+ pass
+
+
+class ImageFilenames(BaseModel):
+ """
+ ImageFilenames model
+ """
+ pass
+
+
+def init_schema(url):
+ """
+ Setup the images database connection and initialise the database schema.
+
+ ``url``
+ The database to setup
+
+ The images database contains the following tables:
+
+ * image_groups
+ * image_filenames
+
+ **image_groups Table**
+ This table holds the names of the images groups. It has the following columns:
+
+ * id
+ * parent_id
+ * group_name
+
+ **image_filenames Table**
+ This table holds the filenames of the images and the group they belong to. It has the following columns:
+
+ * id
+ * group_id
+ * filename
+ """
+ session, metadata = init_db(url)
+
+ # Definition of the "image_groups" table
+ image_groups_table = Table(u'image_groups', metadata,
+ Column(u'id', types.Integer(), primary_key=True),
+ Column(u'parent_id', types.Integer()),
+ Column(u'group_name', types.Unicode(128))
+ )
+
+ # Definition of the "image_filenames" table
+ image_filenames_table = Table(u'image_filenames', metadata,
+ Column(u'id', types.Integer(), primary_key=True),
+ Column(u'group_id', types.Integer(), ForeignKey(u'image_groups.id'), default=None),
+ Column(u'filename', types.Unicode(255), nullable=False)
+ )
+
+ mapper(ImageGroups, image_groups_table)
+ mapper(ImageFilenames, image_filenames_table)
+
+ metadata.create_all(checkfirst=True)
+ return session
=== modified file 'openlp/plugins/images/lib/imagetab.py'
--- openlp/plugins/images/lib/imagetab.py 2013-02-07 08:42:17 +0000
+++ openlp/plugins/images/lib/imagetab.py 2013-03-04 14:42:22 +0000
@@ -31,6 +31,7 @@
from openlp.core.lib import SettingsTab, Registry, Settings, UiStrings, translate
+
class ImageTab(SettingsTab):
"""
ImageTab is the images settings tab in the settings dialog.
@@ -92,4 +93,3 @@
settings.endGroup()
if self.initial_color != self.bg_color:
Registry().execute(u'image_updated')
-
=== modified file 'openlp/plugins/images/lib/mediaitem.py'
--- openlp/plugins/images/lib/mediaitem.py 2013-02-27 11:33:03 +0000
+++ openlp/plugins/images/lib/mediaitem.py 2013-03-04 14:42:22 +0000
@@ -32,13 +32,17 @@
from PyQt4 import QtCore, QtGui
-from openlp.core.lib import MediaManagerItem, ItemCapabilities, Registry, ServiceItemContext, Settings, UiStrings, \
- build_icon, check_item_selected, check_directory_exists, create_thumb, translate, validate_thumb
-from openlp.core.lib.ui import critical_error_message_box
+from openlp.core.lib import ItemCapabilities, MediaManagerItem, Registry, ServiceItemContext, Settings, \
+ StringContent, TreeWidgetWithDnD, UiStrings, build_icon, check_directory_exists, check_item_selected, \
+ create_thumb, translate, validate_thumb
+from openlp.core.lib.ui import create_widget_action, critical_error_message_box
from openlp.core.utils import AppLocation, delete_file, locale_compare, get_images_filter
+from openlp.plugins.images.forms import AddGroupForm, ChooseGroupForm
+from openlp.plugins.images.lib.db import ImageFilenames, ImageGroups
log = logging.getLogger(__name__)
+
class ImageMediaItem(MediaManagerItem):
"""
This is the custom media manager item for images.
@@ -50,6 +54,11 @@
MediaManagerItem.__init__(self, parent, plugin, icon)
self.quickPreviewAllowed = True
self.hasSearch = True
+ self.manager = plugin.manager
+ self.choose_group_form = ChooseGroupForm(self)
+ self.add_group_form = AddGroupForm(self)
+ self.fill_groups_combobox(self.choose_group_form.group_combobox)
+ self.fill_groups_combobox(self.add_group_form.parent_group_combobox)
Registry().register_function(u'live_theme_changed', self.live_theme_changed)
# Allow DnD from the desktop
self.listView.activateDnD()
@@ -59,6 +68,8 @@
'Select Image(s)')
file_formats = get_images_filter()
self.onNewFileMasks = u'%s;;%s (*.*) (*)' % (file_formats, UiStrings().AllFiles)
+ self.addGroupAction.setText(UiStrings().AddGroup)
+ self.addGroupAction.setToolTip(UiStrings().AddGroup)
self.replaceAction.setText(UiStrings().ReplaceBG)
self.replaceAction.setToolTip(UiStrings().ReplaceLiveBG)
self.resetAction.setText(UiStrings().ResetBG)
@@ -75,70 +86,342 @@
log.debug(u'initialise')
self.listView.clear()
self.listView.setIconSize(QtCore.QSize(88, 50))
+ self.listView.setIndentation(self.listView.defaultIndentation)
+ self.listView.allow_internal_dnd = True
self.servicePath = os.path.join(AppLocation.get_section_data_path(self.settingsSection), u'thumbnails')
check_directory_exists(self.servicePath)
- self.loadList(Settings().value(self.settingsSection + u'/images files'), True)
+ # Load images from the database
+ self.loadFullList(
+ self.manager.get_all_objects(ImageFilenames, order_by_ref=ImageFilenames.filename), initial_load=True)
def addListViewToToolBar(self):
- MediaManagerItem.addListViewToToolBar(self)
+ """
+ Creates the main widget for listing items the media item is tracking.
+ This method overloads MediaManagerItem.addListViewToToolBar
+ """
+ # Add the List widget
+ self.listView = TreeWidgetWithDnD(self, self.plugin.name)
+ self.listView.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection)
+ self.listView.setAlternatingRowColors(True)
+ self.listView.setObjectName(u'%sTreeView' % self.plugin.name)
+ # Add to pageLayout
+ self.pageLayout.addWidget(self.listView)
+ # define and add the context menu
+ self.listView.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
+ if self.hasEditIcon:
+ create_widget_action(self.listView,
+ text=self.plugin.getString(StringContent.Edit)[u'title'],
+ icon=u':/general/general_edit.png',
+ triggers=self.onEditClick)
+ create_widget_action(self.listView, separator=True)
+ if self.hasDeleteIcon:
+ create_widget_action(self.listView,
+ text=self.plugin.getString(StringContent.Delete)[u'title'],
+ icon=u':/general/general_delete.png',
+ shortcuts=[QtCore.Qt.Key_Delete], triggers=self.onDeleteClick)
+ create_widget_action(self.listView, separator=True)
+ create_widget_action(self.listView,
+ text=self.plugin.getString(StringContent.Preview)[u'title'],
+ icon=u':/general/general_preview.png',
+ shortcuts=[QtCore.Qt.Key_Enter, QtCore.Qt.Key_Return],
+ triggers=self.onPreviewClick)
+ create_widget_action(self.listView,
+ text=self.plugin.getString(StringContent.Live)[u'title'],
+ icon=u':/general/general_live.png',
+ shortcuts=[QtCore.Qt.ShiftModifier | QtCore.Qt.Key_Enter,
+ QtCore.Qt.ShiftModifier | QtCore.Qt.Key_Return],
+ triggers=self.onLiveClick)
+ create_widget_action(self.listView,
+ text=self.plugin.getString(StringContent.Service)[u'title'],
+ icon=u':/general/general_add.png',
+ shortcuts=[QtCore.Qt.Key_Plus, QtCore.Qt.Key_Equal],
+ triggers=self.onAddClick)
+ if self.addToServiceItem:
+ create_widget_action(self.listView, separator=True)
+ create_widget_action(self.listView,
+ text=translate('OpenLP.MediaManagerItem', '&Add to selected Service Item'),
+ icon=u':/general/general_add.png',
+ triggers=self.onAddEditClick)
+ self.addCustomContextActions()
+ # Create the context menu and add all actions from the listView.
+ self.menu = QtGui.QMenu()
+ self.menu.addActions(self.listView.actions())
+ self.listView.doubleClicked.connect(self.onDoubleClicked)
+ self.listView.itemSelectionChanged.connect(self.onSelectionChange)
+ self.listView.customContextMenuRequested.connect(self.contextMenu)
self.listView.addAction(self.replaceAction)
+ def addStartHeaderBar(self):
+ self.addGroupAction = self.toolbar.addToolbarAction(u'addGroupAction',
+ icon=u':/images/image_new_group.png', triggers=self.onAddGroupClick)
+
def addEndHeaderBar(self):
self.replaceAction = self.toolbar.addToolbarAction(u'replaceAction',
icon=u':/slides/slide_blank.png', triggers=self.onReplaceClick)
self.resetAction = self.toolbar.addToolbarAction(u'resetAction',
icon=u':/system/system_close.png', visible=False, triggers=self.onResetClick)
+ def recursivelyDeleteGroup(self, image_group):
+ """
+ Recursively deletes a group and all groups and images in it
+ """
+ images = self.manager.get_all_objects(ImageFilenames, ImageFilenames.group_id == image_group.id)
+ for image in images:
+ delete_file(os.path.join(self.servicePath, os.path.split(image.filename)[1]))
+ self.manager.delete_object(ImageFilenames, image.id)
+ image_groups = self.manager.get_all_objects(ImageGroups, ImageGroups.parent_id == image_group.id)
+ for group in image_groups:
+ self.recursivelyDeleteGroup(group)
+ self.manager.delete_object(ImageGroups, group.id)
+
def onDeleteClick(self):
"""
Remove an image item from the list
"""
# Turn off auto preview triggers.
self.listView.blockSignals(True)
- if check_item_selected(self.listView, translate('ImagePlugin.MediaItem','You must select an image to delete.')):
- row_list = [item.row() for item in self.listView.selectedIndexes()]
- row_list.sort(reverse=True)
+ if check_item_selected(self.listView, translate('ImagePlugin.MediaItem',
+ 'You must select an image or group to delete.')):
+ item_list = self.listView.selectedItems()
self.application.set_busy_cursor()
- self.main_window.displayProgressBar(len(row_list))
- for row in row_list:
- text = self.listView.item(row)
- if text:
- delete_file(os.path.join(self.servicePath, text.text()))
- self.listView.takeItem(row)
+ self.main_window.displayProgressBar(len(item_list))
+ for row_item in item_list:
+ if row_item:
+ item_data = row_item.data(0, QtCore.Qt.UserRole)
+ if isinstance(item_data, ImageFilenames):
+ delete_file(os.path.join(self.servicePath, row_item.text(0)))
+ if item_data.group_id == 0:
+ self.listView.takeTopLevelItem(self.listView.indexOfTopLevelItem(row_item))
+ else:
+ row_item.parent().removeChild(row_item)
+ self.manager.delete_object(ImageFilenames, row_item.data(0, QtCore.Qt.UserRole).id)
+ elif isinstance(item_data, ImageGroups):
+ if QtGui.QMessageBox.question(self.listView.parent(),
+ translate('ImagePlugin.MediaItem', 'Remove group'),
+ translate('ImagePlugin.MediaItem',
+ 'Are you sure you want to remove "%s" and everything in it?') % item_data.group_name,
+ QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Yes |
+ QtGui.QMessageBox.No)) == QtGui.QMessageBox.Yes:
+ self.recursivelyDeleteGroup(item_data)
+ self.manager.delete_object(ImageGroups, row_item.data(0, QtCore.Qt.UserRole).id)
+ if item_data.parent_id is 0:
+ self.listView.takeTopLevelItem(self.listView.indexOfTopLevelItem(row_item))
+ else:
+ row_item.parent().removeChild(row_item)
+ self.fill_groups_combobox(self.choose_group_form.group_combobox)
+ self.fill_groups_combobox(self.add_group_form.parent_group_combobox)
self.main_window.incrementProgressBar()
- Settings.setValue(self.settingsSection + u'/images files', self.getFileList())
self.main_window.finishedProgressBar()
self.application.set_normal_cursor()
self.listView.blockSignals(False)
- def loadList(self, images, initialLoad=False):
- self.application.set_busy_cursor()
- if not initialLoad:
+ def add_sub_groups(self, group_list, parent_group_id):
+ """
+ Recursively add subgroups to the given parent group in a QTreeWidget
+ """
+ image_groups = self.manager.get_all_objects(ImageGroups, ImageGroups.parent_id == parent_group_id)
+ image_groups.sort(cmp=locale_compare, key=lambda group_object: group_object.group_name)
+ folder_icon = build_icon(u':/images/image_group.png')
+ for image_group in image_groups:
+ group = QtGui.QTreeWidgetItem()
+ group.setText(0, image_group.group_name)
+ group.setData(0, QtCore.Qt.UserRole, image_group)
+ group.setIcon(0, folder_icon)
+ if parent_group_id is 0:
+ self.listView.addTopLevelItem(group)
+ else:
+ group_list[parent_group_id].addChild(group)
+ group_list[image_group.id] = group
+ self.add_sub_groups(group_list, image_group.id)
+
+ def fill_groups_combobox(self, combobox, parent_group_id=0, prefix=''):
+ """
+ Recursively add groups to the combobox in the 'Add group' dialog
+ """
+ if parent_group_id is 0:
+ combobox.clear()
+ combobox.top_level_group_added = False
+ image_groups = self.manager.get_all_objects(ImageGroups, ImageGroups.parent_id == parent_group_id)
+ image_groups.sort(cmp=locale_compare, key=lambda group_object: group_object.group_name)
+ for image_group in image_groups:
+ combobox.addItem(prefix + image_group.group_name, image_group.id)
+ self.fill_groups_combobox(combobox, image_group.id, prefix + ' ')
+
+ def expand_group(self, group_id, root_item=None):
+ return_value = False
+ if root_item is None:
+ root_item = self.listView.invisibleRootItem()
+ for i in range(root_item.childCount()):
+ child = root_item.child(i)
+ if self.expand_group(group_id, child):
+ child.setExpanded(True)
+ return_value = True
+ if isinstance(root_item.data(0, QtCore.Qt.UserRole), ImageGroups):
+ if root_item.data(0, QtCore.Qt.UserRole).id == group_id:
+ return True
+ return return_value
+
+ def loadFullList(self, images, initial_load=False, open_group=None):
+ """
+ Replace the list of images and groups in the interface.
+ """
+ if not initial_load:
+ self.application.set_busy_cursor()
self.main_window.displayProgressBar(len(images))
+ self.listView.clear()
+ # Load the list of groups and add them to the treeView
+ group_items = {}
+ self.add_sub_groups(group_items, parent_group_id=0)
+ if open_group is not None:
+ self.expand_group(open_group.id)
# Sort the images by its filename considering language specific
# characters.
- images.sort(cmp=locale_compare, key=lambda filename: os.path.split(unicode(filename))[1])
+ images.sort(cmp=locale_compare, key=lambda image_object: os.path.split(unicode(image_object.filename))[1])
for imageFile in images:
- filename = os.path.split(unicode(imageFile))[1]
+ log.debug(u'Loading image: %s', imageFile.filename)
+ filename = os.path.split(imageFile.filename)[1]
thumb = os.path.join(self.servicePath, filename)
- if not os.path.exists(unicode(imageFile)):
+ if not os.path.exists(imageFile.filename):
icon = build_icon(u':/general/general_delete.png')
else:
- if validate_thumb(unicode(imageFile), thumb):
+ if validate_thumb(imageFile.filename, thumb):
icon = build_icon(thumb)
else:
- icon = create_thumb(unicode(imageFile), thumb)
- item_name = QtGui.QListWidgetItem(filename)
- item_name.setIcon(icon)
- item_name.setToolTip(imageFile)
- item_name.setData(QtCore.Qt.UserRole, imageFile)
- self.listView.addItem(item_name)
- if not initialLoad:
+ icon = create_thumb(imageFile.filename, thumb)
+ item_name = QtGui.QTreeWidgetItem(filename)
+ item_name.setText(0, filename)
+ item_name.setIcon(0, icon)
+ item_name.setToolTip(0, imageFile.filename)
+ item_name.setData(0, QtCore.Qt.UserRole, imageFile)
+ if imageFile.group_id is 0:
+ self.listView.addTopLevelItem(item_name)
+ else:
+ group_items[imageFile.group_id].addChild(item_name)
+ if not initial_load:
self.main_window.incrementProgressBar()
- if not initialLoad:
+ if not initial_load:
self.main_window.finishedProgressBar()
self.application.set_normal_cursor()
+ def validateAndLoad(self, files, target_group=None):
+ """
+ Process a list for files either from the File Dialog or from Drag and
+ Drop. This method is overloaded from MediaManagerItem.
+
+ ``files``
+ The files to be loaded.
+ """
+ self.loadList(files, target_group)
+ last_dir = os.path.split(unicode(files[0]))[0]
+ Settings().setValue(self.settingsSection + u'/last directory', last_dir)
+
+ def loadList(self, images, target_group=None, initial_load=False):
+ """
+ Add new images to the database. This method is called when adding images using the Add button or DnD.
+ """
+ if target_group is None:
+ # Find out if a group must be pre-selected
+ preselect_group = None
+ selected_items = self.listView.selectedItems()
+ if len(selected_items) > 0:
+ selected_item = selected_items[0]
+ if isinstance(selected_item.data(0, QtCore.Qt.UserRole), ImageFilenames):
+ selected_item = selected_item.parent()
+ if isinstance(selected_item, QtGui.QTreeWidgetItem):
+ if isinstance(selected_item.data(0, QtCore.Qt.UserRole), ImageGroups):
+ preselect_group = selected_item.data(0, QtCore.Qt.UserRole).id
+ # Enable and disable parts of the 'choose group' form
+ if preselect_group is None:
+ self.choose_group_form.nogroup_radio_button.setChecked(True)
+ self.choose_group_form.existing_radio_button.setChecked(False)
+ self.choose_group_form.new_radio_button.setChecked(False)
+ else:
+ self.choose_group_form.nogroup_radio_button.setChecked(False)
+ self.choose_group_form.existing_radio_button.setChecked(True)
+ self.choose_group_form.new_radio_button.setChecked(False)
+ if self.manager.get_object_count(ImageGroups) == 0:
+ self.choose_group_form.existing_radio_button.setDisabled(True)
+ self.choose_group_form.group_combobox.setDisabled(True)
+ else:
+ self.choose_group_form.existing_radio_button.setDisabled(False)
+ self.choose_group_form.group_combobox.setDisabled(False)
+ # Ask which group the images should be saved in
+ if self.choose_group_form.exec_(selected_group=preselect_group):
+ if self.choose_group_form.nogroup_radio_button.isChecked():
+ # User chose 'No group'
+ parent_group = ImageGroups()
+ parent_group.id = 0
+ elif self.choose_group_form.existing_radio_button.isChecked():
+ # User chose 'Existing group'
+ group_id = self.choose_group_form.group_combobox.itemData(
+ self.choose_group_form.group_combobox.currentIndex(), QtCore.Qt.UserRole)
+ parent_group = self.manager.get_object_filtered(ImageGroups, ImageGroups.id == group_id)
+ elif self.choose_group_form.new_radio_button.isChecked():
+ # User chose 'New group'
+ parent_group = ImageGroups()
+ parent_group.parent_id = 0
+ parent_group.group_name = self.choose_group_form.new_group_edit.text()
+ self.manager.save_object(parent_group)
+ else:
+ parent_group = target_group.data(0, QtCore.Qt.UserRole)
+ if isinstance(parent_group, ImageFilenames):
+ if parent_group.group_id == 0:
+ parent_group = ImageGroups()
+ parent_group.id = 0
+ else:
+ parent_group = target_group.parent().data(0, QtCore.Qt.UserRole)
+ # If no valid parent group is found, do nothing
+ if not isinstance(parent_group, ImageGroups):
+ return
+ # Save the new images in the database
+ self.save_new_images_list(images, group_id=parent_group.id, reload_list=False)
+ self.loadFullList(self.manager.get_all_objects(ImageFilenames, order_by_ref=ImageFilenames.filename),
+ initial_load=initial_load, open_group=parent_group)
+
+ def save_new_images_list(self, images_list, group_id=0, reload_list=True):
+ for filename in images_list:
+ if type(filename) is not str and type(filename) is not unicode:
+ continue
+ log.debug(u'Adding new image: %s', filename)
+ imageFile = ImageFilenames()
+ imageFile.group_id = group_id
+ imageFile.filename = unicode(filename)
+ self.manager.save_object(imageFile)
+ if reload_list:
+ self.loadFullList(self.manager.get_all_objects(ImageFilenames, order_by_ref=ImageFilenames.filename))
+
+ def dnd_move_internal(self, target):
+ """
+ Handle drag-and-drop moving of images within the media manager
+ """
+ items_to_move = self.listView.selectedItems()
+ # Determine group to move images to
+ target_group = target
+ if target_group is not None and isinstance(target_group.data(0, QtCore.Qt.UserRole), ImageFilenames):
+ target_group = target.parent()
+ # Move to toplevel
+ if target_group is None:
+ target_group = self.listView.invisibleRootItem()
+ target_group.setData(0, QtCore.Qt.UserRole, ImageGroups())
+ target_group.data(0, QtCore.Qt.UserRole).id = 0
+ # Move images in the treeview
+ items_to_save = []
+ for item in items_to_move:
+ if isinstance(item.data(0, QtCore.Qt.UserRole), ImageFilenames):
+ if isinstance(item.parent(), QtGui.QTreeWidgetItem):
+ item.parent().removeChild(item)
+ else:
+ self.listView.invisibleRootItem().removeChild(item)
+ target_group.addChild(item)
+ item.setSelected(True)
+ item_data = item.data(0, QtCore.Qt.UserRole)
+ item_data.group_id = target_group.data(0, QtCore.Qt.UserRole).id
+ items_to_save.append(item_data)
+ target_group.setExpanded(True)
+ target_group.sortChildren(0, QtCore.Qt.AscendingOrder)
+ # Update the group ID's of the images in the database
+ self.manager.save_objects(items_to_save)
+
def generateSlideData(self, service_item, item=None, xmlVersion=False,
remote=False, context=ServiceItemContext.Service):
background = QtGui.QColor(Settings().value(self.settingsSection + u'/background color'))
@@ -148,7 +431,11 @@
items = self.listView.selectedItems()
if not items:
return False
- service_item.title = unicode(self.plugin.nameStrings[u'plural'])
+ # Determine service item title
+ if isinstance(items[0].data(0, QtCore.Qt.UserRole), ImageGroups):
+ service_item.title = items[0].text(0)
+ else:
+ service_item.title = unicode(self.plugin.nameStrings[u'plural'])
service_item.add_capability(ItemCapabilities.CanMaintain)
service_item.add_capability(ItemCapabilities.CanPreview)
service_item.add_capability(ItemCapabilities.CanLoop)
@@ -157,8 +444,16 @@
service_item.theme = -1
missing_items = []
missing_items_filenames = []
- for bitem in items:
- filename = bitem.data(QtCore.Qt.UserRole)
+ # Expand groups to images
+ for bitem in items:
+ if isinstance(bitem.data(0, QtCore.Qt.UserRole), ImageGroups) or bitem.data(0, QtCore.Qt.UserRole) is None:
+ for index in range(0, bitem.childCount()):
+ if isinstance(bitem.child(index).data(0, QtCore.Qt.UserRole), ImageFilenames):
+ items.append(bitem.child(index))
+ items.remove(bitem)
+ # Find missing files
+ for bitem in items:
+ filename = bitem.data(0, QtCore.Qt.UserRole).filename
if not os.path.exists(filename):
missing_items.append(bitem)
missing_items_filenames.append(filename)
@@ -181,11 +476,70 @@
return False
# Continue with the existing images.
for bitem in items:
- filename = bitem.data(QtCore.Qt.UserRole)
+ filename = bitem.data(0, QtCore.Qt.UserRole).filename
name = os.path.split(filename)[1]
service_item.add_from_image(filename, name, background)
return True
+ def __checkObject(self, objects, newObject, edit):
+ """
+ Utility method to check for an existing object.
+
+ ``edit``
+ If we edit an item, this should be *True*.
+ """
+ if objects:
+ # If we edit an existing object, we need to make sure that we do
+ # not return False when nothing has changed.
+ if edit:
+ for object in objects:
+ if object.id != newObject.id:
+ return False
+ return True
+ else:
+ return False
+ else:
+ return True
+
+ def checkGroupName(self, newGroup, edit=False):
+ """
+ Returns *False* if the given Group already exists, otherwise *True*.
+ """
+ groups = self.manager.get_all_objects(ImageGroups, ImageGroups.group_name == newGroup.group_name)
+ return self.__checkObject(groups, newGroup, edit)
+
+ def onAddGroupClick(self):
+ """
+ Called to add a new group
+ """
+ # Find out if a group must be pre-selected
+ preselect_group = 0
+ selected_items = self.listView.selectedItems()
+ if len(selected_items) > 0:
+ selected_item = selected_items[0]
+ if isinstance(selected_item.data(0, QtCore.Qt.UserRole), ImageFilenames):
+ selected_item = selected_item.parent()
+ if isinstance(selected_item, QtGui.QTreeWidgetItem):
+ if isinstance(selected_item.data(0, QtCore.Qt.UserRole), ImageGroups):
+ preselect_group = selected_item.data(0, QtCore.Qt.UserRole).id
+ # Show 'add group' dialog
+ if self.add_group_form.exec_(show_top_level_group=True, selected_group=preselect_group):
+ new_group = ImageGroups.populate(parent_id=self.add_group_form.parent_group_combobox.itemData(
+ self.add_group_form.parent_group_combobox.currentIndex(), QtCore.Qt.UserRole),
+ group_name=self.add_group_form.name_edit.text())
+ if self.checkGroupName(new_group):
+ if self.manager.save_object(new_group):
+ self.loadFullList(self.manager.get_all_objects(ImageFilenames,
+ order_by_ref=ImageFilenames.filename))
+ self.fill_groups_combobox(self.choose_group_form.group_combobox)
+ self.fill_groups_combobox(self.add_group_form.parent_group_combobox)
+ else:
+ critical_error_message_box(
+ message=translate('ImagePlugin.AddGroupForm', 'Could not add the new group.'))
+ else:
+ critical_error_message_box(
+ message=translate('ImagePlugin.AddGroupForm', 'This group already exists.'))
+
def onResetClick(self):
"""
Called to reset the Live background with the image selected,
@@ -206,9 +560,8 @@
if check_item_selected(self.listView,
translate('ImagePlugin.MediaItem', 'You must select an image to replace the background with.')):
background = QtGui.QColor(Settings().value(self.settingsSection + u'/background color'))
- item = self.listView.selectedIndexes()[0]
- bitem = self.listView.item(item.row())
- filename = bitem.data(QtCore.Qt.UserRole)
+ bitem = self.listView.selectedItems()[0]
+ filename = bitem.data(0, QtCore.Qt.UserRole).filename
if os.path.exists(filename):
if self.live_controller.display.directImage(filename, background):
self.resetAction.setVisible(True)
@@ -221,11 +574,10 @@
'the image file "%s" no longer exists.') % filename)
def search(self, string, showError):
- files = Settings().value(self.settingsSection + u'/images files')
+ files = self.manager.get_all_objects(ImageFilenames, filter_clause=ImageFilenames.filename.contains(string),
+ order_by_ref=ImageFilenames.filename)
results = []
- string = string.lower()
- for file in files:
- filename = os.path.split(unicode(file))[1]
- if filename.lower().find(string) > -1:
- results.append([file, filename])
+ for file_object in files:
+ filename = os.path.split(unicode(file_object.filename))[1]
+ results.append([file_object.filename, filename])
return results
=== modified file 'openlp/plugins/media/lib/mediaitem.py'
--- openlp/plugins/media/lib/mediaitem.py 2013-02-07 11:33:47 +0000
+++ openlp/plugins/media/lib/mediaitem.py 2013-03-04 14:42:22 +0000
@@ -254,7 +254,7 @@
self.listView.takeItem(row)
Settings().setValue(self.settingsSection + u'/media files', self.getFileList())
- def loadList(self, media):
+ def loadList(self, media, target_group=None):
# Sort the media by its filename considering language specific
# characters.
media.sort(cmp=locale_compare, key=lambda filename: os.path.split(unicode(filename))[1])
=== modified file 'openlp/plugins/presentations/lib/mediaitem.py'
--- openlp/plugins/presentations/lib/mediaitem.py 2013-02-07 11:33:47 +0000
+++ openlp/plugins/presentations/lib/mediaitem.py 2013-03-04 14:42:22 +0000
@@ -120,7 +120,7 @@
"""
self.listView.setIconSize(QtCore.QSize(88, 50))
files = Settings().value(self.settingsSection + u'/presentations files')
- self.loadList(files, True)
+ self.loadList(files, initialLoad=True)
self.populate_display_types()
def populate_display_types(self):
@@ -141,7 +141,7 @@
else:
self.presentationWidget.hide()
- def loadList(self, files, initialLoad=False):
+ def loadList(self, files, target_group=None, initialLoad=False):
"""
Add presentations into the media manager
This is called both on initial load of the plugin to populate with
=== added file 'resources/forms/imagesaddgroupdialog.ui'
--- resources/forms/imagesaddgroupdialog.ui 1970-01-01 00:00:00 +0000
+++ resources/forms/imagesaddgroupdialog.ui 2013-03-04 14:42:22 +0000
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>AddGroupDialog</class>
+ <widget class="QDialog" name="AddGroupDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>365</width>
+ <height>119</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Add group</string>
+ </property>
+ <layout class="QFormLayout" name="AddGroupLayout">
+ <property name="fieldGrowthPolicy">
+ <enum>QFormLayout::ExpandingFieldsGrow</enum>
+ </property>
+ <property name="horizontalSpacing">
+ <number>8</number>
+ </property>
+ <property name="verticalSpacing">
+ <number>8</number>
+ </property>
+ <property name="margin">
+ <number>8</number>
+ </property>
+ <item row="1" column="0">
+ <widget class="QLabel" name="ParentGroupLabel">
+ <property name="text">
+ <string>Parent group:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QComboBox" name="ParentGroupComboBox"/>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="GroupNameLabel">
+ <property name="text">
+ <string>Group name:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QLineEdit" name="GroupNameEdit"/>
+ </item>
+ <item row="3" column="1">
+ <widget class="QDialogButtonBox" name="GroupButtonBox">
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Save</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources>
+ <include location="../images/openlp-2.qrc"/>
+ </resources>
+ <connections/>
+</ui>
=== added file 'resources/forms/imageschoosegroupdialog.ui'
--- resources/forms/imageschoosegroupdialog.ui 1970-01-01 00:00:00 +0000
+++ resources/forms/imageschoosegroupdialog.ui 2013-03-04 14:42:22 +0000
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ChooseGroupDialog</class>
+ <widget class="QDialog" name="ChooseGroupDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>440</width>
+ <height>119</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Choose group</string>
+ </property>
+ <layout class="QFormLayout" name="addGroupLayout">
+ <property name="fieldGrowthPolicy">
+ <enum>QFormLayout::ExpandingFieldsGrow</enum>
+ </property>
+ <property name="horizontalSpacing">
+ <number>8</number>
+ </property>
+ <property name="verticalSpacing">
+ <number>8</number>
+ </property>
+ <property name="margin">
+ <number>8</number>
+ </property>
+ <item row="1" column="0" colspan="2">
+ <widget class="QLabel" name="groupQuestionLabel">
+ <property name="text">
+ <string>To which group do you want these images to be added?</string>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QComboBox" name="groupComboBox"/>
+ </item>
+ <item row="3" column="1">
+ <widget class="QDialogButtonBox" name="groupButtonBox">
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Save</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources>
+ <include location="../images/openlp-2.qrc"/>
+ </resources>
+ <connections/>
+</ui>
=== added file 'resources/images/image_group.png'
Binary files resources/images/image_group.png 1970-01-01 00:00:00 +0000 and resources/images/image_group.png 2013-03-04 14:42:22 +0000 differ
=== added file 'resources/images/image_new_group.png'
Binary files resources/images/image_new_group.png 1970-01-01 00:00:00 +0000 and resources/images/image_new_group.png 2013-03-04 14:42:22 +0000 differ
=== modified file 'resources/images/openlp-2.qrc'
--- resources/images/openlp-2.qrc 2012-12-06 19:26:50 +0000
+++ resources/images/openlp-2.qrc 2013-03-04 14:42:22 +0000
@@ -21,6 +21,10 @@
<file>song_topic_edit.png</file>
<file>song_book_edit.png</file>
</qresource>
+ <qresource prefix="images">
+ <file>image_group.png</file>
+ <file>image_new_group.png</file>
+ </qresource>
<qresource prefix="bibles">
<file>bibles_search_text.png</file>
<file>bibles_search_reference.png</file>
Follow ups