This commit is contained in:
Andreas Preikschat 2011-02-15 10:06:24 +01:00
commit ef4bb199d8
77 changed files with 1428 additions and 789 deletions

View File

@ -4,8 +4,8 @@
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2010 Raoul Snyman #
# Portions copyright (c) 2008-2010 Tim Bentley, Jonathan Corwin, Michael #
# Copyright (c) 2008-2011 Raoul Snyman #
# Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael #
# Gorven, Scott Guerrieri, Meinert Jordan, Andreas Preikschat, Christian #
# Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon Tibble, #
# Carsten Tinggaard, Frode Woldsund #

View File

@ -6,18 +6,18 @@ Object Library
.. automodule:: openlp.core.lib
:members:
:mod:`BaseListWithDnD`
----------------------
.. autoclass:: openlp.core.lib.baselistwithdnd.BaseListWithDnD
:members:
:mod:`EventReceiver`
--------------------
.. autoclass:: openlp.core.lib.eventreceiver.EventReceiver
:members:
:mod:`ListWidgetWithDnD`
----------------------
.. autoclass:: openlp.core.lib.listwidgetwithdnd.ListWidgetWithDnD
:members:
:mod:`MediaManagerItem`
-----------------------

View File

@ -319,6 +319,7 @@ def check_directory_exists(dir):
if not os.path.exists(dir):
os.makedirs(dir)
from listwidgetwithdnd import ListWidgetWithDnD
from theme import ThemeLevel, ThemeXML, BackgroundGradientType, \
BackgroundType, HorizontalType, VerticalType
from displaytags import DisplayTags
@ -339,4 +340,3 @@ from dockwidget import OpenLPDockWidget
from renderer import Renderer
from rendermanager import RenderManager
from mediamanageritem import MediaManagerItem
from baselistwithdnd import BaseListWithDnD

View File

@ -28,7 +28,8 @@ import logging
from PyQt4 import QtWebKit
from openlp.core.lib import BackgroundType, BackgroundGradientType
from openlp.core.lib import BackgroundType, BackgroundGradientType, \
VerticalType
log = logging.getLogger(__name__)
@ -536,12 +537,7 @@ def build_lyrics_format_css(theme, width, height):
align = u'right'
else:
align = u'left'
if theme.display_vertical_align == 2:
valign = u'bottom'
elif theme.display_vertical_align == 1:
valign = u'middle'
else:
valign = u'top'
valign = VerticalType.to_string(theme.display_vertical_align)
if theme.font_main_outline:
left_margin = int(theme.font_main_outline_size) * 2
else:
@ -634,13 +630,7 @@ def build_alert_css(alertTab, width):
"""
if not alertTab:
return u''
align = u''
if alertTab.location == 2:
align = u'bottom'
elif alertTab.location == 1:
align = u'middle'
else:
align = u'top'
align = VerticalType.to_string(alertTab.location)
alert = style % (width, align, alertTab.font_face, alertTab.font_size,
alertTab.font_color, alertTab.bg_color)
return alert

View File

@ -28,17 +28,17 @@ Extend QListWidget to handle drag and drop functionality
"""
from PyQt4 import QtCore, QtGui
class BaseListWithDnD(QtGui.QListWidget):
class ListWidgetWithDnD(QtGui.QListWidget):
"""
Provide a list widget to store objects and handle drag and drop events
"""
def __init__(self, parent=None):
def __init__(self, parent=None, name=u''):
"""
Initialise the list widget
"""
QtGui.QListWidget.__init__(self, parent)
# this must be set by the class which is inheriting
assert(self.PluginName)
self.mimeDataText = name
assert(self.mimeDataText)
def mouseMoveEvent(self, event):
"""
@ -47,9 +47,10 @@ class BaseListWithDnD(QtGui.QListWidget):
just tell it what plugin to call
"""
if event.buttons() != QtCore.Qt.LeftButton:
event.ignore()
return
drag = QtGui.QDrag(self)
mimeData = QtCore.QMimeData()
drag.setMimeData(mimeData)
mimeData.setText(self.PluginName)
mimeData.setText(self.mimeDataText)
drag.start(QtCore.Qt.CopyAction)

View File

@ -33,7 +33,7 @@ from PyQt4 import QtCore, QtGui
from openlp.core.lib import context_menu_action, context_menu_separator, \
SettingsManager, OpenLPToolbar, ServiceItem, StringContent, build_icon, \
translate, Receiver
translate, Receiver, ListWidgetWithDnD
log = logging.getLogger(__name__)
@ -73,11 +73,6 @@ class MediaManagerItem(QtGui.QWidget):
assumes that the new action is to load a file. If not, you
need to override the ``OnNew`` method.
``self.ListViewWithDnD_class``
This must be a **class**, not an object, descended from
``openlp.core.lib.BaseListWithDnD`` that is not used in any
other part of OpenLP.
``self.PreviewFunction``
This must be a method which returns a QImage to represent the
item (usually a preview). No scaling is required, that is
@ -202,68 +197,50 @@ class MediaManagerItem(QtGui.QWidget):
"""
Create buttons for the media item toolbar
"""
toolbar_actions = []
## Import Button ##
if self.hasImportIcon:
import_string = self.plugin.getString(StringContent.Import)
self.addToolbarButton(
import_string[u'title'],
import_string[u'tooltip'],
u':/general/general_import.png', self.onImportClick)
toolbar_actions.append([StringContent.Import,
u':/general/general_import.png', self.onImportClick])
## Load Button ##
if self.hasFileIcon:
load_string = self.plugin.getString(StringContent.Load)
self.addToolbarButton(
load_string[u'title'],
load_string[u'tooltip'],
u':/general/general_open.png', self.onFileClick)
toolbar_actions.append([StringContent.Load,
u':/general/general_open.png', self.onFileClick])
## New Button ##
if self.hasNewIcon:
new_string = self.plugin.getString(StringContent.New)
self.addToolbarButton(
new_string[u'title'],
new_string[u'tooltip'],
u':/general/general_new.png', self.onNewClick)
toolbar_actions.append([StringContent.New,
u':/general/general_new.png', self.onNewClick])
## Edit Button ##
if self.hasEditIcon:
edit_string = self.plugin.getString(StringContent.Edit)
self.addToolbarButton(
edit_string[u'title'],
edit_string[u'tooltip'],
u':/general/general_edit.png', self.onEditClick)
toolbar_actions.append([StringContent.Edit,
u':/general/general_edit.png', self.onEditClick])
## Delete Button ##
if self.hasDeleteIcon:
delete_string = self.plugin.getString(StringContent.Delete)
self.addToolbarButton(
delete_string[u'title'],
delete_string[u'tooltip'],
u':/general/general_delete.png', self.onDeleteClick)
toolbar_actions.append([StringContent.Delete,
u':/general/general_delete.png', self.onDeleteClick])
## Separator Line ##
self.addToolbarSeparator()
## Preview ##
preview_string = self.plugin.getString(StringContent.Preview)
self.addToolbarButton(
preview_string[u'title'],
preview_string[u'tooltip'],
u':/general/general_preview.png', self.onPreviewClick)
toolbar_actions.append([StringContent.Preview,
u':/general/general_preview.png', self.onPreviewClick])
## Live Button ##
live_string = self.plugin.getString(StringContent.Live)
self.addToolbarButton(
live_string[u'title'],
live_string[u'tooltip'],
u':/general/general_live.png', self.onLiveClick)
toolbar_actions.append([StringContent.Live,
u':/general/general_live.png', self.onLiveClick])
## Add to service Button ##
service_string = self.plugin.getString(StringContent.Service)
toolbar_actions.append([StringContent.Service,
u':/general/general_add.png', self.onAddClick])
for action in toolbar_actions:
self.addToolbarButton(
service_string[u'title'],
service_string[u'tooltip'],
u':/general/general_add.png', self.onAddClick)
self.plugin.getString(action[0])[u'title'],
self.plugin.getString(action[0])[u'tooltip'],
action[1], action[2])
def addListViewToToolBar(self):
"""
Creates the main widget for listing items the media item is tracking
"""
# Add the List widget
self.listView = self.ListViewWithDnD_class(self)
self.listView = ListWidgetWithDnD(self, self.title)
self.listView.uniformItemSizes = True
self.listView.setSpacing(1)
self.listView.setSelectionMode(
@ -500,7 +477,7 @@ class MediaManagerItem(QtGui.QWidget):
"""
if not self.listView.selectedIndexes() and not self.remoteTriggered:
QtGui.QMessageBox.information(self,
translate('OpenLP.MediaManagerItem', 'No items selected'),
translate('OpenLP.MediaManagerItem', 'No Items Selected'),
translate('OpenLP.MediaManagerItem',
'You must select one or more items'))
else:

View File

@ -114,7 +114,8 @@ class Plugin(QtCore.QObject):
"""
log.info(u'loaded')
def __init__(self, name, version=None, pluginHelpers=None):
def __init__(self, name, version=None, pluginHelpers=None,
mediaItemClass=None, settingsTabClass=None):
"""
This is the constructor for the plugin object. This provides an easy
way for descendent plugins to populate common data. This method *must*
@ -132,6 +133,12 @@ class Plugin(QtCore.QObject):
``pluginHelpers``
Defaults to *None*. A list of helper objects.
``mediaItemClass``
The class name of the plugin's media item.
``settingsTabClass``
The class name of the plugin's settings tab.
"""
QtCore.QObject.__init__(self)
self.name = name
@ -141,6 +148,8 @@ class Plugin(QtCore.QObject):
self.version = version
self.settingsSection = self.name.lower()
self.icon = None
self.mediaItemClass = mediaItemClass
self.settingsTabClass = settingsTabClass
self.weight = 0
self.status = PluginStatus.Inactive
# Set up logging
@ -199,7 +208,9 @@ class Plugin(QtCore.QObject):
Construct a MediaManagerItem object with all the buttons and things
you need, and return it for integration into openlp.org.
"""
pass
if self.mediaItemClass:
return self.mediaItemClass(self, self, self.icon)
return None
def addImportMenuItem(self, importMenu):
"""
@ -230,9 +241,13 @@ class Plugin(QtCore.QObject):
def getSettingsTab(self):
"""
Create a tab for the settings window.
Create a tab for the settings window to display the configurable
options for this plugin to the user.
"""
pass
if self.settingsTabClass:
return self.settingsTabClass(self.name,
self.getString(StringContent.VisibleName)[u'title'])
return None
def addToMenu(self, menubar):
"""
@ -320,37 +335,39 @@ class Plugin(QtCore.QObject):
"""
return self.textStrings[name]
def setPluginTextStrings(self):
def setPluginUiTextStrings(self, tooltips):
"""
Called to define all translatable texts of the plugin
"""
## Load Action ##
self._setSingularTextString(StringContent.Load,
UiStrings.Load, UiStrings.LoadANew)
self.__setNameTextString(StringContent.Load,
UiStrings.Load, tooltips[u'load'])
## Import Action ##
self.__setNameTextString(StringContent.Import,
UiStrings.Import, tooltips[u'import'])
## New Action ##
self._setSingularTextString(StringContent.New,
UiStrings.Add, UiStrings.AddANew)
self.__setNameTextString(StringContent.New,
UiStrings.Add, tooltips[u'new'])
## Edit Action ##
self._setSingularTextString(StringContent.Edit,
UiStrings.Edit, UiStrings.EditSelect)
self.__setNameTextString(StringContent.Edit,
UiStrings.Edit, tooltips[u'edit'])
## Delete Action ##
self._setSingularTextString(StringContent.Delete,
UiStrings.Delete, UiStrings.DeleteSelect)
self.__setNameTextString(StringContent.Delete,
UiStrings.Delete, tooltips[u'delete'])
## Preview Action ##
self._setSingularTextString(StringContent.Preview,
UiStrings.Preview, UiStrings.PreviewSelect)
self.__setNameTextString(StringContent.Preview,
UiStrings.Preview, tooltips[u'preview'])
## Send Live Action ##
self._setSingularTextString(StringContent.Live,
UiStrings.Live, UiStrings.SendSelectLive)
self.__setNameTextString(StringContent.Live,
UiStrings.Live, tooltips[u'live'])
## Add to Service Action ##
self._setSingularTextString(StringContent.Service,
UiStrings.Service, UiStrings.AddSelectService)
self.__setNameTextString(StringContent.Service,
UiStrings.Service, tooltips[u'service'])
def _setSingularTextString(self, name, title, tooltip):
def __setNameTextString(self, name, title, tooltip):
"""
Utility method for creating a plugin's textStrings. This method makes
use of the singular name of the plugin object so must only be called
after this has been set.
"""
self.textStrings[name] = { u'title': title, u'tooltip': tooltip %
self.getString(StringContent.Name)[u'singular']}
self.textStrings[name] = {u'title': title, u'tooltip': tooltip}

View File

@ -68,7 +68,6 @@ class RenderManager(object):
self.theme_level = u''
self.override_background = None
self.theme_data = None
self.alertTab = None
self.force_page = False
def update_display(self):

View File

@ -28,11 +28,13 @@ The :mod:`serviceitem` provides the service item functionality including the
type and capability of an item.
"""
import datetime
import logging
import os
import uuid
from openlp.core.lib import build_icon, clean_tags, expand_tags
from openlp.core.lib.ui import UiStrings
log = logging.getLogger(__name__)
@ -60,6 +62,7 @@ class ItemCapabilities(object):
AddIfNewItem = 9
ProvidesOwnDisplay = 10
AllowsDetailedTitleDisplay = 11
AllowsVarableStartTime = 12
class ServiceItem(object):
@ -105,6 +108,8 @@ class ServiceItem(object):
self.data_string = u''
self.edit_id = None
self.xml_version = None
self.start_time = 0
self.media_length = 0
self._new_item()
def _new_item(self):
@ -257,7 +262,9 @@ class ServiceItem(object):
u'capabilities': self.capabilities,
u'search': self.search_string,
u'data': self.data_string,
u'xml_version': self.xml_version
u'xml_version': self.xml_version,
u'start_time': self.start_time,
u'media_length': self.media_length
}
service_data = []
if self.service_item_type == ServiceItemType.Text:
@ -301,6 +308,10 @@ class ServiceItem(object):
self.data_string = header[u'data']
if u'xml_version' in header:
self.xml_version = header[u'xml_version']
if u'start_time' in header:
self.start_time = header[u'start_time']
if u'media_length' in header:
self.media_length = header[u'media_length']
if self.service_item_type == ServiceItemType.Text:
for slide in serviceitem[u'serviceitem'][u'data']:
self._raw_frames.append(slide)
@ -420,3 +431,25 @@ class ServiceItem(object):
return self._raw_frames[row][u'path']
except IndexError:
return u''
def get_media_time(self):
"""
Returns the start and finish time for a media item
"""
tooltip = None
start = None
end = None
if self.start_time != 0:
start = UiStrings.StartTimeCode % \
unicode(datetime.timedelta(seconds=self.start_time))
if self.media_length != 0:
end = UiStrings.LengthTime % \
unicode(datetime.timedelta(seconds=self.media_length))
if not start and not end:
return None
elif start and not end:
return start
elif not start and end:
return end
else:
return u'%s : %s' % (start, end)

View File

@ -164,13 +164,27 @@ class BackgroundGradientType(object):
elif type_string == u'leftBottom':
return BackgroundGradientType.LeftBottom
class HorizontalType(object):
"""
Type enumeration for horizontal alignment.
"""
Left = 0
Center = 1
Right = 2
Center = 2
Right = 1
@staticmethod
def to_string(horizontal_type):
"""
Return a string representation of a horizontal type.
"""
if horizontal_type == Horizontal.Right:
return u'right'
elif horizontal_type == Horizontal.Center:
return u'center'
else:
return u'left'
class VerticalType(object):
"""
@ -180,6 +194,19 @@ class VerticalType(object):
Middle = 1
Bottom = 2
@staticmethod
def to_string(vertical_type):
"""
Return a string representation of a vertical type.
"""
if vertical_type == VerticalType.Bottom:
return u'bottom'
elif vertical_type == VerticalType.Middle:
return u'middle'
else:
return u'top'
BOOLEAN_LIST = [u'bold', u'italics', u'override', u'outline', u'shadow',
u'slide_transition']

View File

@ -41,36 +41,32 @@ class UiStrings(object):
# These strings should need a good reason to be retranslated elsewhere.
# Should some/more/less of these have an & attached?
Add = translate('OpenLP.Ui', '&Add')
AddANew = unicode(translate('OpenLP.Ui', 'Add a new %s'))
AddSelectService = unicode(translate('OpenLP.Ui',
'Add the selected %s to the service'))
Advanced = translate('OpenLP.Ui', 'Advanced')
AllFiles = translate('OpenLP.Ui', 'All Files')
Authors = translate('OpenLP.Ui', 'Authors')
CreateService = translate('OpenLP.Ui', 'Create a new service.')
Delete = translate('OpenLP.Ui', '&Delete')
DeleteSelect = unicode(translate('OpenLP.Ui', 'Delete the selected %s'))
DeleteType = unicode(translate('OpenLP.Ui', 'Delete %s'))
Edit = translate('OpenLP.Ui', '&Edit')
EditSelect = unicode(translate('OpenLP.Ui', 'Edit the selected %s'))
EditType = unicode(translate('OpenLP.Ui', 'Edit %s'))
Error = translate('OpenLP.Ui', 'Error')
ExportType = unicode(translate('OpenLP.Ui', 'Export %s'))
Import = translate('OpenLP.Ui', 'Import')
ImportType = unicode(translate('OpenLP.Ui', 'Import %s'))
LengthTime = unicode(translate('OpenLP.Ui', 'Length %s'))
Live = translate('OpenLP.Ui', 'Live')
Load = translate('OpenLP.Ui', 'Load')
LoadANew = unicode(translate('OpenLP.Ui', 'Load a new %s'))
New = translate('OpenLP.Ui', 'New')
NewType = unicode(translate('OpenLP.Ui', 'New %s'))
NewService = translate('OpenLP.Ui', 'New Service')
OLPV2 = translate('OpenLP.Ui', 'OpenLP 2.0')
OpenService = translate('OpenLP.Ui', 'Open Service')
Preview = translate('OpenLP.Ui', 'Preview')
PreviewSelect = unicode(translate('OpenLP.Ui', 'Preview the selected %s'))
SendSelectLive = unicode(translate('OpenLP.Ui',
'Send the selected %s live'))
ReplaceBG = translate('OpenLP.Ui', 'Replace Background')
ReplaceLiveBG = translate('OpenLP.Ui', 'Replace Live Background')
ResetBG = translate('OpenLP.Ui', 'Reset Background')
ResetLiveBG = translate('OpenLP.Ui', 'Reset Live Background')
SaveService = translate('OpenLP.Ui', 'Save Service')
Service = translate('OpenLP.Ui', 'Service')
StartTimeCode = unicode(translate('OpenLP.Ui', 'Start %s'))
Theme = translate('OpenLP.Ui', 'Theme')
Themes = translate('OpenLP.Ui', 'Themes')
def add_welcome_page(parent, image):
"""
Generate an opening welcome page for a wizard using a provided image.
@ -98,18 +94,25 @@ def add_welcome_page(parent, image):
parent.welcomeLayout.addStretch()
parent.addPage(parent.welcomePage)
def create_save_cancel_button_box(parent):
def create_accept_reject_button_box(parent, okay=False):
"""
Creates a standard dialog button box with save and cancel buttons. The
button box is connected to the parent's ``accept()`` and ``reject()``
Creates a standard dialog button box with two buttons. The buttons default
to save and cancel but the ``okay`` parameter can be used to make the
buttons okay and cancel instead.
The button box is connected to the parent's ``accept()`` and ``reject()``
methods to handle the default ``accepted()`` and ``rejected()`` signals.
``parent``
The parent object. This should be a ``QWidget`` descendant.
``okay``
If true creates an okay/cancel combination instead of save/cancel.
"""
button_box = QtGui.QDialogButtonBox(parent)
button_box.setStandardButtons(
QtGui.QDialogButtonBox.Save | QtGui.QDialogButtonBox.Cancel)
accept_button = QtGui.QDialogButtonBox.Save
if okay:
accept_button = QtGui.QDialogButtonBox.Ok
button_box.setStandardButtons(accept_button | QtGui.QDialogButtonBox.Cancel)
button_box.setObjectName(u'%sButtonBox' % parent)
QtCore.QObject.connect(button_box, QtCore.SIGNAL(u'accepted()'),
parent.accept)

View File

@ -28,7 +28,7 @@ The :mod:`ui` module provides the core user interface for OpenLP
"""
from PyQt4 import QtGui
from openlp.core.lib import translate, Receiver
from openlp.core.lib import translate
class HideMode(object):
"""
@ -53,6 +53,7 @@ class HideMode(object):
from themeform import ThemeForm
from filerenameform import FileRenameForm
from starttimeform import StartTimeForm
from maindisplay import MainDisplay
from servicenoteform import ServiceNoteForm
from serviceitemeditform import ServiceItemEditForm

View File

@ -164,9 +164,10 @@ class Ui_AboutDialog(object):
self.licenseTextEdit.setPlainText(translate('OpenLP.AboutForm',
'Copyright \xa9 2004-2011 Raoul Snyman\n'
'Portions copyright \xa9 2004-2011 '
'Tim Bentley, Jonathan Corwin, Michael Gorven, Scott Guerrieri, '
'Christian Richter, Maikel Stuivenberg, Martin Thompson, Jon '
'Tibble, Carsten Tinggaard\n'
'Tim Bentley, Jonathan Corwin, Michael Gorven, Scott Guerrieri,\n'
'Meinert Jordan, Andreas Preikschat, Christian Richter, Philip\n'
'Ridout, Maikel Stuivenberg, Martin Thompson, Jon Tibble, Carstenn'
'Tinggaard, Frode Woldsund\n'
'\n'
'This program is free software; you can redistribute it and/or '
'modify it under the terms of the GNU General Public License as '

View File

@ -29,6 +29,7 @@ The :mod:`advancedtab` provides an advanced settings facility.
from PyQt4 import QtCore, QtGui
from openlp.core.lib import SettingsTab, translate
from openlp.core.lib.ui import UiStrings
class AdvancedTab(SettingsTab):
"""
@ -112,7 +113,7 @@ class AdvancedTab(SettingsTab):
"""
Setup the interface translation strings.
"""
self.tabTitleVisible = translate('OpenLP.AdvancedTab', 'Advanced')
self.tabTitleVisible = UiStrings.Advanced
self.uiGroupBox.setTitle(translate('OpenLP.AdvancedTab', 'UI Settings'))
self.recentLabel.setText(
translate('OpenLP.AdvancedTab',

View File

@ -56,6 +56,7 @@ except ImportError:
from openlp.core.lib import translate, SettingsManager
from openlp.core.lib.mailto import mailto
from openlp.core.lib.ui import UiStrings
from exceptiondialog import Ui_ExceptionDialog
@ -176,8 +177,7 @@ class ExceptionForm(QtGui.QDialog, Ui_ExceptionDialog):
self,translate('ImagePlugin.ExceptionDialog',
'Select Attachment'),
SettingsManager.get_last_dir(u'exceptions'),
u'%s (*.*) (*)' %
unicode(translate('ImagePlugin.MediaItem', 'All Files')))
u'%s (*.*) (*)' % UiStrings.AllFiles)
log.info(u'New files(s) %s', unicode(files))
if files:
self.fileAttachment = unicode(files)

View File

@ -27,30 +27,28 @@
from PyQt4 import QtCore, QtGui
from openlp.core.lib import translate
from openlp.core.lib.ui import create_accept_reject_button_box
class Ui_FileRenameDialog(object):
def setupUi(self, FileRenameDialog):
FileRenameDialog.setObjectName(u'FileRenameDialog')
FileRenameDialog.resize(300, 10)
self.dialogLayout = QtGui.QGridLayout(FileRenameDialog)
def setupUi(self, fileRenameDialog):
fileRenameDialog.setObjectName(u'fileRenameDialog')
fileRenameDialog.resize(300, 10)
self.dialogLayout = QtGui.QGridLayout(fileRenameDialog)
self.dialogLayout.setObjectName(u'dialogLayout')
self.fileNameLabel = QtGui.QLabel(FileRenameDialog)
self.fileNameLabel = QtGui.QLabel(fileRenameDialog)
self.fileNameLabel.setObjectName(u'fileNameLabel')
self.dialogLayout.addWidget(self.fileNameLabel, 0, 0)
self.fileNameEdit = QtGui.QLineEdit(FileRenameDialog)
self.fileNameEdit = QtGui.QLineEdit(fileRenameDialog)
self.fileNameEdit.setValidator(QtGui.QRegExpValidator(
QtCore.QRegExp(r'[^/\\?*|<>\[\]":<>+%]+'), self))
self.fileNameEdit.setObjectName(u'fileNameEdit')
self.dialogLayout.addWidget(self.fileNameEdit, 0, 1)
self.buttonBox = QtGui.QDialogButtonBox(FileRenameDialog)
self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Cancel |
QtGui.QDialogButtonBox.Ok)
self.buttonBox.setObjectName(u'buttonBox')
self.buttonBox = create_accept_reject_button_box(fileRenameDialog, True)
self.dialogLayout.addWidget(self.buttonBox, 1, 0, 1, 2)
self.retranslateUi(FileRenameDialog)
self.retranslateUi(fileRenameDialog)
self.setMaximumHeight(self.sizeHint().height())
QtCore.QMetaObject.connectSlotsByName(FileRenameDialog)
QtCore.QMetaObject.connectSlotsByName(fileRenameDialog)
def retranslateUi(self, FileRenameDialog):
def retranslateUi(self, fileRenameDialog):
self.fileNameLabel.setText(translate('OpenLP.FileRenameForm',
'New File Name:'))

View File

@ -24,7 +24,7 @@
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
from PyQt4 import QtCore, QtGui
from PyQt4 import QtGui
from filerenamedialog import Ui_FileRenameDialog
@ -37,10 +37,6 @@ class FileRenameForm(QtGui.QDialog, Ui_FileRenameDialog):
def __init__(self, parent):
QtGui.QDialog.__init__(self, parent)
self.setupUi(self)
QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(u'accepted()'),
self.accept)
QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(u'rejected()'),
self.reject)
def exec_(self, copy=False):
"""

View File

@ -106,6 +106,9 @@ class MainDisplay(DisplayWidget):
self.audio = Phonon.AudioOutput(Phonon.VideoCategory, self.mediaObject)
Phonon.createPath(self.mediaObject, self.videoWidget)
Phonon.createPath(self.mediaObject, self.audio)
QtCore.QObject.connect(self.mediaObject,
QtCore.SIGNAL(u'stateChanged(Phonon::State, Phonon::State)'),
self.videoStart)
self.webView = QtWebKit.QWebView(self)
self.webView.setGeometry(0, 0,
self.screen[u'size'].width(), self.screen[u'size'].height())
@ -145,7 +148,7 @@ class MainDisplay(DisplayWidget):
serviceItem = ServiceItem()
serviceItem.bg_image_bytes = image_to_byte(initialFrame)
self.webView.setHtml(build_html(serviceItem, self.screen,
self.parent.alertTab, self.isLive, None))
self.alertTab, self.isLive, None))
self.initialFrame = True
# To display or not to display?
if not self.screen[u'primary']:
@ -341,6 +344,13 @@ class MainDisplay(DisplayWidget):
Receiver.send_message(u'maindisplay_active')
return self.preview()
def videoStart(self, newState, oldState):
"""
Start the video at a predetermined point.
"""
if newState == Phonon.PlayingState:
self.mediaObject.seek(self.serviceItem.start_time * 1000)
def isWebLoaded(self):
"""
Called by webView event to show display is fully loaded
@ -406,7 +416,7 @@ class MainDisplay(DisplayWidget):
if self.serviceItem.themedata.background_filename:
self.serviceItem.bg_image_bytes = self.imageManager. \
get_image_bytes(self.serviceItem.themedata.theme_name)
html = build_html(self.serviceItem, self.screen, self.parent.alertTab,
html = build_html(self.serviceItem, self.screen, self.alertTab,
self.isLive, background)
log.debug(u'buildHtml - pre setHtml')
self.webView.setHtml(html)

View File

@ -216,6 +216,9 @@ class Ui_MainWindow(object):
self.ToolsAddToolItem = icon_action(mainWindow, u'ToolsAddToolItem',
u':/tools/tools_add.png')
mainWindow.actionList.add_action(self.ToolsAddToolItem, u'Tools')
self.ToolsOpenDataFolder = icon_action(mainWindow,
u'ToolsOpenDataFolder', u':/general/general_open.png')
mainWindow.actionList.add_action(self.ToolsOpenDataFolder, u'Tools')
self.settingsPluginListItem = icon_action(mainWindow,
u'settingsPluginListItem', u':/system/settings_plugin_list.png')
mainWindow.actionList.add_action(self.settingsPluginListItem,
@ -276,6 +279,7 @@ class Ui_MainWindow(object):
self.SettingsLanguageMenu.menuAction(), None,
self.SettingsShortcutsItem, self.SettingsConfigureItem))
add_actions(self.ToolsMenu, (self.ToolsAddToolItem, None))
add_actions(self.ToolsMenu, (self.ToolsOpenDataFolder, None))
add_actions(self.HelpMenu, (self.HelpDocumentationItem,
self.HelpOnlineHelpItem, None, self.HelpWebSiteItem,
self.HelpAboutItem))
@ -315,20 +319,16 @@ class Ui_MainWindow(object):
self.themeManagerDock.setWindowTitle(
translate('OpenLP.MainWindow', 'Theme Manager'))
self.FileNewItem.setText(translate('OpenLP.MainWindow', '&New'))
self.FileNewItem.setToolTip(
translate('OpenLP.MainWindow', 'New Service'))
self.FileNewItem.setStatusTip(
translate('OpenLP.MainWindow', 'Create a new service.'))
self.FileNewItem.setToolTip(UiStrings.NewService)
self.FileNewItem.setStatusTip(UiStrings.CreateService)
self.FileNewItem.setShortcut(translate('OpenLP.MainWindow', 'Ctrl+N'))
self.FileOpenItem.setText(translate('OpenLP.MainWindow', '&Open'))
self.FileOpenItem.setToolTip(
translate('OpenLP.MainWindow', 'Open Service'))
self.FileOpenItem.setToolTip(UiStrings.OpenService)
self.FileOpenItem.setStatusTip(
translate('OpenLP.MainWindow', 'Open an existing service.'))
self.FileOpenItem.setShortcut(translate('OpenLP.MainWindow', 'Ctrl+O'))
self.FileSaveItem.setText(translate('OpenLP.MainWindow', '&Save'))
self.FileSaveItem.setToolTip(
translate('OpenLP.MainWindow', 'Save Service'))
self.FileSaveItem.setToolTip(UiStrings.SaveService)
self.FileSaveItem.setStatusTip(
translate('OpenLP.MainWindow', 'Save the current service to disk.'))
self.FileSaveItem.setShortcut(translate('OpenLP.MainWindow', 'Ctrl+S'))
@ -433,6 +433,10 @@ class Ui_MainWindow(object):
translate('OpenLP.MainWindow', 'Add &Tool...'))
self.ToolsAddToolItem.setStatusTip(translate('OpenLP.MainWindow',
'Add an application to the list of tools.'))
self.ToolsOpenDataFolder.setText(
translate('OpenLP.MainWindow', 'Open &Data Folder...'))
self.ToolsOpenDataFolder.setStatusTip(translate('OpenLP.MainWindow',
'Open the folder where songs, bibles and other data resides.'))
self.ModeDefaultItem.setText(
translate('OpenLP.MainWindow', '&Default'))
self.ModeDefaultItem.setStatusTip(translate('OpenLP.MainWindow',
@ -515,6 +519,8 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
QtCore.SIGNAL(u'triggered()'), self.onHelpWebSiteClicked)
QtCore.QObject.connect(self.HelpAboutItem,
QtCore.SIGNAL(u'triggered()'), self.onHelpAboutItemClicked)
QtCore.QObject.connect(self.ToolsOpenDataFolder,
QtCore.SIGNAL(u'triggered()'), self.onToolsOpenDataFolderClicked)
QtCore.QObject.connect(self.settingsPluginListItem,
QtCore.SIGNAL(u'triggered()'), self.onPluginItemClicked)
QtCore.QObject.connect(self.SettingsConfigureItem,
@ -703,6 +709,13 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
self.pluginForm.load()
self.pluginForm.exec_()
def onToolsOpenDataFolderClicked(self):
"""
Open data folder
"""
path = AppLocation.get_data_path()
QtGui.QDesktopServices.openUrl(QtCore.QUrl("file:///" + path))
def onSettingsConfigureItemClicked(self):
"""
Show the Settings dialog

View File

@ -24,7 +24,6 @@
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
import datetime
import mutagen
import os
from PyQt4 import QtCore, QtGui
@ -113,16 +112,9 @@ class PrintServiceOrderForm(QtGui.QDialog, Ui_PrintServiceOrderDialog):
item.notes.replace(u'\n', u'<br />'))
# Add play length of media files.
if item.is_media() and self.printMetaDataCheckBox.isChecked():
path = os.path.join(item.get_frames()[0][u'path'],
item.get_frames()[0][u'title'])
if not os.path.isfile(path):
continue
file = mutagen.File(path)
if file is not None:
length = int(file.info.length)
text += u'<p><b>%s</b> %s</p>' % (translate(
'OpenLP.ServiceManager', u'Playing time:'),
unicode(datetime.timedelta(seconds=length)))
unicode(datetime.timedelta(seconds=item.media_length)))
if self.customNoteEdit.toPlainText():
text += u'<h4>%s</h4>%s' % (translate('OpenLP.ServiceManager',
u'Custom Service Notes:'), self.customNoteEdit.toPlainText())

View File

@ -27,7 +27,7 @@
from PyQt4 import QtCore, QtGui
from openlp.core.lib import translate
from openlp.core.lib.ui import create_save_cancel_button_box, \
from openlp.core.lib.ui import create_accept_reject_button_box, \
create_delete_push_button, create_up_down_push_button_set
class Ui_ServiceItemEditDialog(object):
@ -50,7 +50,7 @@ class Ui_ServiceItemEditDialog(object):
self.buttonLayout.addWidget(self.downButton)
self.dialogLayout.addLayout(self.buttonLayout, 0, 1)
self.dialogLayout.addWidget(
create_save_cancel_button_box(serviceItemEditDialog), 1, 0, 1, 2)
create_accept_reject_button_box(serviceItemEditDialog), 1, 0, 1, 2)
self.retranslateUi(serviceItemEditDialog)
QtCore.QMetaObject.connectSlotsByName(serviceItemEditDialog)

View File

@ -110,11 +110,12 @@ class ServiceItemEditForm(QtGui.QDialog, Ui_ServiceItemEditDialog):
temp = self.itemList[row]
self.itemList.remove(self.itemList[row])
if direction == u'up':
self.itemList.insert(row - 1, temp)
row -= 1
else:
self.itemList.insert(row + 1, temp)
row += 1
self.itemList.insert(row, temp)
self.loadData()
self.listWidget.setCurrentRow(row + 1)
self.listWidget.setCurrentRow(row)
def onCurrentRowChanged(self, row):
"""

View File

@ -35,8 +35,8 @@ from PyQt4 import QtCore, QtGui
from openlp.core.lib import OpenLPToolbar, ServiceItem, context_menu_action, \
Receiver, build_icon, ItemCapabilities, SettingsManager, translate, \
ThemeLevel
from openlp.core.lib.ui import critical_error_message_box
from openlp.core.ui import ServiceNoteForm, ServiceItemEditForm
from openlp.core.lib.ui import UiStrings, critical_error_message_box
from openlp.core.ui import ServiceNoteForm, ServiceItemEditForm, StartTimeForm
from openlp.core.ui.printserviceorderform import PrintServiceOrderForm
from openlp.core.utils import AppLocation, delete_file, file_is_unicode, \
split_filename
@ -88,6 +88,7 @@ class ServiceManager(QtGui.QWidget):
self._fileName = u''
self.serviceNoteForm = ServiceNoteForm(self.mainwindow)
self.serviceItemEditForm = ServiceItemEditForm(self.mainwindow)
self.startTimeForm = StartTimeForm(self.mainwindow)
# start with the layout
self.layout = QtGui.QVBoxLayout(self)
self.layout.setSpacing(0)
@ -95,18 +96,14 @@ class ServiceManager(QtGui.QWidget):
# Create the top toolbar
self.toolbar = OpenLPToolbar(self)
self.toolbar.addToolbarButton(
translate('OpenLP.ServiceManager', 'New Service'),
u':/general/general_new.png',
translate('OpenLP.ServiceManager', 'Create a new service'),
self.onNewServiceClicked)
UiStrings.NewService, u':/general/general_new.png',
UiStrings.CreateService, self.onNewServiceClicked)
self.toolbar.addToolbarButton(
translate('OpenLP.ServiceManager', 'Open Service'),
u':/general/general_open.png',
UiStrings.OpenService, u':/general/general_open.png',
translate('OpenLP.ServiceManager', 'Load an existing service'),
self.onLoadServiceClicked)
self.toolbar.addToolbarButton(
translate('OpenLP.ServiceManager', 'Save Service'),
u':/general/general_save.png',
UiStrings.SaveService, u':/general/general_save.png',
translate('OpenLP.ServiceManager', 'Save this service'),
self.saveFile)
self.toolbar.addSeparator()
@ -270,16 +267,19 @@ class ServiceManager(QtGui.QWidget):
self.notesAction = self.menu.addAction(
translate('OpenLP.ServiceManager', '&Notes'))
self.notesAction.setIcon(build_icon(u':/services/service_notes.png'))
self.timeAction = self.menu.addAction(
translate('OpenLP.ServiceManager', '&Start Time'))
self.timeAction.setIcon(build_icon(u':/media/media_time.png'))
self.deleteAction = self.menu.addAction(
translate('OpenLP.ServiceManager', '&Delete From Service'))
self.deleteAction.setIcon(build_icon(u':/general/general_delete.png'))
self.sep1 = self.menu.addAction(u'')
self.sep1.setSeparator(True)
self.previewAction = self.menu.addAction(
translate('OpenLP.ServiceManager', '&Preview Verse'))
translate('OpenLP.ServiceManager', 'Show &Preview'))
self.previewAction.setIcon(build_icon(u':/general/general_preview.png'))
self.liveAction = self.menu.addAction(
translate('OpenLP.ServiceManager', '&Live Verse'))
translate('OpenLP.ServiceManager', 'Show &Live'))
self.liveAction.setIcon(build_icon(u':/general/general_live.png'))
self.sep2 = self.menu.addAction(u'')
self.sep2.setSeparator(True)
@ -465,7 +465,7 @@ class ServiceManager(QtGui.QWidget):
save the file.
"""
fileName = unicode(QtGui.QFileDialog.getSaveFileName(self.mainwindow,
translate('OpenLP.ServiceManager', 'Save Service'),
UiStrings.SaveService,
SettingsManager.get_last_dir(
self.mainwindow.serviceSettingsSection),
translate('OpenLP.ServiceManager', 'OpenLP Service Files (*.osz)')))
@ -563,6 +563,7 @@ class ServiceManager(QtGui.QWidget):
self.editAction.setVisible(False)
self.maintainAction.setVisible(False)
self.notesAction.setVisible(False)
self.timeAction.setVisible(False)
if serviceItem[u'service_item'].is_capable(ItemCapabilities.AllowsEdit)\
and serviceItem[u'service_item'].edit_id:
self.editAction.setVisible(True)
@ -571,6 +572,9 @@ class ServiceManager(QtGui.QWidget):
self.maintainAction.setVisible(True)
if item.parent() is None:
self.notesAction.setVisible(True)
if serviceItem[u'service_item']\
.is_capable(ItemCapabilities.AllowsVarableStartTime):
self.timeAction.setVisible(True)
self.themeMenu.menuAction().setVisible(False)
if serviceItem[u'service_item'].is_text():
self.themeMenu.menuAction().setVisible(True)
@ -583,6 +587,8 @@ class ServiceManager(QtGui.QWidget):
self.onDeleteFromService()
if action == self.notesAction:
self.onServiceItemNoteForm()
if action == self.timeAction:
self.onStartTimeForm()
if action == self.previewAction:
self.makePreview()
if action == self.liveAction:
@ -597,6 +603,16 @@ class ServiceManager(QtGui.QWidget):
self.serviceNoteForm.textEdit.toPlainText()
self.repaintServiceList(item, -1)
def onStartTimeForm(self):
item = self.findServiceItem()[0]
self.startTimeForm.item = self.serviceItems[item]
if self.startTimeForm.exec_():
self.serviceItems[item][u'service_item'].start_time = \
self.startTimeForm.hourSpinBox.value() * 3600 + \
self.startTimeForm.minuteSpinBox.value() * 60 + \
self.startTimeForm.secondSpinBox.value()
self.repaintServiceList(item, -1)
def onServiceItemEditForm(self):
item = self.findServiceItem()[0]
self.serviceItemEditForm.setServiceItem(
@ -843,6 +859,11 @@ class ServiceManager(QtGui.QWidget):
text = frame[u'title'].replace(u'\n', u' ')
child.setText(0, text[:40])
child.setData(0, QtCore.Qt.UserRole, QtCore.QVariant(count))
if item[u'service_item'] \
.is_capable(ItemCapabilities.AllowsVarableStartTime):
tip = item[u'service_item'].get_media_time()
if tip:
child.setToolTip(0, tip)
if serviceItem == itemcount:
if item[u'expanded'] and serviceItemChild == count:
self.serviceManagerList.setCurrentItem(child)

View File

@ -27,7 +27,7 @@
from PyQt4 import QtCore, QtGui
from openlp.core.lib import translate
from openlp.core.lib.ui import create_save_cancel_button_box
from openlp.core.lib.ui import create_accept_reject_button_box
class ServiceNoteForm(QtGui.QDialog):
"""
@ -48,7 +48,7 @@ class ServiceNoteForm(QtGui.QDialog):
self.textEdit = QtGui.QTextEdit(self)
self.textEdit.setObjectName(u'textEdit')
self.dialogLayout.addWidget(self.textEdit)
self.dialogLayout.addWidget(create_save_cancel_button_box(self))
self.dialogLayout.addWidget(create_accept_reject_button_box(self))
QtCore.QMetaObject.connectSlotsByName(self)
def retranslateUi(self):

View File

@ -27,6 +27,7 @@
from PyQt4 import QtCore, QtGui
from openlp.core.lib import translate, build_icon
from openlp.core.lib.ui import create_accept_reject_button_box
class Ui_SettingsDialog(object):
def setupUi(self, settingsDialog):
@ -40,16 +41,9 @@ class Ui_SettingsDialog(object):
self.settingsTabWidget = QtGui.QTabWidget(settingsDialog)
self.settingsTabWidget.setObjectName(u'settingsTabWidget')
self.settingsLayout.addWidget(self.settingsTabWidget)
self.buttonBox = QtGui.QDialogButtonBox(settingsDialog)
self.buttonBox.setStandardButtons(
QtGui.QDialogButtonBox.Cancel | QtGui.QDialogButtonBox.Ok)
self.buttonBox.setObjectName(u'buttonBox')
self.buttonBox = create_accept_reject_button_box(settingsDialog, True)
self.settingsLayout.addWidget(self.buttonBox)
self.retranslateUi(settingsDialog)
QtCore.QObject.connect(self.buttonBox,
QtCore.SIGNAL(u'accepted()'), settingsDialog.accept)
QtCore.QObject.connect(self.buttonBox,
QtCore.SIGNAL(u'rejected()'), settingsDialog.reject)
QtCore.QMetaObject.connectSlotsByName(settingsDialog)
def retranslateUi(self, settingsDialog):

View File

@ -877,7 +877,7 @@ class SlideController(QtGui.QWidget):
using *Blank to Theme*.
"""
log.debug(u'updatePreview %s ' % self.screens.current[u'primary'])
if not self.screens.current[u'primary'] and \
if not self.screens.current[u'primary'] and self.serviceItem and \
self.serviceItem.is_capable(ItemCapabilities.ProvidesOwnDisplay):
# Grab now, but try again in a couple of seconds if slide change
# is slow

View File

@ -0,0 +1,70 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2011 Raoul Snyman #
# Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael #
# Gorven, Scott Guerrieri, Meinert Jordan, Andreas Preikschat, Christian #
# Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon Tibble, #
# Carsten Tinggaard, Frode Woldsund #
# --------------------------------------------------------------------------- #
# 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_accept_reject_button_box
class Ui_StartTimeDialog(object):
def setupUi(self, StartTimeDialog):
StartTimeDialog.setObjectName(u'StartTimeDialog')
StartTimeDialog.resize(300, 10)
self.dialogLayout = QtGui.QGridLayout(StartTimeDialog)
self.dialogLayout.setObjectName(u'dialogLayout')
self.hourLabel = QtGui.QLabel(StartTimeDialog)
self.hourLabel.setObjectName("hourLabel")
self.dialogLayout.addWidget(self.hourLabel, 0, 0, 1, 1)
self.hourSpinBox = QtGui.QSpinBox(StartTimeDialog)
self.hourSpinBox.setObjectName("hourSpinBox")
self.dialogLayout.addWidget(self.hourSpinBox, 0, 1, 1, 1)
self.minuteLabel = QtGui.QLabel(StartTimeDialog)
self.minuteLabel.setObjectName("minuteLabel")
self.dialogLayout.addWidget(self.minuteLabel, 1, 0, 1, 1)
self.minuteSpinBox = QtGui.QSpinBox(StartTimeDialog)
self.minuteSpinBox.setObjectName("minuteSpinBox")
self.dialogLayout.addWidget(self.minuteSpinBox, 1, 1, 1, 1)
self.secondLabel = QtGui.QLabel(StartTimeDialog)
self.secondLabel.setObjectName("secondLabel")
self.dialogLayout.addWidget(self.secondLabel, 2, 0, 1, 1)
self.secondSpinBox = QtGui.QSpinBox(StartTimeDialog)
self.secondSpinBox.setObjectName("secondSpinBox")
self.dialogLayout.addWidget(self.secondSpinBox, 2, 1, 1, 1)
self.buttonBox = create_accept_reject_button_box(StartTimeDialog, True)
self.dialogLayout.addWidget(self.buttonBox, 4, 0, 1, 2)
self.retranslateUi(StartTimeDialog)
self.setMaximumHeight(self.sizeHint().height())
QtCore.QMetaObject.connectSlotsByName(StartTimeDialog)
def retranslateUi(self, StartTimeDialog):
self.setWindowTitle(translate('OpenLP.StartTimeForm',
'Item Start Time'))
self.hourLabel.setText(translate('OpenLP.StartTimeForm', 'Hours:'))
self.hourSpinBox.setSuffix(translate('OpenLP.StartTimeForm', 'h'))
self.minuteSpinBox.setSuffix(translate('OpenLP.StartTimeForm', 'm'))
self.secondSpinBox.setSuffix(translate('OpenLP.StartTimeForm', 's'))
self.minuteLabel.setText(translate('OpenLP.StartTimeForm', 'Minutes:'))
self.secondLabel.setText(translate('OpenLP.StartTimeForm', 'Seconds:'))

View File

@ -0,0 +1,52 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2011 Raoul Snyman #
# Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael #
# Gorven, Scott Guerrieri, Meinert Jordan, Andreas Preikschat, Christian #
# Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon Tibble, #
# Carsten Tinggaard, Frode Woldsund #
# --------------------------------------------------------------------------- #
# 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 starttimedialog import Ui_StartTimeDialog
class StartTimeForm(QtGui.QDialog, Ui_StartTimeDialog):
"""
The exception dialog
"""
def __init__(self, parent):
QtGui.QDialog.__init__(self, parent)
self.setupUi(self)
def exec_(self):
"""
Run the Dialog with correct heading.
"""
seconds = self.item[u'service_item'].start_time
hours = seconds / 3600
seconds -= 3600 * hours
minutes = seconds / 60
seconds -= 60 * minutes
self.hourSpinBox.setValue(hours)
self.minuteSpinBox.setValue(minutes)
self.secondSpinBox.setValue(seconds)
return QtGui.QDialog.exec_(self)

View File

@ -483,7 +483,8 @@ class ThemeForm(QtGui.QWizard, Ui_ThemeWizard):
Background Image button pushed.
"""
images_filter = get_images_filter()
images_filter = '%s;;%s (*.*) (*)' % (images_filter, UiStrings.AllFiles)
images_filter = u'%s;;%s (*.*) (*)' % (
images_filter, UiStrings.AllFiles)
filename = QtGui.QFileDialog.getOpenFileName(self,
translate('OpenLP.ThemeForm', 'Select Image'), u'',
images_filter)

View File

@ -34,7 +34,8 @@ from PyQt4 import QtCore, QtGui
from openlp.core.lib import OpenLPToolbar, ThemeXML, get_text_file_string, \
build_icon, Receiver, SettingsManager, translate, check_item_selected, \
BackgroundType, BackgroundGradientType, check_directory_exists
BackgroundType, BackgroundGradientType, check_directory_exists, \
VerticalType
from openlp.core.lib.ui import UiStrings, critical_error_message_box
from openlp.core.theme import Theme
from openlp.core.ui import FileRenameForm, ThemeForm
@ -62,28 +63,28 @@ class ThemeManager(QtGui.QWidget):
self.layout.setObjectName(u'layout')
self.toolbar = OpenLPToolbar(self)
self.toolbar.addToolbarButton(
UiStrings.NewType % UiStrings.Theme,
translate('OpenLP.ThemeManager', 'New Theme'),
u':/themes/theme_new.png',
translate('OpenLP.ThemeManager', 'Create a new theme.'),
self.onAddTheme)
self.toolbar.addToolbarButton(
UiStrings.EditType % UiStrings.Theme,
translate('OpenLP.ThemeManager', 'Edit Theme'),
u':/themes/theme_edit.png',
translate('OpenLP.ThemeManager', 'Edit a theme.'),
self.onEditTheme)
self.deleteToolbarAction = self.toolbar.addToolbarButton(
UiStrings.DeleteType % UiStrings.Theme,
translate('OpenLP.ThemeManager', 'Delete Theme'),
u':/general/general_delete.png',
translate('OpenLP.ThemeManager', 'Delete a theme.'),
self.onDeleteTheme)
self.toolbar.addSeparator()
self.toolbar.addToolbarButton(
UiStrings.ImportType % UiStrings.Theme,
translate('OpenLP.ThemeManager', 'Import Theme'),
u':/general/general_import.png',
translate('OpenLP.ThemeManager', 'Import a theme.'),
self.onImportTheme)
self.toolbar.addToolbarButton(
UiStrings.ExportType % UiStrings.Theme,
translate('OpenLP.ThemeManager', 'Export Theme'),
u':/general/general_export.png',
translate('OpenLP.ThemeManager', 'Export a theme.'),
self.onExportTheme)
@ -405,8 +406,8 @@ class ThemeManager(QtGui.QWidget):
files = QtGui.QFileDialog.getOpenFileNames(self,
translate('OpenLP.ThemeManager', 'Select Theme Import File'),
SettingsManager.get_last_dir(self.settingsSection),
translate('OpenLP.ThemeManager', 'Theme v1 (*.theme);;'
'Theme v2 (*.otz);;All Files (*.*)'))
unicode(translate('OpenLP.ThemeManager', 'Theme v1 (*.theme);;'
'Theme v2 (*.otz);;%s (*.*)')) % UiStrings.AllFiles)
log.info(u'New Themes %s', unicode(files))
if files:
for file in files:
@ -762,11 +763,11 @@ class ThemeManager(QtGui.QWidget):
newtheme.font_main_outline = True
newtheme.font_main_outline_color = \
unicode(theme.OutlineColor.name())
vAlignCorrection = 0
vAlignCorrection = VerticalType.Top
if theme.VerticalAlign == 2:
vAlignCorrection = 1
vAlignCorrection = VerticalType.Middle
elif theme.VerticalAlign == 1:
vAlignCorrection = 2
vAlignCorrection = VerticalType.Bottom
newtheme.display_horizontal_align = theme.HorizontalAlign
newtheme.display_vertical_align = vAlignCorrection
return newtheme.extract_xml()

View File

@ -27,11 +27,12 @@
The :mod:``wizard`` module provides generic wizard tools for OpenLP.
"""
import logging
import os
from PyQt4 import QtCore, QtGui
from openlp.core.lib import build_icon, Receiver
from openlp.core.lib.ui import add_welcome_page
from openlp.core.lib import build_icon, Receiver, SettingsManager
from openlp.core.lib.ui import UiStrings, add_welcome_page
log = logging.getLogger(__name__)
@ -70,6 +71,12 @@ class OpenLPWizard(QtGui.QWizard):
self.retranslateUi()
QtCore.QMetaObject.connectSlotsByName(self)
def registerFields(self):
"""
Hook method for wizards to register any fields they need.
"""
pass
def addProgressPage(self):
"""
Add the progress page for the wizard. This page informs the user how
@ -146,3 +153,30 @@ class OpenLPWizard(QtGui.QWizard):
self.finishButton.setVisible(True)
self.cancelButton.setVisible(False)
Receiver.send_message(u'openlp_process_events')
def getFileName(self, title, editbox, filters=u''):
"""
Opens a QFileDialog and saves the filename to the given editbox.
``title``
The title of the dialog (unicode).
``editbox``
A editbox (QLineEdit).
``filters``
The file extension filters. It should contain the file description
as well as the file extension. For example::
u'OpenLP 2.0 Databases (*.sqlite)'
"""
if filters:
filters += u';;'
filters += u'%s (*)' % UiStrings.AllFiles
filename = QtGui.QFileDialog.getOpenFileName(self, title,
os.path.dirname(SettingsManager.get_last_dir(
self.plugin.settingsSection, 1)), filters)
if filename:
editbox.setText(filename)
SettingsManager.set_last_dir(self.plugin.settingsSection,
filename, 1)

View File

@ -165,6 +165,8 @@ def _get_os_dir_path(dir_type):
Return a path based on which OS and environment we are running in.
"""
if sys.platform == u'win32':
if dir_type == AppLocation.DataDir:
return os.path.join(os.getenv(u'APPDATA'), u'openlp', u'data')
return os.path.join(os.getenv(u'APPDATA'), u'openlp')
elif sys.platform == u'darwin':
if dir_type == AppLocation.DataDir:
@ -180,7 +182,8 @@ def _get_os_dir_path(dir_type):
return os.path.join(BaseDirectory.xdg_data_home, u'openlp')
elif dir_type == AppLocation.CacheDir:
return os.path.join(BaseDirectory.xdg_cache_home, u'openlp')
else:
if dir_type == AppLocation.DataDir:
return os.path.join(os.getenv(u'HOME'), u'.openlp', u'data')
return os.path.join(os.getenv(u'HOME'), u'.openlp')
def _get_frozen_path(frozen_option, non_frozen_option):
@ -189,7 +192,6 @@ def _get_frozen_path(frozen_option, non_frozen_option):
"""
if hasattr(sys, u'frozen') and sys.frozen == 1:
return frozen_option
else:
return non_frozen_option
def check_latest_version(current_version):

View File

@ -40,21 +40,14 @@ class AlertsPlugin(Plugin):
log.info(u'Alerts Plugin loaded')
def __init__(self, plugin_helpers):
Plugin.__init__(self, u'Alerts', u'1.9.4', plugin_helpers)
Plugin.__init__(self, u'Alerts', u'1.9.4', plugin_helpers,
settingsTabClass=AlertsTab)
self.weight = -3
self.icon = build_icon(u':/plugins/plugin_alerts.png')
self.alertsmanager = AlertsManager(self)
self.manager = Manager(u'alerts', init_schema)
self.visible_name = self.getString(StringContent.VisibleName)
self.alertForm = AlertForm(self)
def getSettingsTab(self):
"""
Return the settings tab for the Alerts plugin
"""
self.alertsTab = AlertsTab(self, self.visible_name[u'title'])
return self.alertsTab
def addToolsMenuItem(self, tools_menu):
"""
Give the alerts plugin the opportunity to add items to the
@ -81,7 +74,7 @@ class AlertsPlugin(Plugin):
log.info(u'Alerts Initialising')
Plugin.initialise(self)
self.toolsAlertItem.setVisible(True)
self.liveController.alertTab = self.alertsTab
self.liveController.alertTab = self.settings_tab
def finalise(self):
"""

View File

@ -84,7 +84,7 @@ class AlertsManager(QtCore.QObject):
if len(self.alertList) == 0:
return
text = self.alertList.pop(0)
alertTab = self.parent.alertsTab
alertTab = self.parent.settings_tab
self.parent.liveController.display.alert(text)
# Check to see if we have a timer running.
if self.timer_id == 0:

View File

@ -33,10 +33,8 @@ class AlertsTab(SettingsTab):
"""
AlertsTab is the alerts settings tab in the settings dialog.
"""
def __init__(self, parent, visible_title):
self.parent = parent
self.manager = parent.manager
SettingsTab.__init__(self, parent.name, visible_title)
def __init__(self, name, visible_title):
SettingsTab.__init__(self, name, visible_title)
def setupUi(self):
self.setObjectName(u'AlertsTab')

View File

@ -38,7 +38,8 @@ class BiblePlugin(Plugin):
log.info(u'Bible Plugin loaded')
def __init__(self, plugin_helpers):
Plugin.__init__(self, u'Bibles', u'1.9.4', plugin_helpers)
Plugin.__init__(self, u'Bibles', u'1.9.4', plugin_helpers,
BibleMediaItem, BiblesTab)
self.weight = -9
self.icon_path = u':/plugins/plugin_bibles.png'
self.icon = build_icon(self.icon_path)
@ -62,14 +63,6 @@ class BiblePlugin(Plugin):
self.importBibleItem.setVisible(False)
self.exportBibleItem.setVisible(False)
def getSettingsTab(self):
visible_name = self.getString(StringContent.VisibleName)
return BiblesTab(self.name, visible_name[u'title'])
def getMediaManagerItem(self):
# Create the BibleManagerItem object.
return BibleMediaItem(self, self, self.icon)
def addImportMenuItem(self, import_menu):
self.importBibleItem = QtGui.QAction(import_menu)
self.importBibleItem.setObjectName(u'importBibleItem')
@ -136,9 +129,15 @@ class BiblePlugin(Plugin):
u'title': translate('BiblesPlugin', 'Bibles', 'container title')
}
# Middle Header Bar
## Import Action ##
self.textStrings[StringContent.Import] = {
u'title': UiStrings.Import,
u'tooltip': translate('BiblesPlugin', 'Import a Bible')
tooltips = {
u'load': u'',
u'import': translate('BiblesPlugin', 'Import a Bible'),
u'new': translate('BiblesPlugin', 'Add a new Bible'),
u'edit': translate('BiblesPlugin', 'Edit the selected Bible'),
u'delete': translate('BiblesPlugin', 'Delete the selected Bible'),
u'preview': translate('BiblesPlugin', 'Preview the selected Bible'),
u'live': translate('BiblesPlugin', 'Send the selected Bible live'),
u'service': translate('BiblesPlugin',
'Add the selected Bible to the service')
}
Plugin.setPluginTextStrings(self)
self.setPluginUiTextStrings(tooltips)

View File

@ -33,9 +33,9 @@ import os.path
from PyQt4 import QtCore, QtGui
from openlp.core.lib import Receiver, SettingsManager, translate
from openlp.core.lib import Receiver, translate
from openlp.core.lib.db import delete_database
from openlp.core.lib.ui import UiStrings, critical_error_message_box
from openlp.core.lib.ui import critical_error_message_box
from openlp.core.ui.wizard import OpenLPWizard
from openlp.core.utils import AppLocation, string_is_unicode
from openlp.plugins.bibles.lib.manager import BibleFormat
@ -727,33 +727,6 @@ class BibleImportForm(OpenLPWizard):
if books_file:
books_file.close()
def getFileName(self, title, editbox, filters=u''):
"""
Opens a QFileDialog and saves the filename to the given editbox.
``title``
The title of the dialog (unicode).
``editbox``
A editbox (QLineEdit).
``filters``
The file extension filters. It should contain the file description
as well as the file extension. For example::
u'openlp.org 1.x bible (*.bible)'
"""
if filters:
filters += u';;'
filters += u'%s (*)' % UiStrings.AllFiles
filename = QtGui.QFileDialog.getOpenFileName(self, title,
os.path.dirname(SettingsManager.get_last_dir(
self.plugin.settingsSection, 1)), filters)
if filename:
editbox.setText(filename)
SettingsManager.set_last_dir(
self.plugin.settingsSection, filename, 1)
def preWizard(self):
"""
Prepare the UI for the import.

View File

@ -28,22 +28,22 @@ import logging
from PyQt4 import QtCore, QtGui
from openlp.core.lib import MediaManagerItem, Receiver, BaseListWithDnD, \
ItemCapabilities, translate
from openlp.core.lib.ui import add_widget_completer, media_item_combo_box, \
critical_error_message_box
from openlp.core.lib import MediaManagerItem, Receiver, ItemCapabilities, \
translate
from openlp.core.lib.searchedit import SearchEdit
from openlp.core.lib.ui import UiStrings, add_widget_completer, \
media_item_combo_box, critical_error_message_box
from openlp.plugins.bibles.forms import BibleImportForm
from openlp.plugins.bibles.lib import get_reference_match
log = logging.getLogger(__name__)
class BibleListView(BaseListWithDnD):
class BibleSearch(object):
"""
Custom list view descendant, required for drag and drop.
Enumeration class for the different search methods for the "quick search".
"""
def __init__(self, parent=None):
self.PluginName = u'Bibles'
BaseListWithDnD.__init__(self, parent)
Reference = 1
Text = 2
class BibleMediaItem(MediaManagerItem):
@ -54,7 +54,6 @@ class BibleMediaItem(MediaManagerItem):
def __init__(self, parent, plugin, icon):
self.IconPath = u'songs/song'
self.ListViewWithDnD_class = BibleListView
MediaManagerItem.__init__(self, parent, plugin, icon)
# Place to store the search results for both bibles.
self.search_results = {}
@ -93,18 +92,17 @@ class BibleMediaItem(MediaManagerItem):
u'quickSecondComboBox')
self.quickSecondLabel.setBuddy(self.quickSecondComboBox)
self.quickLayout.addRow(self.quickSecondLabel, self.quickSecondComboBox)
self.quickSearchTypeLabel = QtGui.QLabel(self.quickTab)
self.quickSearchTypeLabel.setObjectName(u'quickSearchTypeLabel')
self.quickSearchComboBox = media_item_combo_box(self.quickTab,
u'quickSearchComboBox')
self.quickSearchTypeLabel.setBuddy(self.quickSearchComboBox)
self.quickLayout.addRow(self.quickSearchTypeLabel,
self.quickSearchComboBox)
self.quickSearchLabel = QtGui.QLabel(self.quickTab)
self.quickSearchLabel.setObjectName(u'quickSearchLabel')
self.quickSearchEdit = QtGui.QLineEdit(self.quickTab)
self.quickSearchEdit = SearchEdit(self.quickTab)
self.quickSearchEdit.setObjectName(u'quickSearchEdit')
self.quickSearchLabel.setBuddy(self.quickSearchEdit)
self.quickSearchEdit.setSearchTypes([
(BibleSearch.Reference, u':/bibles/bibles_search_reference.png',
translate('BiblesPlugin.MediaItem', 'Scripture Reference')),
(BibleSearch.Text, u':/bibles/bibles_search_text.png',
translate('BiblesPlugin.MediaItem', 'Text Search'))
])
self.quickLayout.addRow(self.quickSearchLabel, self.quickSearchEdit)
self.quickClearLabel = QtGui.QLabel(self.quickTab)
self.quickClearLabel.setObjectName(u'quickClearLabel')
@ -192,8 +190,7 @@ class BibleMediaItem(MediaManagerItem):
self.advancedSearchButtonLayout.addWidget(self.advancedSearchButton)
self.advancedLayout.addLayout(
self.advancedSearchButtonLayout, 7, 0, 1, 3)
self.searchTabWidget.addTab(self.advancedTab,
translate('BiblesPlugin.MediaItem', 'Advanced'))
self.searchTabWidget.addTab(self.advancedTab, UiStrings.Advanced)
# Add the search tab widget to the page layout.
self.pageLayout.addWidget(self.searchTabWidget)
# Combo Boxes
@ -207,8 +204,8 @@ class BibleMediaItem(MediaManagerItem):
QtCore.SIGNAL(u'activated(int)'), self.onAdvancedFromVerse)
QtCore.QObject.connect(self.advancedToChapter,
QtCore.SIGNAL(u'activated(int)'), self.onAdvancedToChapter)
QtCore.QObject.connect(self.quickSearchComboBox,
QtCore.SIGNAL(u'activated(int)'), self.updateAutoCompleter)
QtCore.QObject.connect(self.quickSearchEdit,
QtCore.SIGNAL(u'searchTypeChanged(int)'), self.updateAutoCompleter)
QtCore.QObject.connect(self.quickVersionComboBox,
QtCore.SIGNAL(u'activated(int)'), self.updateAutoCompleter)
# Buttons
@ -242,8 +239,6 @@ class BibleMediaItem(MediaManagerItem):
translate('BiblesPlugin.MediaItem', 'Version:'))
self.quickSecondLabel.setText(
translate('BiblesPlugin.MediaItem', 'Second:'))
self.quickSearchTypeLabel.setText(
translate('BiblesPlugin.MediaItem', 'Search type:'))
self.quickSearchLabel.setText(
translate('BiblesPlugin.MediaItem', 'Find:'))
self.quickSearchButton.setText(
@ -268,10 +263,6 @@ class BibleMediaItem(MediaManagerItem):
translate('BiblesPlugin.MediaItem', 'Results:'))
self.advancedSearchButton.setText(
translate('BiblesPlugin.MediaItem', 'Search'))
self.quickSearchComboBox.addItem(
translate('BiblesPlugin.MediaItem', 'Verse Search'))
self.quickSearchComboBox.addItem(
translate('BiblesPlugin.MediaItem', 'Text Search'))
self.quickClearComboBox.addItem(
translate('BiblesPlugin.MediaItem', 'Clear'))
self.quickClearComboBox.addItem(
@ -369,11 +360,11 @@ class BibleMediaItem(MediaManagerItem):
"""
This updates the bible book completion list for the search field. The
completion depends on the bible. It is only updated when we are doing a
verse search, otherwise the auto completion list is removed.
reference search, otherwise the auto completion list is removed.
"""
books = []
# We have to do a 'Verse Search'.
if self.quickSearchComboBox.currentIndex() == 0:
# We have to do a 'Reference Search'.
if self.quickSearchEdit.currentSearchType() == BibleSearch.Reference:
bibles = self.parent.manager.get_bibles()
bible = unicode(self.quickVersionComboBox.currentText())
if bible:
@ -502,7 +493,7 @@ class BibleMediaItem(MediaManagerItem):
def onQuickSearchButton(self):
"""
Does a quick search and saves the search results. Quick search can
either be "Verse Search" or "Text Search".
either be "Reference Search" or "Text Search".
"""
log.debug(u'Quick Search Button pressed')
self.quickSearchButton.setEnabled(False)
@ -510,8 +501,8 @@ class BibleMediaItem(MediaManagerItem):
bible = unicode(self.quickVersionComboBox.currentText())
second_bible = unicode(self.quickSecondComboBox.currentText())
text = unicode(self.quickSearchEdit.text())
if self.quickSearchComboBox.currentIndex() == 0:
# We are doing a 'Verse Search'.
if self.quickSearchEdit.currentSearchType() == BibleSearch.Reference:
# We are doing a 'Reference Search'.
self.search_results = self.parent.manager.get_verses(bible, text)
if second_bible and self.search_results:
self.second_search_results = self.parent.manager.get_verses(

View File

@ -48,21 +48,14 @@ class CustomPlugin(Plugin):
log.info(u'Custom Plugin loaded')
def __init__(self, plugin_helpers):
Plugin.__init__(self, u'Custom', u'1.9.4', plugin_helpers)
Plugin.__init__(self, u'Custom', u'1.9.4', plugin_helpers,
CustomMediaItem, CustomTab)
self.weight = -5
self.manager = Manager(u'custom', init_schema)
self.edit_custom_form = EditCustomForm(self.manager)
self.icon_path = u':/plugins/plugin_custom.png'
self.icon = build_icon(self.icon_path)
def getSettingsTab(self):
visible_name = self.getString(StringContent.VisibleName)
return CustomTab(self.name, visible_name[u'title'])
def getMediaManagerItem(self):
# Create the ManagerItem object
return CustomMediaItem(self, self, self.icon)
def about(self):
about_text = translate('CustomPlugin', '<strong>Custom Plugin</strong>'
'<br />The custom plugin provides the ability to set up custom '
@ -113,13 +106,20 @@ class CustomPlugin(Plugin):
u'title': translate('CustomsPlugin', 'Custom', 'container title')
}
# Middle Header Bar
## Import Action ##
self.textStrings[StringContent.Import] = {
u'title': UiStrings.Import,
u'tooltip': translate('CustomsPlugin',
'Import a Custom')
tooltips = {
u'load': translate('CustomsPlugin', 'Load a new Custom'),
u'import': translate('CustomsPlugin', 'Import a Custom'),
u'new': translate('CustomsPlugin', 'Add a new Custom'),
u'edit': translate('CustomsPlugin', 'Edit the selected Custom'),
u'delete': translate('CustomsPlugin', 'Delete the selected Custom'),
u'preview': translate('CustomsPlugin',
'Preview the selected Custom'),
u'live': translate('CustomsPlugin',
'Send the selected Custom live'),
u'service': translate('CustomsPlugin',
'Add the selected Custom to the service')
}
Plugin.setPluginTextStrings(self)
self.setPluginUiTextStrings(tooltips)
def finalise(self):
"""

View File

@ -27,7 +27,7 @@
from PyQt4 import QtCore, QtGui
from openlp.core.lib import build_icon, translate
from openlp.core.lib.ui import UiStrings, create_save_cancel_button_box, \
from openlp.core.lib.ui import UiStrings, create_accept_reject_button_box, \
create_delete_push_button, create_up_down_push_button_set
class Ui_CustomEditDialog(object):
@ -94,7 +94,7 @@ class Ui_CustomEditDialog(object):
self.creditLabel.setBuddy(self.creditEdit)
self.bottomFormLayout.addRow(self.creditLabel, self.creditEdit)
self.dialogLayout.addLayout(self.bottomFormLayout)
self.buttonBox = create_save_cancel_button_box(customEditDialog)
self.buttonBox = create_accept_reject_button_box(customEditDialog)
self.previewButton = QtGui.QPushButton()
self.buttonBox.addButton(
self.previewButton, QtGui.QDialogButtonBox.ActionRole)

View File

@ -27,7 +27,7 @@
from PyQt4 import QtCore, QtGui
from openlp.core.lib import translate, SpellTextEdit
from openlp.core.lib.ui import create_save_cancel_button_box
from openlp.core.lib.ui import create_accept_reject_button_box
class Ui_CustomSlideEditDialog(object):
def setupUi(self, customSlideEditDialog):
@ -37,7 +37,7 @@ class Ui_CustomSlideEditDialog(object):
self.slideTextEdit = SpellTextEdit(self)
self.slideTextEdit.setObjectName(u'slideTextEdit')
self.dialogLayout.addWidget(self.slideTextEdit)
self.buttonBox = create_save_cancel_button_box(customSlideEditDialog)
self.buttonBox = create_accept_reject_button_box(customSlideEditDialog)
self.splitButton = QtGui.QPushButton(customSlideEditDialog)
self.splitButton.setObjectName(u'splitButton')
self.buttonBox.addButton(self.splitButton,

View File

@ -28,18 +28,13 @@ import logging
from PyQt4 import QtCore, QtGui
from openlp.core.lib import MediaManagerItem, BaseListWithDnD, \
Receiver, ItemCapabilities, translate, check_item_selected
from openlp.core.lib import MediaManagerItem, Receiver, ItemCapabilities, \
translate, check_item_selected
from openlp.plugins.custom.lib import CustomXMLParser
from openlp.plugins.custom.lib.db import CustomSlide
log = logging.getLogger(__name__)
class CustomListView(BaseListWithDnD):
def __init__(self, parent=None):
self.PluginName = u'Custom'
BaseListWithDnD.__init__(self, parent)
class CustomMediaItem(MediaManagerItem):
"""
This is the custom media manager item for Custom Slides.
@ -48,9 +43,6 @@ class CustomMediaItem(MediaManagerItem):
def __init__(self, parent, plugin, icon):
self.IconPath = u'custom/custom'
# this next is a class, not an instance of a class - it will
# be instanced by the base MediaManagerItem
self.ListViewWithDnD_class = CustomListView
MediaManagerItem.__init__(self, parent, self, icon)
self.singleServiceItem = False
# Holds information about whether the edit is remotly triggered and

View File

@ -27,7 +27,6 @@
import logging
from openlp.core.lib import Plugin, StringContent, build_icon, translate
from openlp.core.lib.ui import UiStrings
from openlp.plugins.images.lib import ImageMediaItem
log = logging.getLogger(__name__)
@ -36,15 +35,12 @@ class ImagePlugin(Plugin):
log.info(u'Image Plugin loaded')
def __init__(self, plugin_helpers):
Plugin.__init__(self, u'Images', u'1.9.4', plugin_helpers)
Plugin.__init__(self, u'Images', u'1.9.4', plugin_helpers,
ImageMediaItem)
self.weight = -7
self.icon_path = u':/plugins/plugin_images.png'
self.icon = build_icon(self.icon_path)
def getMediaManagerItem(self):
# Create the MediaManagerItem object.
return ImageMediaItem(self, self, self.icon)
def about(self):
about_text = translate('ImagePlugin', '<strong>Image Plugin</strong>'
'<br />The image plugin provides displaying of images.<br />One '
@ -73,4 +69,15 @@ class ImagePlugin(Plugin):
u'title': translate('ImagePlugin', 'Images', 'container title')
}
# Middle Header Bar
Plugin.setPluginTextStrings(self)
tooltips = {
u'load': translate('ImagePlugin', 'Load a new Image'),
u'import': u'',
u'new': translate('ImagePlugin', 'Add a new Image'),
u'edit': translate('ImagePlugin', 'Edit the selected Image'),
u'delete': translate('ImagePlugin', 'Delete the selected Image'),
u'preview': translate('ImagePlugin', 'Preview the selected Image'),
u'live': translate('ImagePlugin', 'Send the selected Image live'),
u'service': translate('ImagePlugin',
'Add the selected Image to the service')
}
self.setPluginUiTextStrings(tooltips)

View File

@ -29,21 +29,14 @@ import os
from PyQt4 import QtCore, QtGui
from openlp.core.lib import MediaManagerItem, BaseListWithDnD, build_icon, \
ItemCapabilities, SettingsManager, translate, check_item_selected, \
check_directory_exists, Receiver
from openlp.core.lib import MediaManagerItem, build_icon, ItemCapabilities, \
SettingsManager, translate, check_item_selected, check_directory_exists, \
Receiver
from openlp.core.lib.ui import UiStrings, critical_error_message_box
from openlp.core.utils import AppLocation, delete_file, get_images_filter
log = logging.getLogger(__name__)
# We have to explicitly create separate classes for each plugin
# in order for DnD to the Service manager to work correctly.
class ImageListView(BaseListWithDnD):
def __init__(self, parent=None):
self.PluginName = u'Images'
BaseListWithDnD.__init__(self, parent)
class ImageMediaItem(MediaManagerItem):
"""
This is the custom media manager item for images.
@ -52,9 +45,6 @@ class ImageMediaItem(MediaManagerItem):
def __init__(self, parent, plugin, icon):
self.IconPath = u'images/image'
# This next is a class, not an instance of a class - it will
# be instanced by the base MediaManagerItem.
self.ListViewWithDnD_class = ImageListView
MediaManagerItem.__init__(self, parent, self, icon)
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'live_theme_changed'), self.liveThemeChanged)
@ -64,15 +54,11 @@ class ImageMediaItem(MediaManagerItem):
'Select Image(s)')
file_formats = get_images_filter()
self.OnNewFileMasks = u'%s;;%s (*.*) (*)' % (file_formats,
unicode(UiStrings.AllFiles))
self.replaceAction.setText(
translate('ImagePlugin.MediaItem', 'Replace Background'))
self.replaceAction.setToolTip(
translate('ImagePlugin.MediaItem', 'Replace Live Background'))
self.resetAction.setText(
translate('ImagePlugin.MediaItem', 'Reset Background'))
self.resetAction.setToolTip(
translate('ImagePlugin.MediaItem', 'Reset Live Background'))
UiStrings.AllFiles)
self.replaceAction.setText(UiStrings.ReplaceBG)
self.replaceAction.setToolTip(UiStrings.ReplaceLiveBG)
self.resetAction.setText(UiStrings.ResetBG)
self.resetAction.setToolTip(UiStrings.ResetLiveBG)
def requiredIcons(self):
MediaManagerItem.requiredIcons(self)

View File

@ -29,18 +29,13 @@ import os
from PyQt4 import QtCore, QtGui
from openlp.core.lib import MediaManagerItem, BaseListWithDnD, build_icon, \
ItemCapabilities, SettingsManager, translate, check_item_selected, Receiver
from openlp.core.lib.ui import critical_error_message_box
from openlp.core.lib import MediaManagerItem, build_icon, ItemCapabilities, \
SettingsManager, translate, check_item_selected, Receiver
from openlp.core.lib.ui import UiStrings, critical_error_message_box
from PyQt4.phonon import Phonon
log = logging.getLogger(__name__)
class MediaListView(BaseListWithDnD):
def __init__(self, parent=None):
self.PluginName = u'Media'
BaseListWithDnD.__init__(self, parent)
class MediaMediaItem(MediaManagerItem):
"""
This is the custom media manager item for Media Slides.
@ -50,30 +45,27 @@ class MediaMediaItem(MediaManagerItem):
def __init__(self, parent, plugin, icon):
self.IconPath = u'images/image'
self.background = False
# this next is a class, not an instance of a class - it will
# be instanced by the base MediaManagerItem
self.ListViewWithDnD_class = MediaListView
self.PreviewFunction = QtGui.QPixmap(
u':/media/media_video.png').toImage()
MediaManagerItem.__init__(self, parent, self, icon)
self.singleServiceItem = False
self.mediaObject = Phonon.MediaObject(self)
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'video_background_replaced'),
self.videobackgroundReplaced)
QtCore.QObject.connect(self.mediaObject,
QtCore.SIGNAL(u'stateChanged(Phonon::State, Phonon::State)'),
self.videoStart)
def retranslateUi(self):
self.OnNewPrompt = translate('MediaPlugin.MediaItem', 'Select Media')
self.OnNewFileMasks = unicode(translate('MediaPlugin.MediaItem',
'Videos (%s);;Audio (%s);;All files (*)')) % \
(self.parent.video_list, self.parent.audio_list)
self.replaceAction.setText(
translate('MediaPlugin.MediaItem', 'Replace Background'))
self.replaceAction.setToolTip(
translate('MediaPlugin.MediaItem', 'Replace Live Background'))
self.resetAction.setText(
translate('MediaPlugin.MediaItem', 'Reset Background'))
self.resetAction.setToolTip(
translate('ImagePlugin.MediaItem', 'Reset Live Background'))
'Videos (%s);;Audio (%s);;%s (*)')) % (self.parent.video_list,
self.parent.audio_list, UiStrings.AllFiles)
self.replaceAction.setText(UiStrings.ReplaceBG)
self.replaceAction.setToolTip(UiStrings.ReplaceLiveBG)
self.resetAction.setText(UiStrings.ResetBG)
self.resetAction.setToolTip(UiStrings.ResetLiveBG)
def requiredIcons(self):
MediaManagerItem.requiredIcons(self)
@ -133,13 +125,22 @@ class MediaMediaItem(MediaManagerItem):
return False
filename = unicode(item.data(QtCore.Qt.UserRole).toString())
if os.path.exists(filename):
self.MediaState = None
self.mediaObject.stop()
self.mediaObject.clearQueue()
self.mediaObject.setCurrentSource(Phonon.MediaSource(filename))
self.mediaObject.play()
service_item.title = unicode(
translate('MediaPlugin.MediaItem', 'Media'))
service_item.add_capability(ItemCapabilities.RequiresMedia)
service_item.add_capability(ItemCapabilities.AllowsVarableStartTime)
# force a nonexistent theme
service_item.theme = -1
frame = u':/media/image_clapperboard.png'
(path, name) = os.path.split(filename)
while not self.MediaState:
Receiver.send_message(u'openlp_process_events')
service_item.media_length = self.mediaLength
service_item.add_from_command(path, name, frame)
return True
else:
@ -151,6 +152,7 @@ class MediaMediaItem(MediaManagerItem):
return False
def initialise(self):
self.listView.clear()
self.listView.setIconSize(QtCore.QSize(88, 50))
self.loadList(SettingsManager.load_list(self.settingsSection,
self.settingsSection))
@ -176,3 +178,12 @@ class MediaMediaItem(MediaManagerItem):
item_name.setIcon(build_icon(img))
item_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(file))
self.listView.addItem(item_name)
def videoStart(self, newState, oldState):
"""
Start the video at a predetermined point.
"""
if newState == Phonon.PlayingState:
self.MediaState = newState
self.mediaLength = self.mediaObject.totalTime()/1000
self.mediaObject.stop()

View File

@ -32,8 +32,8 @@ class MediaTab(SettingsTab):
"""
MediaTab is the Media settings tab in the settings dialog.
"""
def __init__(self, title):
SettingsTab.__init__(self, title)
def __init__(self, title, visible_title):
SettingsTab.__init__(self, title, visible_title)
def setupUi(self):
self.setObjectName(u'MediaTab')
@ -53,9 +53,8 @@ class MediaTab(SettingsTab):
self.onUsePhononCheckBoxChanged)
def retranslateUi(self):
self.tabTitleVisible = translate('MediaPlugin.MediaTab', 'Media')
self.mediaModeGroupBox.setTitle(translate('MediaPlugin.MediaTab',
'Media Display'))
self.mediaModeGroupBox.setTitle(
translate('MediaPlugin.MediaTab', 'Media Display'))
self.usePhononCheckBox.setText(
translate('MediaPlugin.MediaTab', 'Use Phonon for video playback'))

View File

@ -30,7 +30,6 @@ import mimetypes
from PyQt4.phonon import Phonon
from openlp.core.lib import Plugin, StringContent, build_icon, translate
from openlp.core.lib.ui import UiStrings
from openlp.plugins.media.lib import MediaMediaItem, MediaTab
log = logging.getLogger(__name__)
@ -39,7 +38,8 @@ class MediaPlugin(Plugin):
log.info(u'%s MediaPlugin loaded', __name__)
def __init__(self, plugin_helpers):
Plugin.__init__(self, u'Media', u'1.9.4', plugin_helpers)
Plugin.__init__(self, u'Media', u'1.9.4', plugin_helpers,
MediaMediaItem, MediaTab)
self.weight = -6
self.icon_path = u':/plugins/plugin_media.png'
self.icon = build_icon(self.icon_path)
@ -76,13 +76,6 @@ class MediaPlugin(Plugin):
mimetype = u''
return list, mimetype
def getSettingsTab(self):
return MediaTab(self.name)
def getMediaManagerItem(self):
# Create the MediaManagerItem object.
return MediaMediaItem(self, self, self.icon)
def about(self):
about_text = translate('MediaPlugin', '<strong>Media Plugin</strong>'
'<br />The media plugin provides playback of audio and video.')
@ -102,4 +95,15 @@ class MediaPlugin(Plugin):
u'title': translate('MediaPlugin', 'Media', 'container title')
}
# Middle Header Bar
Plugin.setPluginTextStrings(self)
tooltips = {
u'load': translate('MediaPlugin', 'Load a new Media'),
u'import': u'',
u'new': translate('MediaPlugin', 'Add a new Media'),
u'edit': translate('MediaPlugin', 'Edit the selected Media'),
u'delete': translate('MediaPlugin', 'Delete the selected Media'),
u'preview': translate('MediaPlugin', 'Preview the selected Media'),
u'live': translate('MediaPlugin', 'Send the selected Media live'),
u'service': translate('MediaPlugin',
'Add the selected Media to the service')
}
self.setPluginUiTextStrings(tooltips)

View File

@ -145,7 +145,12 @@ class ImpressController(PresentationController):
log.debug(u'get COM Desktop OpenOffice')
if not self.manager:
return None
return self.manager.createInstance(u'com.sun.star.frame.Desktop')
desktop = None
try:
desktop = self.manager.createInstance(u'com.sun.star.frame.Desktop')
except AttributeError:
log.exception(u'Failure to find desktop - Impress may have closed')
return desktop if desktop else None
def get_com_servicemanager(self):
"""
@ -166,13 +171,15 @@ class ImpressController(PresentationController):
log.debug(u'Kill OpenOffice')
while self.docs:
self.docs[0].close_presentation()
desktop = None
try:
if os.name != u'nt':
desktop = self.get_uno_desktop()
else:
desktop = self.get_com_desktop()
#Sometimes we get a failure and desktop is None
if not desktop:
except:
log.exception(u'Failed to find an OpenOffice desktop to terminate')
if not desktop:
return
docs = desktop.getComponents()
if docs.hasElements():

View File

@ -29,24 +29,13 @@ import os
from PyQt4 import QtCore, QtGui
from openlp.core.lib import MediaManagerItem, BaseListWithDnD, build_icon, \
SettingsManager, translate, check_item_selected, Receiver, ItemCapabilities
from openlp.core.lib import MediaManagerItem, build_icon, SettingsManager, \
translate, check_item_selected, Receiver, ItemCapabilities
from openlp.core.lib.ui import critical_error_message_box, media_item_combo_box
from openlp.plugins.presentations.lib import MessageListener
log = logging.getLogger(__name__)
class PresentationListView(BaseListWithDnD):
"""
Class for the list of Presentations
We have to explicitly create separate classes for each plugin
in order for DnD to the Service manager to work correctly.
"""
def __init__(self, parent=None):
self.PluginName = u'Presentations'
BaseListWithDnD.__init__(self, parent)
class PresentationMediaItem(MediaManagerItem):
"""
This is the Presentation media manager item for Presentation Items.
@ -61,9 +50,6 @@ class PresentationMediaItem(MediaManagerItem):
self.controllers = controllers
self.IconPath = u'presentations/presentation'
self.Automatic = u''
# this next is a class, not an instance of a class - it will
# be instanced by the base MediaManagerItem
self.ListViewWithDnD_class = PresentationListView
MediaManagerItem.__init__(self, parent, self, icon)
self.message_listener = MessageListener(self)
QtCore.QObject.connect(Receiver.get_receiver(),

View File

@ -27,6 +27,7 @@
from PyQt4 import QtCore, QtGui
from openlp.core.lib import Receiver, SettingsTab, translate
from openlp.core.lib.ui import UiStrings
class PresentationTab(SettingsTab):
"""
@ -85,9 +86,7 @@ class PresentationTab(SettingsTab):
checkbox.setText(
unicode(translate('PresentationPlugin.PresentationTab',
'%s (unvailable)')) % controller.name)
self.AdvancedGroupBox.setTitle(
translate('PresentationPlugin.PresentationTab',
'Advanced'))
self.AdvancedGroupBox.setTitle(UiStrings.Advanced)
self.OverrideAppCheckBox.setText(
translate('PresentationPlugin.PresentationTab',
'Allow presentation application to be overriden'))

View File

@ -31,7 +31,6 @@ import os
import logging
from openlp.core.lib import Plugin, StringContent, build_icon, translate
from openlp.core.lib.ui import UiStrings
from openlp.core.utils import AppLocation
from openlp.plugins.presentations.lib import PresentationController, \
PresentationMediaItem, PresentationTab
@ -168,4 +167,18 @@ class PresentationPlugin(Plugin):
'container title')
}
# Middle Header Bar
Plugin.setPluginTextStrings(self)
tooltips = {
u'load': translate('PresentationPlugin', 'Load a new Presentation'),
u'import': u'',
u'new': u'',
u'edit': u'',
u'delete': translate('PresentationPlugin',
'Delete the selected Presentation'),
u'preview': translate('PresentationPlugin',
'Preview the selected Presentation'),
u'live': translate('PresentationPlugin',
'Send the selected Presentation live'),
u'service': translate('PresentationPlugin',
'Add the selected Presentation to the service')
}
self.setPluginUiTextStrings(tooltips)

View File

@ -38,7 +38,8 @@ class RemotesPlugin(Plugin):
"""
remotes constructor
"""
Plugin.__init__(self, u'Remotes', u'1.9.4', plugin_helpers)
Plugin.__init__(self, u'Remotes', u'1.9.4', plugin_helpers,
settingsTabClass=RemoteTab)
self.icon = build_icon(u':/plugins/plugin_remote.png')
self.weight = -1
self.server = None
@ -61,13 +62,6 @@ class RemotesPlugin(Plugin):
if self.server:
self.server.close()
def getSettingsTab(self):
"""
Create the settings Tab
"""
visible_name = self.getString(StringContent.VisibleName)
return RemoteTab(self.name, visible_name[u'title'])
def about(self):
"""
Information about this plugin

View File

@ -58,3 +58,5 @@ from editverseform import EditVerseForm
from editsongform import EditSongForm
from songmaintenanceform import SongMaintenanceForm
from songimportform import SongImportForm
from songexportform import SongExportForm

View File

@ -27,7 +27,7 @@
from PyQt4 import QtCore, QtGui
from openlp.core.lib import translate
from openlp.core.lib.ui import create_save_cancel_button_box
from openlp.core.lib.ui import create_accept_reject_button_box
class Ui_AuthorsDialog(object):
def setupUi(self, authorsDialog):
@ -57,7 +57,7 @@ class Ui_AuthorsDialog(object):
self.authorLayout.addRow(self.displayLabel, self.displayEdit)
self.dialogLayout.addLayout(self.authorLayout)
self.dialogLayout.addWidget(
create_save_cancel_button_box(authorsDialog))
create_accept_reject_button_box(authorsDialog))
self.retranslateUi(authorsDialog)
authorsDialog.setMaximumHeight(authorsDialog.sizeHint().height())
QtCore.QMetaObject.connectSlotsByName(authorsDialog)

View File

@ -27,7 +27,7 @@
from PyQt4 import QtCore, QtGui
from openlp.core.lib import build_icon, translate
from openlp.core.lib.ui import UiStrings, create_save_cancel_button_box
from openlp.core.lib.ui import UiStrings, create_accept_reject_button_box
class Ui_EditSongDialog(object):
def setupUi(self, editSongDialog):
@ -241,7 +241,7 @@ class Ui_EditSongDialog(object):
self.themeTabLayout.addWidget(self.commentsGroupBox)
self.songTabWidget.addTab(self.themeTab, u'')
self.dialogLayout.addWidget(self.songTabWidget)
self.buttonBox = create_save_cancel_button_box(editSongDialog)
self.buttonBox = create_accept_reject_button_box(editSongDialog)
self.dialogLayout.addWidget(self.buttonBox)
self.retranslateUi(editSongDialog)
QtCore.QMetaObject.connectSlotsByName(editSongDialog)

View File

@ -27,7 +27,7 @@
from PyQt4 import QtCore, QtGui
from openlp.core.lib import build_icon, translate, SpellTextEdit
from openlp.core.lib.ui import create_save_cancel_button_box
from openlp.core.lib.ui import create_accept_reject_button_box
from openlp.plugins.songs.lib import VerseType
class Ui_EditVerseDialog(object):
@ -61,7 +61,7 @@ class Ui_EditVerseDialog(object):
self.verseTypeLayout.addStretch()
self.dialogLayout.addLayout(self.verseTypeLayout)
self.dialogLayout.addWidget(
create_save_cancel_button_box(editVerseDialog))
create_accept_reject_button_box(editVerseDialog))
self.retranslateUi(editVerseDialog)
QtCore.QMetaObject.connectSlotsByName(editVerseDialog)

View File

@ -27,7 +27,7 @@
from PyQt4 import QtCore, QtGui
from openlp.core.lib import translate
from openlp.core.lib.ui import create_save_cancel_button_box
from openlp.core.lib.ui import create_accept_reject_button_box
class Ui_SongBookDialog(object):
def setupUi(self, songBookDialog):
@ -51,7 +51,7 @@ class Ui_SongBookDialog(object):
self.bookLayout.addRow(self.publisherLabel, self.publisherEdit)
self.dialogLayout.addLayout(self.bookLayout)
self.dialogLayout.addWidget(
create_save_cancel_button_box(songBookDialog))
create_accept_reject_button_box(songBookDialog))
self.retranslateUi(songBookDialog)
songBookDialog.setMaximumHeight(songBookDialog.sizeHint().height())
QtCore.QMetaObject.connectSlotsByName(songBookDialog)

View File

@ -0,0 +1,367 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2011 Raoul Snyman #
# Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael #
# Gorven, Scott Guerrieri, Meinert Jordan, Andreas Preikschat, Christian #
# Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon Tibble, #
# Carsten Tinggaard, Frode Woldsund #
# --------------------------------------------------------------------------- #
# 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:`songexportform` module provides the wizard for exporting songs to the
OpenLyrics format.
"""
import logging
from PyQt4 import QtCore, QtGui
from openlp.core.lib import build_icon, Receiver, SettingsManager, translate
from openlp.core.lib.ui import critical_error_message_box
from openlp.core.ui.wizard import OpenLPWizard
from openlp.plugins.songs.lib.db import Song
from openlp.plugins.songs.lib.openlyricsexport import OpenLyricsExport
log = logging.getLogger(__name__)
class SongExportForm(OpenLPWizard):
"""
This is the Song Export Wizard, which allows easy exporting of Songs to the
OpenLyrics format.
"""
log.info(u'SongExportForm loaded')
def __init__(self, parent, plugin):
"""
Instantiate the wizard, and run any extra setup we need to.
``parent``
The QWidget-derived parent of the wizard.
``plugin``
The songs plugin.
"""
self.plugin = plugin
OpenLPWizard.__init__(self, parent, plugin, u'songExportWizard',
u':/wizards/wizard_exportsong.bmp')
self.stop_export_flag = False
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'openlp_stop_wizard'), self.stop_export)
def stop_export(self):
"""
Sets the flag for the exporter to stop the export.
"""
log.debug(u'Stopping songs export')
self.stop_export_flag = True
def setupUi(self, image):
"""
Set up the song wizard UI.
"""
OpenLPWizard.setupUi(self, image)
def customInit(self):
"""
Song wizard specific initialisation.
"""
pass
def customSignals(self):
"""
Song wizard specific signals.
"""
QtCore.QObject.connect(self.availableListWidget,
QtCore.SIGNAL(u'itemActivated(QListWidgetItem*)'),
self.onItemPressed)
QtCore.QObject.connect(self.searchLineEdit,
QtCore.SIGNAL(u'textEdited(const QString&)'),
self.onSearchLineEditChanged)
QtCore.QObject.connect(self.uncheckButton,
QtCore.SIGNAL(u'clicked()'), self.onUncheckButtonClicked)
QtCore.QObject.connect(self.checkButton,
QtCore.SIGNAL(u'clicked()'), self.onCheckButtonClicked)
QtCore.QObject.connect(self.directoryButton,
QtCore.SIGNAL(u'clicked()'), self.onDirectoryButtonClicked)
def addCustomPages(self):
"""
Add song wizard specific pages.
"""
# The page with all available songs.
self.availableSongsPage = QtGui.QWizardPage()
self.availableSongsPage.setObjectName(u'availableSongsPage')
self.availableSongsLayout = QtGui.QHBoxLayout(self.availableSongsPage)
self.availableSongsLayout.setObjectName(u'availableSongsLayout')
self.verticalLayout = QtGui.QVBoxLayout()
self.verticalLayout.setObjectName(u'verticalLayout')
self.availableListWidget = QtGui.QListWidget(self.availableSongsPage)
self.availableListWidget.setObjectName(u'availableListWidget')
self.verticalLayout.addWidget(self.availableListWidget)
self.horizontalLayout = QtGui.QHBoxLayout()
self.horizontalLayout.setObjectName(u'horizontalLayout')
self.searchLabel = QtGui.QLabel(self.availableSongsPage)
self.searchLabel.setObjectName(u'searchLabel')
self.horizontalLayout.addWidget(self.searchLabel)
self.searchLineEdit = QtGui.QLineEdit(self.availableSongsPage)
self.searchLineEdit.setObjectName(u'searchLineEdit')
self.horizontalLayout.addWidget(self.searchLineEdit)
spacerItem = QtGui.QSpacerItem(40, 20,
QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum)
self.horizontalLayout.addItem(spacerItem)
self.uncheckButton = QtGui.QPushButton(self.availableSongsPage)
self.uncheckButton.setObjectName(u'uncheckButton')
self.horizontalLayout.addWidget(self.uncheckButton)
self.checkButton = QtGui.QPushButton(self.availableSongsPage)
self.checkButton.setObjectName(u'selectButton')
self.horizontalLayout.addWidget(self.checkButton)
self.verticalLayout.addLayout(self.horizontalLayout)
self.availableSongsLayout.addLayout(self.verticalLayout)
self.addPage(self.availableSongsPage)
# The page with the selected songs.
self.exportSongPage = QtGui.QWizardPage()
self.exportSongPage.setObjectName(u'availableSongsPage')
self.exportSongLayout = QtGui.QHBoxLayout(self.exportSongPage)
self.exportSongLayout.setObjectName(u'exportSongLayout')
self.gridLayout = QtGui.QGridLayout()
self.gridLayout.setObjectName(u'gridLayout')
self.selectedListWidget = QtGui.QListWidget(self.exportSongPage)
self.selectedListWidget.setObjectName(u'selectedListWidget')
self.gridLayout.addWidget(self.selectedListWidget, 1, 0, 1, 1)
self.horizontalLayout = QtGui.QHBoxLayout()
self.horizontalLayout.setObjectName(u'horizontalLayout')
self.directoryLabel = QtGui.QLabel(self.exportSongPage)
self.directoryLabel.setObjectName(u'directoryLabel')
self.horizontalLayout.addWidget(self.directoryLabel)
self.directoryLineEdit = QtGui.QLineEdit(self.exportSongPage)
self.directoryLineEdit.setObjectName(u'directoryLineEdit')
self.horizontalLayout.addWidget(self.directoryLineEdit)
self.directoryButton = QtGui.QToolButton(self.exportSongPage)
self.directoryButton.setIcon(build_icon(u':/exports/export_load.png'))
self.directoryButton.setObjectName(u'directoryButton')
self.horizontalLayout.addWidget(self.directoryButton)
self.gridLayout.addLayout(self.horizontalLayout, 0, 0, 1, 1)
self.exportSongLayout.addLayout(self.gridLayout)
self.addPage(self.exportSongPage)
def retranslateUi(self):
"""
Song wizard localisation.
"""
self.setWindowTitle(
translate('SongsPlugin.ExportWizardForm', 'Song Export Wizard'))
self.titleLabel.setText(
u'<span style="font-size:14pt; font-weight:600;">%s</span>' %
translate('SongsPlugin.ExportWizardForm',
'Welcome to the Song Export Wizard'))
self.informationLabel.setText(
translate('SongsPlugin.ExportWizardForm', 'This wizard will help to'
' export your songs to the open and free OpenLyrics worship song '
'format.'))
self.availableSongsPage.setTitle(
translate('SongsPlugin.ExportWizardForm', 'Select Songs'))
self.availableSongsPage.setSubTitle(
translate('SongsPlugin.ExportWizardForm',
'Check the songs, you want to export.'))
self.searchLabel.setText(
translate('SongsPlugin.ExportWizardForm', 'Search:'))
self.uncheckButton.setText(
translate('SongsPlugin.ExportWizardForm', 'Uncheck All'))
self.checkButton.setText(
translate('SongsPlugin.ExportWizardForm', 'Check All'))
self.exportSongPage.setTitle(
translate('SongsPlugin.ExportWizardForm', 'Select Directory'))
self.exportSongPage.setSubTitle(
translate('SongsPlugin.ExportWizardForm',
'Select the directory you want the songs to be saved.'))
self.directoryLabel.setText(
translate('SongsPlugin.ExportWizardForm', 'Directory:'))
self.progressPage.setTitle(
translate('SongsPlugin.ExportWizardForm', 'Exporting'))
self.progressPage.setSubTitle(
translate('SongsPlugin.ExportWizardForm',
'Please wait while your songs are exported.'))
self.progressLabel.setText(
translate('SongsPlugin.ExportWizardForm', 'Ready.'))
self.progressBar.setFormat(
translate('SongsPlugin.ExportWizardForm', '%p%'))
def validateCurrentPage(self):
"""
Validate the current page before moving on to the next page.
"""
if self.currentPage() == self.welcomePage:
return True
elif self.currentPage() == self.availableSongsPage:
items = [
item for item in self._findListWidgetItems(
self.availableListWidget) if item.checkState()
]
if not items:
critical_error_message_box(
translate('SongsPlugin.ExportWizardForm',
'No Song Selected'),
translate('SongsPlugin.ExportWizardForm',
'You need to add at least one Song to export.'))
return False
self.selectedListWidget.clear()
# Add the songs to the list of selected songs.
for item in items:
song = QtGui.QListWidgetItem(item.text())
song.setData(QtCore.Qt.UserRole,
QtCore.QVariant(item.data(QtCore.Qt.UserRole).toPyObject()))
song.setFlags(QtCore.Qt.ItemIsEnabled)
self.selectedListWidget.addItem(song)
return True
elif self.currentPage() == self.exportSongPage:
if not self.directoryLineEdit.text():
critical_error_message_box(
translate('SongsPlugin.ExportWizardForm',
'No Save Location specified'),
translate('SongsPlugin.ExportWizardForm',
'You need to specified a directory to save the songs in.'))
return False
return True
elif self.currentPage() == self.progressPage:
self.availableListWidget.clear()
self.selectedListWidget.clear()
return True
def setDefaults(self):
"""
Set default form values for the song export wizard.
"""
self.restart()
self.finishButton.setVisible(False)
self.cancelButton.setVisible(True)
self.availableListWidget.clear()
self.selectedListWidget.clear()
self.directoryLineEdit.clear()
# Load the list of songs.
Receiver.send_message(u'cursor_busy')
songs = self.plugin.manager.get_all_objects(Song)
for song in songs:
authors = u', '.join([author.display_name
for author in song.authors])
title = u'%s (%s)' % (unicode(song.title), authors)
item = QtGui.QListWidgetItem(title)
item.setData(QtCore.Qt.UserRole, QtCore.QVariant(song))
item.setFlags(QtCore.Qt.ItemIsSelectable|
QtCore.Qt.ItemIsUserCheckable | QtCore.Qt.ItemIsEnabled)
item.setCheckState(QtCore.Qt.Unchecked)
self.availableListWidget.addItem(item)
Receiver.send_message(u'cursor_normal')
def preWizard(self):
"""
Perform pre export tasks.
"""
OpenLPWizard.preWizard(self)
self.progressLabel.setText(
translate('SongsPlugin.ExportWizardForm', 'Starting export...'))
Receiver.send_message(u'openlp_process_events')
def performWizard(self):
"""
Perform the actual export. This creates an *openlyricsexport* instance
and calls the *do_export* method.
"""
songs = [
song.data(QtCore.Qt.UserRole).toPyObject()
for song in self._findListWidgetItems(self.selectedListWidget)
]
exporter = OpenLyricsExport(
self, songs, unicode(self.directoryLineEdit.text()))
if exporter.do_export():
self.progressLabel.setText(
translate('SongsPlugin.SongExportForm', 'Finished export.'))
else:
self.progressLabel.setText(
translate('SongsPlugin.SongExportForm',
'Your song export failed.'))
def _findListWidgetItems(self, listWidget, text=u''):
"""
Returns a list of *QListWidgetItem*s of the ``listWidget``. Note, that
hidden items are included.
``listWidget``
The widget to get all items from. (QListWidget)
``text``
The text to search for. (unicode string)
"""
return [item for item in listWidget.findItems(
QtCore.QString(unicode(text)), QtCore.Qt.MatchContains)
]
def onItemPressed(self, item):
"""
Called, when an item in the *availableListWidget* has been pressed. Thes
item is check if it was not checked, whereas it is unchecked when it was
checked.
``item``
The *QListWidgetItem* which was pressed.
"""
item.setCheckState(
QtCore.Qt.Unchecked if item.checkState() else QtCore.Qt.Checked)
def onSearchLineEditChanged(self, text):
"""
The *searchLineEdit*'s text has been changed. Update the list of
available songs. Note that any song, which does not match the ``text``
will be hidden, but not unchecked!
``text``
The text of the *searchLineEdit*. (QString)
"""
search_result = [
song for song in self._findListWidgetItems(
self.availableListWidget, unicode(text))
]
for item in self._findListWidgetItems(self.availableListWidget):
item.setHidden(False if item in search_result else True)
def onUncheckButtonClicked(self):
"""
The *uncheckButton* has been clicked. Set all songs unchecked.
"""
for row in range(self.availableListWidget.count()):
item = self.availableListWidget.item(row)
item.setCheckState(QtCore.Qt.Unchecked)
def onCheckButtonClicked(self):
"""
The *checkButton* has been clicked. Set all songs checked.
"""
for row in range(self.availableListWidget.count()):
item = self.availableListWidget.item(row)
item.setCheckState(QtCore.Qt.Checked)
def onDirectoryButtonClicked(self):
"""
Called when the *directoryButton* was clicked. Opens a dialog and writes
the path to *directoryLineEdit*.
"""
path = unicode(QtGui.QFileDialog.getExistingDirectory(self,
translate('SongsPlugin.ExportWizardForm', 'Selecte to Folder'),
SettingsManager.get_last_dir(self.plugin.settingsSection, 1),
options=QtGui.QFileDialog.ShowDirsOnly))
SettingsManager.set_last_dir(self.plugin.settingsSection, path, 1)
self.directoryLineEdit.setText(path)

View File

@ -140,6 +140,12 @@ class SongImportForm(OpenLPWizard):
QtCore.QObject.connect(self.songBeamerRemoveButton,
QtCore.SIGNAL(u'clicked()'),
self.onSongBeamerRemoveButtonClicked)
QtCore.QObject.connect(self.songShowPlusAddButton,
QtCore.SIGNAL(u'clicked()'),
self.onSongShowPlusAddButtonClicked)
QtCore.QObject.connect(self.songShowPlusRemoveButton,
QtCore.SIGNAL(u'clicked()'),
self.onSongShowPlusRemoveButtonClicked)
def addCustomPages(self):
"""
@ -188,6 +194,8 @@ class SongImportForm(OpenLPWizard):
self.addFileSelectItem(u'ew', single_select=True)
# Words of Worship
self.addFileSelectItem(u'songBeamer')
# Song Show Plus
self.addFileSelectItem(u'songShowPlus')
# Commented out for future use.
# self.addFileSelectItem(u'csv', u'CSV', single_select=True)
self.sourceLayout.addLayout(self.formatStack)
@ -237,6 +245,8 @@ class SongImportForm(OpenLPWizard):
translate('SongsPlugin.ImportWizardForm', 'EasyWorship'))
self.formatComboBox.setItemText(10,
translate('SongsPlugin.ImportWizardForm', 'SongBeamer'))
self.formatComboBox.setItemText(11,
translate('SongsPlugin.ImportWizardForm', 'SongShow Plus'))
# self.formatComboBox.setItemText(11,
# translate('SongsPlugin.ImportWizardForm', 'CSV'))
self.openLP2FilenameLabel.setText(
@ -301,6 +311,10 @@ class SongImportForm(OpenLPWizard):
translate('SongsPlugin.ImportWizardForm', 'Add Files...'))
self.songBeamerRemoveButton.setText(
translate('SongsPlugin.ImportWizardForm', 'Remove File(s)'))
self.songShowPlusAddButton.setText(
translate('SongsPlugin.ImportWizardForm', 'Add Files...'))
self.songShowPlusRemoveButton.setText(
translate('SongsPlugin.ImportWizardForm', 'Remove File(s)'))
# self.csvFilenameLabel.setText(
# translate('SongsPlugin.ImportWizardForm', 'Filename:'))
# self.csvBrowseButton.setText(
@ -438,38 +452,20 @@ class SongImportForm(OpenLPWizard):
'file to import from.'))
self.songBeamerAddButton.setFocus()
return False
elif source_format == SongFormat.SongShowPlus:
if self.songShowPlusFileListWidget.count() == 0:
critical_error_message_box(
translate('SongsPlugin.ImportWizardForm',
'No SongShow Plus Files Selected'),
translate('SongsPlugin.ImportWizardForm',
'You need to add at least one SongShow Plus '
'file to import from.'))
self.wordsOfWorshipAddButton.setFocus()
return False
return True
elif self.currentPage() == self.progressPage:
return True
def getFileName(self, title, editbox, filters=u''):
"""
Opens a QFileDialog and writes the filename to the given editbox.
``title``
The title of the dialog (unicode).
``editbox``
A editbox (QLineEdit).
``filters``
The file extension filters. It should contain the file descriptions
as well as the file extensions. For example::
u'OpenLP 2.0 Databases (*.sqlite)'
"""
if filters:
filters += u';;'
filters += u'%s (*)' % translate('SongsPlugin.ImportWizardForm',
'All Files')
filename = QtGui.QFileDialog.getOpenFileName(self, title,
SettingsManager.get_last_dir(self.plugin.settingsSection, 1),
filters)
if filename:
editbox.setText(filename)
SettingsManager.set_last_dir(self.plugin.settingsSection,
os.path.split(unicode(filename))[0], 1)
def getFiles(self, title, listbox, filters=u''):
"""
Opens a QFileDialog and writes the filenames to the given listbox.
@ -672,11 +668,23 @@ class SongImportForm(OpenLPWizard):
"""
self.removeSelectedItems(self.songBeamerFileListWidget)
def registerFields(self):
def onSongShowPlusAddButtonClicked(self):
"""
Register song import wizard fields.
Get SongShow Plus song database files
"""
pass
self.getFiles(
translate('SongsPlugin.ImportWizardForm',
'Select SongShow Plus Files'),
self.songShowPlusFileListWidget, u'%s (*.sbsong)'
% translate('SongsPlugin.ImportWizardForm',
'SongShow Plus Song Files')
)
def onSongShowPlusRemoveButtonClicked(self):
"""
Remove selected SongShow Plus files from the import list
"""
self.removeSelectedItems(self.songShowPlusFileListWidget)
def setDefaults(self):
"""
@ -697,6 +705,7 @@ class SongImportForm(OpenLPWizard):
self.easiSlidesFilenameEdit.setText(u'')
self.ewFilenameEdit.setText(u'')
self.songBeamerFileListWidget.clear()
self.songShowPlusFileListWidget.clear()
#self.csvFilenameEdit.setText(u'')
def preWizard(self):
@ -773,6 +782,12 @@ class SongImportForm(OpenLPWizard):
importer = self.plugin.importSongs(SongFormat.SongBeamer,
filenames=self.getListOfFiles(self.songBeamerFileListWidget)
)
elif source_format == SongFormat.SongShowPlus:
# Import ShongShow Plus songs
importer = self.plugin.importSongs(SongFormat.SongShowPlus,
filenames=self.getListOfFiles(
self.songShowPlusFileListWidget)
)
if importer.do_import():
self.progressLabel.setText(
translate('SongsPlugin.SongImportForm', 'Finished import.'))

View File

@ -27,7 +27,7 @@
from PyQt4 import QtCore, QtGui
from openlp.core.lib import translate
from openlp.core.lib.ui import create_save_cancel_button_box
from openlp.core.lib.ui import create_accept_reject_button_box
class Ui_TopicsDialog(object):
def setupUi(self, topicsDialog):
@ -45,7 +45,7 @@ class Ui_TopicsDialog(object):
self.nameLayout.addRow(self.nameLabel, self.nameEdit)
self.dialogLayout.addLayout(self.nameLayout)
self.dialogLayout.addWidget(
create_save_cancel_button_box(topicsDialog))
create_accept_reject_button_box(topicsDialog))
self.retranslateUi(topicsDialog)
topicsDialog.setMaximumHeight(topicsDialog.sizeHint().height())
QtCore.QMetaObject.connectSlotsByName(topicsDialog)

View File

@ -34,6 +34,7 @@ from wowimport import WowImport
from cclifileimport import CCLIFileImport
from ewimport import EasyWorshipSongImport
from songbeamerimport import SongBeamerImport
from songshowplusimport import SongShowPlusImport
# Imports that might fail
try:
from olp1import import OpenLP1SongImport
@ -71,6 +72,7 @@ class SongFormat(object):
EasiSlides = 8
EasyWorship = 9
SongBeamer = 10
SongShowPlus = 11
@staticmethod
def get_class(format):
@ -102,6 +104,8 @@ class SongFormat(object):
return EasyWorshipSongImport
elif format == SongFormat.SongBeamer:
return SongBeamerImport
elif format == SongFormat.SongShowPlus:
return SongShowPlusImport
return None
@staticmethod
@ -120,7 +124,8 @@ class SongFormat(object):
SongFormat.Generic,
SongFormat.EasiSlides,
SongFormat.EasyWorship,
SongFormat.SongBeamer
SongFormat.SongBeamer,
SongFormat.SongShowPlus
]
@staticmethod

View File

@ -31,23 +31,17 @@ import re
from PyQt4 import QtCore, QtGui
from sqlalchemy.sql import or_
from openlp.core.lib import MediaManagerItem, BaseListWithDnD, Receiver, \
ItemCapabilities, translate, check_item_selected, PluginStatus
from openlp.core.lib import MediaManagerItem, Receiver, ItemCapabilities, \
translate, check_item_selected, PluginStatus
from openlp.core.lib.ui import UiStrings
from openlp.plugins.songs.forms import EditSongForm, SongMaintenanceForm, \
SongImportForm
SongImportForm, SongExportForm
from openlp.plugins.songs.lib import OpenLyrics, SongXML
from openlp.plugins.songs.lib.db import Author, Song
from openlp.core.lib.searchedit import SearchEdit
log = logging.getLogger(__name__)
class SongListView(BaseListWithDnD):
def __init__(self, parent=None):
self.PluginName = u'Songs'
BaseListWithDnD.__init__(self, parent)
class SongMediaItem(MediaManagerItem):
"""
This is the custom media manager item for Songs.
@ -56,7 +50,6 @@ class SongMediaItem(MediaManagerItem):
def __init__(self, parent, plugin, icon):
self.IconPath = u'songs/song'
self.ListViewWithDnD_class = SongListView
MediaManagerItem.__init__(self, parent, self, icon)
self.edit_song_form = EditSongForm(self, self.parent.manager)
self.openLyrics = OpenLyrics(self.parent.manager)
@ -265,6 +258,11 @@ class SongMediaItem(MediaManagerItem):
if self.import_wizard.exec_() == QtGui.QDialog.Accepted:
Receiver.send_message(u'songs_load_list')
def onExportClick(self):
if not hasattr(self, u'export_wizard'):
self.export_wizard = SongExportForm(self, self.parent)
self.export_wizard.exec_()
def onNewClick(self):
log.debug(u'onNewClick')
self.edit_song_form.newSong()

View File

@ -0,0 +1,74 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2011 Raoul Snyman #
# Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael #
# Gorven, Scott Guerrieri, Meinert Jordan, Andreas Preikschat, Christian #
# Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon Tibble, #
# Carsten Tinggaard, Frode Woldsund #
# --------------------------------------------------------------------------- #
# 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:`openlyricsexport` module provides the functionality for exporting
songs from the database to the OpenLyrics format.
"""
import logging
import os
from lxml import etree
from openlp.core.lib import Receiver, translate
from openlp.plugins.songs.lib import OpenLyrics
log = logging.getLogger(__name__)
class OpenLyricsExport(object):
"""
This provides the Openlyrics export.
"""
def __init__(self, parent, songs, save_path):
"""
Initialise the export.
"""
log.debug(u'initialise OpenLyricsExport')
self.parent = parent
self.manager = parent.plugin.manager
self.songs = songs
self.save_path = save_path
if not os.path.exists(self.save_path):
os.mkdir(self.save_path)
def do_export(self):
"""
Export the songs.
"""
log.debug(u'started OpenLyricsExport')
openLyrics = OpenLyrics(self.manager)
self.parent.progressBar.setMaximum(len(self.songs))
for song in self.songs:
Receiver.send_message(u'openlp_process_events')
if self.parent.stop_export_flag:
return False
self.parent.incrementProgressBar(unicode(translate(
'SongsPlugin.OpenLyricsExport', 'Exporting "%s"...')) %
song.title)
xml = openLyrics.song_to_xml(song)
tree = etree.ElementTree(etree.fromstring(xml))
tree.write(os.path.join(self.save_path, song.title + u'.xml'),
encoding=u'utf-8', xml_declaration=True, pretty_print=True)
return True

View File

@ -36,6 +36,7 @@ from openlp.plugins.songs.lib.songimport import SongImport
log = logging.getLogger(__name__)
#TODO: Use lxml for parsing and make sure we use methods of "SongImport" .
class OpenSongImport(SongImport):
"""
Import songs exported from OpenSong
@ -276,7 +277,7 @@ class OpenSongImport(SongImport):
for num in versenums:
versetag = u'%s%s' % (our_verse_type, num)
lines = u'\n'.join(verses[versetype][num])
self.verses.append([versetag, lines])
self.add_verse(lines, versetag)
# Keep track of what we have for error checking later
versetags[versetag] = 1
# now figure out the presentation order
@ -292,6 +293,8 @@ class OpenSongImport(SongImport):
else:
log.warn(u'No verse order available for %s, skipping.',
self.title)
# TODO: make sure that the default order list will be overwritten, if
# the songs provides its own order list.
for tag in order:
if tag[0].isdigit():
# Assume it's a verse if it has no prefix

View File

@ -0,0 +1,212 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2011 Raoul Snyman #
# Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael #
# Gorven, Scott Guerrieri, Meinert Jordan, Andreas Preikschat, Christian #
# Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon Tibble, #
# Carsten Tinggaard, Frode Woldsund #
# --------------------------------------------------------------------------- #
# 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:`wowimport` module provides the functionality for importing Words of
Worship songs into the OpenLP database.
"""
import os
import logging
import struct
from openlp.plugins.songs.lib.songimport import SongImport
TITLE = 1
AUTHOR = 2
COPYRIGHT = 3
CCLI_NO = 5
VERSE = 12
CHORUS = 20
TOPIC = 29
COMMENTS = 30
VERSE_ORDER = 31
SONG_BOOK = 35
SONG_NUMBER = 36
CUSTOM_VERSE = 37
log = logging.getLogger(__name__)
class SongShowPlusImport(SongImport):
"""
The :class:`SongShowPlusImport` class provides the ability to import song
files from SongShow Plus.
**SongShow Plus Song File Format:**
The SongShow Plus song file format is as follows:
* Each piece of data in the song file has some information that precedes
it.
* The general format of this data is as follows:
4 Bytes, forming a 32 bit number, a key if you will, this describes what
the data is (see blockKey below)
4 Bytes, forming a 32 bit number, which is the number of bytes until the
next block starts
1 Byte, which tells how namy bytes follows
1 or 4 Bytes, describes how long the string is, if its 1 byte, the string
is less than 255
The next bytes are the actuall data.
The next block of data follows on.
This description does differ for verses. Which includes extra bytes
stating the verse type or number. In some cases a "custom" verse is used,
in that case, this block will in include 2 strings, with the associated
string length descriptors. The first string is the name of the verse, the
second is the verse content.
The file is ended with four null bytes.
Valid extensions for a SongShow Plus song file are:
* .sbsong
"""
otherList = {}
otherCount = 0
def __init__(self, master_manager, **kwargs):
"""
Initialise the import.
``master_manager``
The song manager for the running OpenLP installation.
"""
SongImport.__init__(self, master_manager)
if kwargs.has_key(u'filename'):
self.import_source = kwargs[u'filename']
if kwargs.has_key(u'filenames'):
self.import_source = kwargs[u'filenames']
log.debug(self.import_source)
def do_import(self):
"""
Receive a single file or a list of files to import.
"""
if isinstance(self.import_source, list):
self.import_wizard.progressBar.setMaximum(len(self.import_source))
for file in self.import_source:
author = u''
copyright = u''
self.sspVerseOrderList = []
otherCount = 0
otherList = {}
file_name = os.path.split(file)[1]
self.import_wizard.incrementProgressBar(
u'Importing %s' % (file_name), 0)
songData = open(file, 'rb')
while (1):
blockKey, = struct.unpack("I",songData.read(4))
# The file ends with 4 NUL's
if blockKey == 0:
break
nextBlockStarts, = struct.unpack("I",songData.read(4))
if blockKey == VERSE or blockKey == CHORUS:
null, verseNo, = struct.unpack("BB",songData.read(2))
elif blockKey == CUSTOM_VERSE:
null, verseNameLength, = struct.unpack("BB",
songData.read(2))
verseName = songData.read(verseNameLength)
lengthDescriptorSize, = struct.unpack("B",songData.read(1))
# Detect if/how long the length descriptor is
if lengthDescriptorSize == 12:
lengthDescriptor, = struct.unpack("I",songData.read(4))
elif lengthDescriptorSize == 2:
lengthDescriptor = 1
elif lengthDescriptorSize == 9:
lengthDescriptor = 0
else:
lengthDescriptor, = struct.unpack("B",songData.read(1))
data = songData.read(lengthDescriptor)
if blockKey == TITLE:
self.title = unicode(data, u'cp1252')
elif blockKey == AUTHOR:
authors = data.split(" / ")
for author in authors:
if author.find(",") !=-1:
authorParts = author.split(", ")
author = authorParts[1] + " " + authorParts[0]
self.parse_author(unicode(author, u'cp1252'))
elif blockKey == COPYRIGHT:
self.add_copyright(unicode(data, u'cp1252'))
elif blockKey == CCLI_NO:
self.ccli_number = int(data)
elif blockKey == VERSE:
self.add_verse(unicode(data, u'cp1252'),
"V%s" % verseNo)
elif blockKey == CHORUS:
self.add_verse(unicode(data, u'cp1252'),
"C%s" % verseNo)
elif blockKey == TOPIC:
self.topics.append(unicode(data, u'cp1252'))
elif blockKey == COMMENTS:
self.comments = unicode(data, u'cp1252')
elif blockKey == VERSE_ORDER:
verseTag = self.toOpenLPVerseTag(data)
self.sspVerseOrderList.append(unicode(verseTag,
u'cp1252'))
elif blockKey == SONG_BOOK:
self.song_book_name = unicode(data, u'cp1252')
elif blockKey == SONG_NUMBER:
self.song_number = ord(data)
elif blockKey == CUSTOM_VERSE:
verseTag = self.toOpenLPVerseTag(verseName)
self.add_verse(unicode(data, u'cp1252'), verseTag)
else:
log.debug("Unrecognised blockKey: %s, data: %s"
%(blockKey, data))
self.verse_order_list = self.sspVerseOrderList
songData.close()
self.finish()
self.import_wizard.incrementProgressBar(
u'Importing %s' % (file_name))
return True
def toOpenLPVerseTag(self, verseName):
if verseName.find(" ")!=-1:
verseParts = verseName.split(" ")
verseType = verseParts[0]
verseNumber = verseParts[1]
else:
verseType = verseName
verseNumber = "1"
verseType = verseType.lower()
if verseType == "verse":
verseTag = "V"
elif verseType == "chorus":
verseTag = "C"
elif verseType == "bridge":
verseTag = "B"
elif verseType == "pre-chorus":
verseTag = "P"
elif verseType == "bridge":
verseTag = "B"
else:
if not self.otherList.has_key(verseName):
self.otherCount = self.otherCount + 1
self.otherList[verseName] = str(self.otherCount)
verseTag = "O"
verseNumber = self.otherList[verseName]
verseTag = verseTag + verseNumber
return verseTag

View File

@ -60,6 +60,7 @@ The XML of an `OpenLyrics <http://openlyrics.info/>`_ song looks like this::
</song>
"""
import datetime
import logging
import re
@ -89,8 +90,10 @@ class SongXML(object):
Add a verse to the ``<lyrics>`` tag.
``type``
A string denoting the type of verse. Possible values are "V",
"C", "B", "P", "I", "E" and "O".
A string denoting the type of verse. Possible values are *Verse*,
*Chorus*, *Bridge*, *Pre-Chorus*, *Intro*, *Ending* and *Other*.
Any other type is **not** allowed, this also includes translated
types.
``number``
An integer denoting the number of the item, for example: verse 1.
@ -126,8 +129,8 @@ class SongXML(object):
The returned list has the following format::
[[{'lang': 'en', 'type': 'V', 'label': '1'}, u"The English verse."],
[{'lang': 'en', 'type': 'C', 'label': '1'}, u"The English chorus."]]
[[{'lang': 'en', 'type': 'Verse', 'label': '1'}, u"English verse"],
[{'lang': 'en', 'type': 'Chorus', 'label': '1'}, u"English chorus"]]
"""
self.song_xml = None
if xml[:5] == u'<?xml':
@ -207,12 +210,14 @@ class OpenLyrics(object):
This property is not supported.
``<verse name="v1a" lang="he" translit="en">``
The attribute *translit* is not supported.
The attribute *translit* is not supported. Note, the attribute *lang* is
considered, but there is not further functionality implemented yet.
``<verseOrder>``
OpenLP supports this property.
"""
IMPLEMENTED_VERSION = u'0.7'
def __init__(self, manager):
self.manager = manager
@ -222,8 +227,14 @@ class OpenLyrics(object):
"""
sxml = SongXML()
verse_list = sxml.get_verses(song.lyrics)
song_xml = objectify.fromstring(
u'<song version="0.7" createdIn="OpenLP 2.0"/>')
song_xml = objectify.fromstring(u'<song/>')
# Append the necessary meta data to the song.
song_xml.set(u'xmlns', u'http://openlyrics.info/namespace/2009/song')
song_xml.set(u'version', OpenLyrics.IMPLEMENTED_VERSION)
song_xml.set(u'createdIn', u'OpenLP 1.9.4') # Use variable
song_xml.set(u'modifiedIn', u'OpenLP 1.9.4') # Use variable
song_xml.set(u'modifiedDate',
datetime.datetime.now().strftime(u'%Y-%m-%dT%H:%M:%S'))
properties = etree.SubElement(song_xml, u'properties')
titles = etree.SubElement(properties, u'titles')
self._add_text_to_element(u'title', titles, song.title.strip())
@ -237,7 +248,7 @@ class OpenLyrics(object):
self._add_text_to_element(u'copyright', properties, song.copyright)
if song.verse_order:
self._add_text_to_element(
u'verseOrder', properties, song.verse_order)
u'verseOrder', properties, song.verse_order.lower())
if song.ccli_number:
self._add_text_to_element(u'ccliNo', properties, song.ccli_number)
if song.authors:
@ -252,6 +263,7 @@ class OpenLyrics(object):
songbooks = etree.SubElement(properties, u'songbooks')
element = self._add_text_to_element(
u'songbook', songbooks, None, book)
if song.song_number:
element.set(u'entry', song.song_number)
if song.topics:
themes = etree.SubElement(properties, u'themes')
@ -263,6 +275,8 @@ class OpenLyrics(object):
verse[0][u'type'][0].lower(), verse[0][u'label'])
element = \
self._add_text_to_element(u'verse', lyrics, None, verse_tag)
if verse[0].has_key(u'lang'):
element.set(u'lang', verse[0][u'lang'])
element = self._add_text_to_element(u'lines', element)
for line in unicode(verse[1]).split(u'\n'):
self._add_text_to_element(u'line', element, line)
@ -450,7 +464,7 @@ class OpenLyrics(object):
text += u'\n'
text += u'\n'.join([unicode(line) for line in lines.line])
verse_name = self._get(verse, u'name')
verse_type = unicode(VerseType.to_string(verse_name[0]))[0]
verse_type = unicode(VerseType.to_string(verse_name[0]))
verse_number = re.compile(u'[a-zA-Z]*').sub(u'', verse_name)
verse_part = re.compile(u'[0-9]*').sub(u'', verse_name[1:])
# OpenLyrics allows e. g. "c", but we need "c1".
@ -478,9 +492,9 @@ class OpenLyrics(object):
for name in temp_verse_order:
if name[0] == previous_type:
if name[1] != previous_number:
verse_order.append(u''.join((name[0], name[1])))
verse_order.append(u''.join((name[0][0], name[1])))
else:
verse_order.append(u''.join((name[0], name[1])))
verse_order.append(u''.join((name[0][0], name[1])))
previous_type = name[0]
previous_number = name[1]
previous_part = name[2]

View File

@ -31,7 +31,6 @@ from PyQt4 import QtCore, QtGui
from openlp.core.lib import Plugin, StringContent, build_icon, translate
from openlp.core.lib.db import Manager
from openlp.core.lib.ui import UiStrings
from openlp.plugins.songs.lib import SongMediaItem, SongsTab, SongXML
from openlp.plugins.songs.lib.db import Author, init_schema, Song
from openlp.plugins.songs.lib.importer import SongFormat
@ -52,17 +51,14 @@ class SongsPlugin(Plugin):
"""
Create and set up the Songs plugin.
"""
Plugin.__init__(self, u'Songs', u'1.9.4', plugin_helpers)
Plugin.__init__(self, u'Songs', u'1.9.4', plugin_helpers,
SongMediaItem, SongsTab)
self.weight = -10
self.manager = Manager(u'songs', init_schema)
self.icon_path = u':/plugins/plugin_songs.png'
self.icon = build_icon(self.icon_path)
self.whitespace = re.compile(r'\W+', re.UNICODE)
def getSettingsTab(self):
visible_name = self.getString(StringContent.VisibleName)
return SongsTab(self.name, visible_name[u'title'])
def initialise(self):
log.info(u'Songs Initialising')
Plugin.initialise(self)
@ -70,13 +66,6 @@ class SongsPlugin(Plugin):
self.mediaItem.displayResultsSong(
self.manager.get_all_objects(Song, order_by_ref=Song.search_title))
def getMediaManagerItem(self):
"""
Create the MediaManagerItem object, which is displaed in the
Media Manager.
"""
return SongMediaItem(self, self, self.icon)
def addImportMenuItem(self, import_menu):
"""
Give the Songs plugin the opportunity to add items to the
@ -107,8 +96,17 @@ class SongsPlugin(Plugin):
The actual **Export** menu item, so that your actions can
use it as their parent.
"""
# No menu items for now.
pass
# Main song import menu item - will eventually be the only one
self.SongExportItem = QtGui.QAction(export_menu)
self.SongExportItem.setObjectName(u'SongExportItem')
self.SongExportItem.setText(translate(
'SongsPlugin', '&Song'))
self.SongExportItem.setToolTip(translate('SongsPlugin',
'Exports songs using the export wizard.'))
export_menu.addAction(self.SongExportItem)
# Signals and slots
QtCore.QObject.connect(self.SongExportItem,
QtCore.SIGNAL(u'triggered()'), self.onSongExportItemClicked)
def addToolsMenuItem(self, tools_menu):
"""
@ -184,6 +182,10 @@ class SongsPlugin(Plugin):
if self.mediaItem:
self.mediaItem.onImportClick()
def onSongExportItemClicked(self):
if self.mediaItem:
self.mediaItem.onExportClick()
def about(self):
about_text = translate('SongsPlugin', '<strong>Songs Plugin</strong>'
'<br />The songs plugin provides the ability to display and '
@ -237,7 +239,18 @@ class SongsPlugin(Plugin):
u'title': translate('SongsPlugin', 'Songs', 'container title')
}
# Middle Header Bar
Plugin.setPluginTextStrings(self)
tooltips = {
u'load': u'',
u'import': u'',
u'new': translate('SongsPlugin', 'Add a new Song'),
u'edit': translate('SongsPlugin', 'Edit the selected Song'),
u'delete': translate('SongsPlugin', 'Delete the selected Song'),
u'preview': translate('SongsPlugin', 'Preview the selected Song'),
u'live': translate('SongsPlugin', 'Send the selected Song live'),
u'service': translate('SongsPlugin',
'Add the selected Song to the service')
}
self.setPluginUiTextStrings(tooltips)
def finalise(self):
"""

View File

@ -25,7 +25,9 @@
###############################################################################
from PyQt4 import QtCore, QtGui
from openlp.core.lib import translate
from openlp.core.lib.ui import create_accept_reject_button_box
class Ui_SongUsageDeleteDialog(object):
def setupUi(self, songUsageDeleteDialog):
@ -43,19 +45,11 @@ class Ui_SongUsageDeleteDialog(object):
QtGui.QCalendarWidget.NoVerticalHeader)
self.deleteCalendar.setObjectName(u'deleteCalendar')
self.verticalLayout.addWidget(self.deleteCalendar)
self.buttonBox = QtGui.QDialogButtonBox(songUsageDeleteDialog)
self.buttonBox = create_accept_reject_button_box(
songUsageDeleteDialog, True)
self.buttonBox.setGeometry(QtCore.QRect(30, 210, 245, 25))
self.buttonBox.setStandardButtons(
QtGui.QDialogButtonBox.Cancel|QtGui.QDialogButtonBox.Ok)
self.buttonBox.setObjectName(u'buttonBox')
self.retranslateUi(songUsageDeleteDialog)
QtCore.QObject.connect(
self.buttonBox, QtCore.SIGNAL(u'accepted()'),
songUsageDeleteDialog.accept)
QtCore.QObject.connect(
self.buttonBox, QtCore.SIGNAL(u'rejected()'),
songUsageDeleteDialog.close)
QtCore.QMetaObject.connectSlotsByName(songUsageDeleteDialog)
def retranslateUi(self, songUsageDeleteDialog):

View File

@ -27,6 +27,7 @@
from PyQt4 import QtCore, QtGui
from openlp.core.lib import build_icon, translate
from openlp.core.lib.ui import create_accept_reject_button_box
class Ui_SongUsageDetailDialog(object):
def setupUi(self, songUsageDetailDialog):
@ -71,17 +72,10 @@ class Ui_SongUsageDetailDialog(object):
self.verticalLayout4.addLayout(self.horizontalLayout)
self.verticalLayout2.addWidget(self.fileGroupBox)
self.verticalLayout.addWidget(self.dateRangeGroupBox)
self.buttonBox = QtGui.QDialogButtonBox(songUsageDetailDialog)
self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Cancel |
QtGui.QDialogButtonBox.Ok)
self.buttonBox.setObjectName(u'buttonBox')
self.buttonBox = create_accept_reject_button_box(
songUsageDetailDialog, True)
self.verticalLayout.addWidget(self.buttonBox)
self.retranslateUi(songUsageDetailDialog)
QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(u'accepted()'),
songUsageDetailDialog.accept)
QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(u'rejected()'),
songUsageDetailDialog.close)
QtCore.QObject.connect(self.saveFilePushButton,
QtCore.SIGNAL(u'pressed()'),
songUsageDetailDialog.defineOutputLocation)

View File

@ -1,241 +0,0 @@
<ui version="4.0" >
<class>SongExportDialog</class>
<widget class="QDialog" name="SongExportDialog" >
<property name="geometry" >
<rect>
<x>0</x>
<y>0</y>
<width>641</width>
<height>607</height>
</rect>
</property>
<property name="windowTitle" >
<string>Dialog</string>
</property>
<layout class="QVBoxLayout" name="SongExportLayout" >
<property name="spacing" >
<number>8</number>
</property>
<property name="margin" >
<number>8</number>
</property>
<item>
<widget class="QWidget" native="1" name="SongListsWidget" >
<layout class="QHBoxLayout" name="SongListsLayout" >
<property name="spacing" >
<number>8</number>
</property>
<property name="margin" >
<number>0</number>
</property>
<item>
<widget class="QGroupBox" name="AvailableGroupBox" >
<property name="title" >
<string>Available Songs</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout" >
<item>
<widget class="QListWidget" name="AvailableListWidget" />
</item>
<item>
<widget class="QToolButton" name="AvailableAllToolButton" >
<property name="text" >
<string>Select All</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QWidget" native="1" name="SelectionWidget" >
<property name="sizePolicy" >
<sizepolicy vsizetype="Minimum" hsizetype="Minimum" >
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize" >
<size>
<width>30</width>
<height>16777215</height>
</size>
</property>
<layout class="QVBoxLayout" name="SelectionLayout" >
<property name="spacing" >
<number>8</number>
</property>
<property name="sizeConstraint" >
<enum>QLayout::SetMinimumSize</enum>
</property>
<property name="margin" >
<number>0</number>
</property>
<item>
<spacer name="TopVerticalSpacer" >
<property name="orientation" >
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType" >
<enum>QSizePolicy::MinimumExpanding</enum>
</property>
<property name="sizeHint" stdset="0" >
<size>
<width>20</width>
<height>132</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QToolButton" name="SelectToolButton" >
<property name="text" >
<string>Select Songs</string>
</property>
<property name="icon" >
<iconset resource="../images/openlp-2.qrc" >
<normaloff>:/exports/export_move_to_list.png</normaloff>:/exports/export_move_to_list.png</iconset>
</property>
<property name="iconSize" >
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="DeselectToolButton" >
<property name="text" >
<string>Deselect Songs</string>
</property>
<property name="icon" >
<iconset resource="../images/openlp-2.qrc" >
<normaloff>:/exports/export_remove.png</normaloff>:/exports/export_remove.png</iconset>
</property>
<property name="iconSize" >
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</widget>
</item>
<item>
<spacer name="BottomVerticalSpacer" >
<property name="orientation" >
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType" >
<enum>QSizePolicy::MinimumExpanding</enum>
</property>
<property name="sizeHint" stdset="0" >
<size>
<width>20</width>
<height>131</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="SelectedGroupBox" >
<property name="title" >
<string>Selected Songs</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2" >
<item>
<widget class="QListWidget" name="SelectedListWidget" />
</item>
<item>
<widget class="QToolButton" name="SelectedAllToolButton" >
<property name="text" >
<string>Select All</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QTabWidget" name="ExportTabWidget" >
<property name="currentIndex" >
<number>0</number>
</property>
<widget class="QWidget" name="OpenLyricTab" >
<attribute name="title" >
<string>OpenLyric Format</string>
</attribute>
</widget>
<widget class="QWidget" name="TextFileTab" >
<attribute name="title" >
<string>Text File</string>
</attribute>
</widget>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="SongExportButtonBox" >
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons" >
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<tabstops>
<tabstop>SongExportButtonBox</tabstop>
<tabstop>AvailableListWidget</tabstop>
<tabstop>AvailableAllToolButton</tabstop>
<tabstop>SelectToolButton</tabstop>
<tabstop>DeselectToolButton</tabstop>
<tabstop>SelectedListWidget</tabstop>
<tabstop>SelectedAllToolButton</tabstop>
<tabstop>ExportTabWidget</tabstop>
</tabstops>
<resources>
<include location="../images/openlp-2.qrc" />
</resources>
<connections>
<connection>
<sender>SongExportButtonBox</sender>
<signal>accepted()</signal>
<receiver>SongExportDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel" >
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel" >
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>SongExportButtonBox</sender>
<signal>rejected()</signal>
<receiver>SongExportDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel" >
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel" >
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 335 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 862 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 666 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 784 B

View File

@ -21,6 +21,10 @@
<file>song_topic_edit.png</file>
<file>song_book_edit.png</file>
</qresource>
<qresource prefix="bibles">
<file>bibles_search_text.png</file>
<file>bibles_search_reference.png</file>
</qresource>
<qresource prefix="plugins">
<file>plugin_alerts.png</file>
<file>plugin_bibles.png</file>
@ -80,12 +84,10 @@
<file>import_load.png</file>
</qresource>
<qresource prefix="exports">
<file>export_selectall.png</file>
<file>export_remove.png</file>
<file>export_load.png</file>
<file>export_move_to_list.png</file>
</qresource>
<qresource prefix="wizards">
<file>wizard_exportsong.bmp</file>
<file>wizard_importsong.bmp</file>
<file>wizard_importbible.bmp</file>
<file>wizard_createtheme.bmp</file>

Binary file not shown.

After

Width:  |  Height:  |  Size: 168 KiB