19.02.2011

This commit is contained in:
Armin Köhler 2011-02-19 10:07:44 +01:00
commit b2d38da3d2
47 changed files with 765 additions and 544 deletions

View File

@ -239,7 +239,8 @@ def resize_image(image, width, height, background=QtCore.Qt.black):
Resize an image to fit on the current screen. Resize an image to fit on the current screen.
``image`` ``image``
The image to resize. The image to resize. It has to be either a ``QImage`` instance or the
path to the image.
``width`` ``width``
The new image width. The new image width.

View File

@ -85,8 +85,7 @@ class ImageManager(QtCore.QObject):
for key in self._cache.keys(): for key in self._cache.keys():
image = self._cache[key] image = self._cache[key]
image.dirty = True image.dirty = True
image.image = resize_image(image.path, image.image = resize_image(image.path, self.width, self.height)
self.width, self.height)
self._cache_dirty = True self._cache_dirty = True
# only one thread please # only one thread please
if not self._thread_running: if not self._thread_running:
@ -128,8 +127,7 @@ class ImageManager(QtCore.QObject):
image = Image() image = Image()
image.name = name image.name = name
image.path = path image.path = path
image.image = resize_image(path, image.image = resize_image(path, self.width, self.height)
self.width, self.height)
self._cache[name] = image self._cache[name] = image
else: else:
log.debug(u'Image in cache %s:%s' % (name, path)) log.debug(u'Image in cache %s:%s' % (name, path))

View File

@ -240,7 +240,7 @@ class MediaManagerItem(QtGui.QWidget):
Creates the main widget for listing items the media item is tracking Creates the main widget for listing items the media item is tracking
""" """
# Add the List widget # Add the List widget
self.listView = ListWidgetWithDnD(self, self.title) self.listView = ListWidgetWithDnD(self, self.plugin.name)
self.listView.uniformItemSizes = True self.listView.uniformItemSizes = True
self.listView.setSpacing(1) self.listView.setSpacing(1)
self.listView.setSelectionMode( self.listView.setSelectionMode(
@ -252,7 +252,6 @@ class MediaManagerItem(QtGui.QWidget):
self.pageLayout.addWidget(self.listView) self.pageLayout.addWidget(self.listView)
# define and add the context menu # define and add the context menu
self.listView.setContextMenuPolicy(QtCore.Qt.ActionsContextMenu) self.listView.setContextMenuPolicy(QtCore.Qt.ActionsContextMenu)
name_string = self.plugin.getString(StringContent.Name)
if self.hasEditIcon: if self.hasEditIcon:
self.listView.addAction( self.listView.addAction(
context_menu_action( context_menu_action(

View File

@ -335,37 +335,39 @@ class Plugin(QtCore.QObject):
""" """
return self.textStrings[name] return self.textStrings[name]
def setPluginTextStrings(self): def setPluginUiTextStrings(self, tooltips):
""" """
Called to define all translatable texts of the plugin Called to define all translatable texts of the plugin
""" """
## Load Action ## ## Load Action ##
self._setSingularTextString(StringContent.Load, self.__setNameTextString(StringContent.Load,
UiStrings.Load, UiStrings.LoadANew) UiStrings.Load, tooltips[u'load'])
## Import Action ##
self.__setNameTextString(StringContent.Import,
UiStrings.Import, tooltips[u'import'])
## New Action ## ## New Action ##
self._setSingularTextString(StringContent.New, self.__setNameTextString(StringContent.New,
UiStrings.Add, UiStrings.AddANew) UiStrings.Add, tooltips[u'new'])
## Edit Action ## ## Edit Action ##
self._setSingularTextString(StringContent.Edit, self.__setNameTextString(StringContent.Edit,
UiStrings.Edit, UiStrings.EditSelect) UiStrings.Edit, tooltips[u'edit'])
## Delete Action ## ## Delete Action ##
self._setSingularTextString(StringContent.Delete, self.__setNameTextString(StringContent.Delete,
UiStrings.Delete, UiStrings.DeleteSelect) UiStrings.Delete, tooltips[u'delete'])
## Preview Action ## ## Preview Action ##
self._setSingularTextString(StringContent.Preview, self.__setNameTextString(StringContent.Preview,
UiStrings.Preview, UiStrings.PreviewSelect) UiStrings.Preview, tooltips[u'preview'])
## Send Live Action ## ## Send Live Action ##
self._setSingularTextString(StringContent.Live, self.__setNameTextString(StringContent.Live,
UiStrings.Live, UiStrings.SendSelectLive) UiStrings.Live, tooltips[u'live'])
## Add to Service Action ## ## Add to Service Action ##
self._setSingularTextString(StringContent.Service, self.__setNameTextString(StringContent.Service,
UiStrings.Service, UiStrings.AddSelectService) 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 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 use of the singular name of the plugin object so must only be called
after this has been set. after this has been set.
""" """
self.textStrings[name] = { u'title': title, u'tooltip': tooltip % self.textStrings[name] = {u'title': title, u'tooltip': tooltip}
self.getString(StringContent.Name)[u'singular']}

View File

@ -203,12 +203,12 @@ class RenderManager(object):
# set the default image size for previews # set the default image size for previews
self.calculate_default(self.screens.preview[u'size']) self.calculate_default(self.screens.preview[u'size'])
verse = u'The Lord said to {r}Noah{/r}: \n' \ verse = u'The Lord said to {r}Noah{/r}: \n' \
'There\'s gonna be a {su}floody{/su}, {sb}floody{/sb}\n' \ 'There\'s gonna be a {su}floody{/su}, {sb}floody{/sb}\n' \
'The Lord said to {g}Noah{/g}:\n' \ 'The Lord said to {g}Noah{/g}:\n' \
'There\'s gonna be a {st}floody{/st}, {it}floody{/it}\n' \ 'There\'s gonna be a {st}floody{/st}, {it}floody{/it}\n' \
'Get those children out of the muddy, muddy \n' \ 'Get those children out of the muddy, muddy \n' \
'{r}C{/r}{b}h{/b}{bl}i{/bl}{y}l{/y}{g}d{/g}{pk}' \ '{r}C{/r}{b}h{/b}{bl}i{/bl}{y}l{/y}{g}d{/g}{pk}' \
'r{/pk}{o}e{/o}{pp}n{/pp} of the Lord\n' 'r{/pk}{o}e{/o}{pp}n{/pp} of the Lord\n'
# make big page for theme edit dialog to get line count # make big page for theme edit dialog to get line count
if self.force_page: if self.force_page:
verse = verse + verse + verse verse = verse + verse + verse

View File

@ -30,7 +30,6 @@ type and capability of an item.
import datetime import datetime
import logging import logging
import mutagen
import os import os
import uuid import uuid
@ -110,6 +109,7 @@ class ServiceItem(object):
self.edit_id = None self.edit_id = None
self.xml_version = None self.xml_version = None
self.start_time = 0 self.start_time = 0
self.media_length = 0
self._new_item() self._new_item()
def _new_item(self): def _new_item(self):
@ -263,7 +263,8 @@ class ServiceItem(object):
u'search': self.search_string, u'search': self.search_string,
u'data': self.data_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'start_time': self.start_time,
u'media_length': self.media_length
} }
service_data = [] service_data = []
if self.service_item_type == ServiceItemType.Text: if self.service_item_type == ServiceItemType.Text:
@ -309,6 +310,8 @@ class ServiceItem(object):
self.xml_version = header[u'xml_version'] self.xml_version = header[u'xml_version']
if u'start_time' in header: if u'start_time' in header:
self.start_time = header[u'start_time'] 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: if self.service_item_type == ServiceItemType.Text:
for slide in serviceitem[u'serviceitem'][u'data']: for slide in serviceitem[u'serviceitem'][u'data']:
self._raw_frames.append(slide) self._raw_frames.append(slide)
@ -433,20 +436,14 @@ class ServiceItem(object):
""" """
Returns the start and finish time for a media item Returns the start and finish time for a media item
""" """
tooltip = None
start = None start = None
end = None end = None
if self.start_time != 0: if self.start_time != 0:
start = UiStrings.StartTimeCode % \ start = UiStrings.StartTimeCode % \
unicode(datetime.timedelta(seconds=self.start_time)) unicode(datetime.timedelta(seconds=self.start_time))
path = os.path.join(self.get_frames()[0][u'path'], if self.media_length != 0:
self.get_frames()[0][u'title']) end = UiStrings.LengthTime % \
if os.path.isfile(path): unicode(datetime.timedelta(seconds=self.media_length))
file = mutagen.File(path)
if file is not None:
seconds = int(file.info.length)
end = UiStrings.LengthTime % \
unicode(datetime.timedelta(seconds=seconds))
if not start and not end: if not start and not end:
return None return None
elif start and not end: elif start and not end:

View File

@ -178,9 +178,9 @@ class HorizontalType(object):
""" """
Return a string representation of a horizontal type. Return a string representation of a horizontal type.
""" """
if horizontal_type == Horizontal.Right: if horizontal_type == HorizontalType.Right:
return u'right' return u'right'
elif horizontal_type == Horizontal.Center: elif horizontal_type == HorizontalType.Center:
return u'center' return u'center'
else: else:
return u'left' return u'left'

View File

@ -41,40 +41,27 @@ class UiStrings(object):
# These strings should need a good reason to be retranslated elsewhere. # These strings should need a good reason to be retranslated elsewhere.
# Should some/more/less of these have an & attached? # Should some/more/less of these have an & attached?
Add = translate('OpenLP.Ui', '&Add') 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') Advanced = translate('OpenLP.Ui', 'Advanced')
AllFiles = translate('OpenLP.Ui', 'All Files') AllFiles = translate('OpenLP.Ui', 'All Files')
Authors = translate('OpenLP.Ui', 'Authors') Authors = translate('OpenLP.Ui', 'Authors')
CreateANew = unicode(translate('OpenLP.Ui', 'Create a new %s.')) CreateService = translate('OpenLP.Ui', 'Create a new service.')
Delete = translate('OpenLP.Ui', '&Delete') 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') 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') Error = translate('OpenLP.Ui', 'Error')
ExportType = unicode(translate('OpenLP.Ui', 'Export %s'))
Import = translate('OpenLP.Ui', 'Import') Import = translate('OpenLP.Ui', 'Import')
ImportType = unicode(translate('OpenLP.Ui', 'Import %s'))
LengthTime = unicode(translate('OpenLP.Ui', 'Length %s')) LengthTime = unicode(translate('OpenLP.Ui', 'Length %s'))
Live = translate('OpenLP.Ui', 'Live') Live = translate('OpenLP.Ui', 'Live')
Load = translate('OpenLP.Ui', 'Load') Load = translate('OpenLP.Ui', 'Load')
LoadANew = unicode(translate('OpenLP.Ui', 'Load a new %s.'))
New = translate('OpenLP.Ui', 'New') 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') OLPV2 = translate('OpenLP.Ui', 'OpenLP 2.0')
OpenType = unicode(translate('OpenLP.Ui', 'Open %s')) OpenService = translate('OpenLP.Ui', 'Open Service')
Preview = translate('OpenLP.Ui', 'Preview') Preview = translate('OpenLP.Ui', 'Preview')
PreviewSelect = unicode(translate('OpenLP.Ui', 'Preview the selected %s.'))
ReplaceBG = translate('OpenLP.Ui', 'Replace Background') ReplaceBG = translate('OpenLP.Ui', 'Replace Background')
ReplaceLiveBG = translate('OpenLP.Ui', 'Replace Live Background') ReplaceLiveBG = translate('OpenLP.Ui', 'Replace Live Background')
ResetBG = translate('OpenLP.Ui', 'Reset Background') ResetBG = translate('OpenLP.Ui', 'Reset Background')
ResetLiveBG = translate('OpenLP.Ui', 'Reset Live Background') ResetLiveBG = translate('OpenLP.Ui', 'Reset Live Background')
SaveType = unicode(translate('OpenLP.Ui', 'Save %s')) SaveService = translate('OpenLP.Ui', 'Save Service')
SendSelectLive = unicode(translate('OpenLP.Ui',
'Send the selected %s live.'))
Service = translate('OpenLP.Ui', 'Service') Service = translate('OpenLP.Ui', 'Service')
StartTimeCode = unicode(translate('OpenLP.Ui', 'Start %s')) StartTimeCode = unicode(translate('OpenLP.Ui', 'Start %s'))
Theme = translate('OpenLP.Ui', 'Theme') Theme = translate('OpenLP.Ui', 'Theme')

View File

@ -348,7 +348,7 @@ class MainDisplay(DisplayWidget):
""" """
Start the video at a predetermined point. Start the video at a predetermined point.
""" """
if newState == 2: if newState == Phonon.PlayingState:
self.mediaObject.seek(self.serviceItem.start_time * 1000) self.mediaObject.seek(self.serviceItem.start_time * 1000)
def isWebLoaded(self): def isWebLoaded(self):

View File

@ -319,17 +319,16 @@ class Ui_MainWindow(object):
self.themeManagerDock.setWindowTitle( self.themeManagerDock.setWindowTitle(
translate('OpenLP.MainWindow', 'Theme Manager')) translate('OpenLP.MainWindow', 'Theme Manager'))
self.FileNewItem.setText(translate('OpenLP.MainWindow', '&New')) self.FileNewItem.setText(translate('OpenLP.MainWindow', '&New'))
self.FileNewItem.setToolTip(UiStrings.NewType % UiStrings.Service) self.FileNewItem.setToolTip(UiStrings.NewService)
self.FileNewItem.setStatusTip( self.FileNewItem.setStatusTip(UiStrings.CreateService)
UiStrings.CreateANew % UiStrings.Service.toLower())
self.FileNewItem.setShortcut(translate('OpenLP.MainWindow', 'Ctrl+N')) self.FileNewItem.setShortcut(translate('OpenLP.MainWindow', 'Ctrl+N'))
self.FileOpenItem.setText(translate('OpenLP.MainWindow', '&Open')) self.FileOpenItem.setText(translate('OpenLP.MainWindow', '&Open'))
self.FileOpenItem.setToolTip(UiStrings.OpenType % UiStrings.Service) self.FileOpenItem.setToolTip(UiStrings.OpenService)
self.FileOpenItem.setStatusTip( self.FileOpenItem.setStatusTip(
translate('OpenLP.MainWindow', 'Open an existing service.')) translate('OpenLP.MainWindow', 'Open an existing service.'))
self.FileOpenItem.setShortcut(translate('OpenLP.MainWindow', 'Ctrl+O')) self.FileOpenItem.setShortcut(translate('OpenLP.MainWindow', 'Ctrl+O'))
self.FileSaveItem.setText(translate('OpenLP.MainWindow', '&Save')) self.FileSaveItem.setText(translate('OpenLP.MainWindow', '&Save'))
self.FileSaveItem.setToolTip(UiStrings.SaveType % UiStrings.Service) self.FileSaveItem.setToolTip(UiStrings.SaveService)
self.FileSaveItem.setStatusTip( self.FileSaveItem.setStatusTip(
translate('OpenLP.MainWindow', 'Save the current service to disk.')) translate('OpenLP.MainWindow', 'Save the current service to disk.'))
self.FileSaveItem.setShortcut(translate('OpenLP.MainWindow', 'Ctrl+S')) self.FileSaveItem.setShortcut(translate('OpenLP.MainWindow', 'Ctrl+S'))

View File

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

View File

@ -96,18 +96,14 @@ class ServiceManager(QtGui.QWidget):
# Create the top toolbar # Create the top toolbar
self.toolbar = OpenLPToolbar(self) self.toolbar = OpenLPToolbar(self)
self.toolbar.addToolbarButton( self.toolbar.addToolbarButton(
UiStrings.NewType % UiStrings.Service, UiStrings.NewService, u':/general/general_new.png',
u':/general/general_new.png', UiStrings.CreateService, self.onNewServiceClicked)
UiStrings.CreateANew % UiStrings.Service.toLower(),
self.onNewServiceClicked)
self.toolbar.addToolbarButton( self.toolbar.addToolbarButton(
UiStrings.OpenType % UiStrings.Service, UiStrings.OpenService, u':/general/general_open.png',
u':/general/general_open.png',
translate('OpenLP.ServiceManager', 'Load an existing service'), translate('OpenLP.ServiceManager', 'Load an existing service'),
self.onLoadServiceClicked) self.onLoadServiceClicked)
self.toolbar.addToolbarButton( self.toolbar.addToolbarButton(
UiStrings.SaveType % UiStrings.Service, UiStrings.SaveService, u':/general/general_save.png',
u':/general/general_save.png',
translate('OpenLP.ServiceManager', 'Save this service'), translate('OpenLP.ServiceManager', 'Save this service'),
self.saveFile) self.saveFile)
self.toolbar.addSeparator() self.toolbar.addSeparator()
@ -469,7 +465,7 @@ class ServiceManager(QtGui.QWidget):
save the file. save the file.
""" """
fileName = unicode(QtGui.QFileDialog.getSaveFileName(self.mainwindow, fileName = unicode(QtGui.QFileDialog.getSaveFileName(self.mainwindow,
UiStrings.SaveType % UiStrings.Service, UiStrings.SaveService,
SettingsManager.get_last_dir( SettingsManager.get_last_dir(
self.mainwindow.serviceSettingsSection), self.mainwindow.serviceSettingsSection),
translate('OpenLP.ServiceManager', 'OpenLP Service Files (*.osz)'))) translate('OpenLP.ServiceManager', 'OpenLP Service Files (*.osz)')))

View File

@ -36,7 +36,6 @@ class Ui_SettingsDialog(object):
settingsDialog.setWindowIcon( settingsDialog.setWindowIcon(
build_icon(u':/system/system_settings.png')) build_icon(u':/system/system_settings.png'))
self.settingsLayout = QtGui.QVBoxLayout(settingsDialog) self.settingsLayout = QtGui.QVBoxLayout(settingsDialog)
margins = self.settingsLayout.contentsMargins()
self.settingsLayout.setObjectName(u'settingsLayout') self.settingsLayout.setObjectName(u'settingsLayout')
self.settingsTabWidget = QtGui.QTabWidget(settingsDialog) self.settingsTabWidget = QtGui.QTabWidget(settingsDialog)
self.settingsTabWidget.setObjectName(u'settingsTabWidget') self.settingsTabWidget.setObjectName(u'settingsTabWidget')

View File

@ -36,7 +36,7 @@ class Ui_ShortcutListDialog(object):
self.treeWidget = QtGui.QTreeWidget(shortcutListDialog) self.treeWidget = QtGui.QTreeWidget(shortcutListDialog)
self.treeWidget.setAlternatingRowColors(True) self.treeWidget.setAlternatingRowColors(True)
self.treeWidget.setObjectName(u'treeWidget') self.treeWidget.setObjectName(u'treeWidget')
self.treeWidget.setColumnCount(2) self.treeWidget.setColumnCount(3)
self.dialogLayout.addWidget(self.treeWidget) self.dialogLayout.addWidget(self.treeWidget)
self.defaultButton = QtGui.QRadioButton(shortcutListDialog) self.defaultButton = QtGui.QRadioButton(shortcutListDialog)
self.defaultButton.setChecked(True) self.defaultButton.setChecked(True)
@ -78,7 +78,8 @@ class Ui_ShortcutListDialog(object):
translate('OpenLP.ShortcutListDialog', 'Customize Shortcuts')) translate('OpenLP.ShortcutListDialog', 'Customize Shortcuts'))
self.treeWidget.setHeaderLabels([ self.treeWidget.setHeaderLabels([
translate('OpenLP.ShortcutListDialog', 'Action'), translate('OpenLP.ShortcutListDialog', 'Action'),
translate('OpenLP.ShortcutListDialog', 'Shortcut')]) translate('OpenLP.ShortcutListDialog', 'Shortcut'),
translate('OpenLP.ShortcutListDialog', 'Alternate')])
self.defaultButton.setText( self.defaultButton.setText(
translate('OpenLP.ShortcutListDialog', 'Default: %s')) translate('OpenLP.ShortcutListDialog', 'Default: %s'))
self.customButton.setText( self.customButton.setText(

View File

@ -95,8 +95,13 @@ class ShortcutListForm(QtGui.QDialog, Ui_ShortcutListDialog):
item = QtGui.QTreeWidgetItem([category.name]) item = QtGui.QTreeWidgetItem([category.name])
for action in category.actions: for action in category.actions:
actionText = REMOVE_AMPERSAND.sub('', unicode(action.text())) actionText = REMOVE_AMPERSAND.sub('', unicode(action.text()))
shortcutText = action.shortcut().toString() if (len(action.shortcuts()) == 2):
actionItem = QtGui.QTreeWidgetItem([actionText, shortcutText]) shortcutText = action.shortcuts()[0].toString()
alternateText = action.shortcuts()[1].toString()
else:
shortcutText = action.shortcut().toString()
alternateText = u''
actionItem = QtGui.QTreeWidgetItem([actionText, shortcutText, alternateText])
actionItem.setIcon(0, action.icon()) actionItem.setIcon(0, action.icon())
item.addChild(actionItem) item.addChild(actionItem)
item.setExpanded(True) item.setExpanded(True)

View File

@ -380,7 +380,7 @@ class SlideController(QtGui.QWidget):
self.previousItem.setShortcuts([QtCore.Qt.Key_Up, QtCore.Qt.Key_PageUp]) self.previousItem.setShortcuts([QtCore.Qt.Key_Up, QtCore.Qt.Key_PageUp])
self.previousItem.setShortcutContext( self.previousItem.setShortcutContext(
QtCore.Qt.WidgetWithChildrenShortcut) QtCore.Qt.WidgetWithChildrenShortcut)
actionList.add_action(self.nextItem, u'Live') actionList.add_action(self.previousItem, u'Live')
self.nextItem.setShortcuts([QtCore.Qt.Key_Down, QtCore.Qt.Key_PageDown]) self.nextItem.setShortcuts([QtCore.Qt.Key_Down, QtCore.Qt.Key_PageDown])
self.nextItem.setShortcutContext(QtCore.Qt.WidgetWithChildrenShortcut) self.nextItem.setShortcutContext(QtCore.Qt.WidgetWithChildrenShortcut)
actionList.add_action(self.nextItem, u'Live') actionList.add_action(self.nextItem, u'Live')
@ -603,14 +603,15 @@ class SlideController(QtGui.QWidget):
slideHeight = 0 slideHeight = 0
if self.serviceItem.is_text(): if self.serviceItem.is_text():
if frame[u'verseTag']: if frame[u'verseTag']:
bits = frame[u'verseTag'].split(u':') # These tags are already translated.
tag = u'%s\n%s' % (bits[0][0], bits[1][0:] ) verse_def = frame[u'verseTag']
tag1 = u'%s%s' % (bits[0][0], bits[1][0:] ) verse_def = u'%s%s' % (verse_def[0].upper(), verse_def[1:])
row = tag two_line_def = u'%s\n%s' % (verse_def[0], verse_def[1:] )
row = two_line_def
if self.isLive: if self.isLive:
if tag1 not in self.slideList: if verse_def not in self.slideList:
self.slideList[tag1] = framenumber self.slideList[verse_def] = framenumber
self.songMenu.menu().addAction(tag1, self.songMenu.menu().addAction(verse_def,
self.onSongBarHandler) self.onSongBarHandler)
else: else:
row += 1 row += 1

View File

@ -483,7 +483,8 @@ class ThemeForm(QtGui.QWizard, Ui_ThemeWizard):
Background Image button pushed. Background Image button pushed.
""" """
images_filter = get_images_filter() 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, filename = QtGui.QFileDialog.getOpenFileName(self,
translate('OpenLP.ThemeForm', 'Select Image'), u'', translate('OpenLP.ThemeForm', 'Select Image'), u'',
images_filter) images_filter)

View File

@ -63,28 +63,28 @@ class ThemeManager(QtGui.QWidget):
self.layout.setObjectName(u'layout') self.layout.setObjectName(u'layout')
self.toolbar = OpenLPToolbar(self) self.toolbar = OpenLPToolbar(self)
self.toolbar.addToolbarButton( self.toolbar.addToolbarButton(
UiStrings.NewType % UiStrings.Theme, translate('OpenLP.ThemeManager', 'New Theme'),
u':/themes/theme_new.png', u':/themes/theme_new.png',
UiStrings.CreateANew % UiStrings.Theme.toLower(), translate('OpenLP.ThemeManager', 'Create a new theme.'),
self.onAddTheme) self.onAddTheme)
self.toolbar.addToolbarButton( self.toolbar.addToolbarButton(
UiStrings.EditType % UiStrings.Theme, translate('OpenLP.ThemeManager', 'Edit Theme'),
u':/themes/theme_edit.png', u':/themes/theme_edit.png',
translate('OpenLP.ThemeManager', 'Edit a theme.'), translate('OpenLP.ThemeManager', 'Edit a theme.'),
self.onEditTheme) self.onEditTheme)
self.deleteToolbarAction = self.toolbar.addToolbarButton( self.deleteToolbarAction = self.toolbar.addToolbarButton(
UiStrings.DeleteType % UiStrings.Theme, translate('OpenLP.ThemeManager', 'Delete Theme'),
u':/general/general_delete.png', u':/general/general_delete.png',
translate('OpenLP.ThemeManager', 'Delete a theme.'), translate('OpenLP.ThemeManager', 'Delete a theme.'),
self.onDeleteTheme) self.onDeleteTheme)
self.toolbar.addSeparator() self.toolbar.addSeparator()
self.toolbar.addToolbarButton( self.toolbar.addToolbarButton(
UiStrings.ImportType % UiStrings.Theme, translate('OpenLP.ThemeManager', 'Import Theme'),
u':/general/general_import.png', u':/general/general_import.png',
translate('OpenLP.ThemeManager', 'Import a theme.'), translate('OpenLP.ThemeManager', 'Import a theme.'),
self.onImportTheme) self.onImportTheme)
self.toolbar.addToolbarButton( self.toolbar.addToolbarButton(
UiStrings.ExportType % UiStrings.Theme, translate('OpenLP.ThemeManager', 'Export Theme'),
u':/general/general_export.png', u':/general/general_export.png',
translate('OpenLP.ThemeManager', 'Export a theme.'), translate('OpenLP.ThemeManager', 'Export a theme.'),
self.onExportTheme) self.onExportTheme)
@ -314,7 +314,6 @@ class ThemeManager(QtGui.QWidget):
translate('OpenLP.ThemeManager', translate('OpenLP.ThemeManager',
'You must select a theme to edit.')): 'You must select a theme to edit.')):
item = self.themeListWidget.currentItem() item = self.themeListWidget.currentItem()
themeName = unicode(item.text())
theme = self.getThemeData( theme = self.getThemeData(
unicode(item.data(QtCore.Qt.UserRole).toString())) unicode(item.data(QtCore.Qt.UserRole).toString()))
if theme.background_type == u'image': if theme.background_type == u'image':
@ -406,8 +405,8 @@ class ThemeManager(QtGui.QWidget):
files = QtGui.QFileDialog.getOpenFileNames(self, files = QtGui.QFileDialog.getOpenFileNames(self,
translate('OpenLP.ThemeManager', 'Select Theme Import File'), translate('OpenLP.ThemeManager', 'Select Theme Import File'),
SettingsManager.get_last_dir(self.settingsSection), SettingsManager.get_last_dir(self.settingsSection),
translate('OpenLP.ThemeManager', 'Theme v1 (*.theme);;' unicode(translate('OpenLP.ThemeManager',
'Theme v2 (*.otz);;%s (*.*)') % UiStrings.AllFiles) 'OpenLP Themes (*.theme *.otz)')))
log.info(u'New Themes %s', unicode(files)) log.info(u'New Themes %s', unicode(files))
if files: if files:
for file in files: for file in files:
@ -530,6 +529,18 @@ class ThemeManager(QtGui.QWidget):
else: else:
outfile = open(fullpath, u'wb') outfile = open(fullpath, u'wb')
outfile.write(zip.read(file)) outfile.write(zip.read(file))
except (IOError, NameError):
critical_error_message_box(
translate('OpenLP.ThemeManager', 'Validation Error'),
translate('OpenLP.ThemeManager', 'File is not a valid theme.'))
log.exception(u'Importing theme from zip failed %s' % filename)
finally:
# Close the files, to be able to continue creating the theme.
if zip:
zip.close()
if outfile:
outfile.close()
# As all files are closed, we can create the Theme.
if filexml: if filexml:
theme = self._createThemeFromXml(filexml, self.path) theme = self._createThemeFromXml(filexml, self.path)
self.generateAndSaveImage(dir, themename, theme) self.generateAndSaveImage(dir, themename, theme)
@ -540,17 +551,6 @@ class ThemeManager(QtGui.QWidget):
'File is not a valid theme.')) 'File is not a valid theme.'))
log.exception(u'Theme file does not contain XML data %s' % log.exception(u'Theme file does not contain XML data %s' %
filename) filename)
except (IOError, NameError):
critical_error_message_box(
translate('OpenLP.ThemeManager', 'Validation Error'),
translate('OpenLP.ThemeManager',
'File is not a valid theme.'))
log.exception(u'Importing theme from zip failed %s' % filename)
finally:
if zip:
zip.close()
if outfile:
outfile.close()
def checkIfThemeExists(self, themeName): def checkIfThemeExists(self, themeName):
""" """

View File

@ -164,27 +164,34 @@ def _get_os_dir_path(dir_type):
""" """
Return a path based on which OS and environment we are running in. Return a path based on which OS and environment we are running in.
""" """
encoding = sys.getfilesystemencoding()
if sys.platform == u'win32': if sys.platform == u'win32':
if dir_type == AppLocation.DataDir: if dir_type == AppLocation.DataDir:
return os.path.join(os.getenv(u'APPDATA'), u'openlp', u'data') return os.path.join(unicode(os.getenv(u'APPDATA'), encoding),
return os.path.join(os.getenv(u'APPDATA'), u'openlp') u'openlp', u'data')
return os.path.join(unicode(os.getenv(u'APPDATA'), encoding),
u'openlp')
elif sys.platform == u'darwin': elif sys.platform == u'darwin':
if dir_type == AppLocation.DataDir: if dir_type == AppLocation.DataDir:
return os.path.join(os.getenv(u'HOME'), u'Library', return os.path.join(unicode(os.getenv(u'HOME'), encoding),
u'Application Support', u'openlp', u'Data') u'Library', u'Application Support', u'openlp', u'Data')
return os.path.join(os.getenv(u'HOME'), u'Library', return os.path.join(unicode(os.getenv(u'HOME'), encoding),
u'Application Support', u'openlp') u'Library', u'Application Support', u'openlp')
else: else:
if XDG_BASE_AVAILABLE: if XDG_BASE_AVAILABLE:
if dir_type == AppLocation.ConfigDir: if dir_type == AppLocation.ConfigDir:
return os.path.join(BaseDirectory.xdg_config_home, u'openlp') return os.path.join(unicode(BaseDirectory.xdg_config_home,
encoding), u'openlp')
elif dir_type == AppLocation.DataDir: elif dir_type == AppLocation.DataDir:
return os.path.join(BaseDirectory.xdg_data_home, u'openlp') return os.path.join(
unicode(BaseDirectory.xdg_data_home, encoding), u'openlp')
elif dir_type == AppLocation.CacheDir: elif dir_type == AppLocation.CacheDir:
return os.path.join(BaseDirectory.xdg_cache_home, u'openlp') return os.path.join(unicode(BaseDirectory.xdg_cache_home,
encoding), u'openlp')
if dir_type == AppLocation.DataDir: if dir_type == AppLocation.DataDir:
return os.path.join(os.getenv(u'HOME'), u'.openlp', u'data') return os.path.join(unicode(os.getenv(u'HOME'), encoding),
return os.path.join(os.getenv(u'HOME'), u'.openlp') u'.openlp', u'data')
return os.path.join(unicode(os.getenv(u'HOME'), encoding), u'.openlp')
def _get_frozen_path(frozen_option, non_frozen_option): def _get_frozen_path(frozen_option, non_frozen_option):
""" """
@ -375,13 +382,13 @@ def get_uno_command():
""" """
Returns the UNO command to launch an openoffice.org instance. Returns the UNO command to launch an openoffice.org instance.
""" """
COMMAND = u'soffice'
OPTIONS = u'-nologo -norestore -minimized -invisible -nofirststartwizard'
if UNO_CONNECTION_TYPE == u'pipe': if UNO_CONNECTION_TYPE == u'pipe':
return u'openoffice.org -nologo -norestore -minimized -invisible ' \ CONNECTION = u'"-accept=pipe,name=openlp_pipe;urp;"'
+ u'-nofirststartwizard -accept=pipe,name=openlp_pipe;urp;'
else: else:
return u'openoffice.org -nologo -norestore -minimized ' \ CONNECTION = u'"-accept=socket,host=localhost,port=2002;urp;"'
+ u'-invisible -nofirststartwizard ' \ return u'%s %s %s' % (COMMAND, OPTIONS, CONNECTION)
+ u'-accept=socket,host=localhost,port=2002;urp;'
def get_uno_instance(resolver): def get_uno_instance(resolver):
""" """

View File

@ -29,7 +29,6 @@ import logging
from PyQt4 import QtCore, QtGui from PyQt4 import QtCore, QtGui
from openlp.core.lib import Plugin, StringContent, build_icon, translate from openlp.core.lib import Plugin, StringContent, build_icon, translate
from openlp.core.lib.ui import UiStrings
from openlp.plugins.bibles.lib import BibleManager, BiblesTab, BibleMediaItem from openlp.plugins.bibles.lib import BibleManager, BiblesTab, BibleMediaItem
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -129,9 +128,15 @@ class BiblePlugin(Plugin):
u'title': translate('BiblesPlugin', 'Bibles', 'container title') u'title': translate('BiblesPlugin', 'Bibles', 'container title')
} }
# Middle Header Bar # Middle Header Bar
## Import Action ## tooltips = {
self.textStrings[StringContent.Import] = { u'load': u'',
u'title': UiStrings.Import, u'import': translate('BiblesPlugin', 'Import a Bible'),
u'tooltip': 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

@ -30,6 +30,7 @@ from PyQt4 import QtCore, QtGui
from openlp.core.lib import MediaManagerItem, Receiver, ItemCapabilities, \ from openlp.core.lib import MediaManagerItem, Receiver, ItemCapabilities, \
translate translate
from openlp.core.lib.searchedit import SearchEdit
from openlp.core.lib.ui import UiStrings, add_widget_completer, \ from openlp.core.lib.ui import UiStrings, add_widget_completer, \
media_item_combo_box, critical_error_message_box media_item_combo_box, critical_error_message_box
from openlp.plugins.bibles.forms import BibleImportForm from openlp.plugins.bibles.forms import BibleImportForm
@ -37,6 +38,14 @@ from openlp.plugins.bibles.lib import get_reference_match
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
class BibleSearch(object):
"""
Enumeration class for the different search methods for the "quick search".
"""
Reference = 1
Text = 2
class BibleMediaItem(MediaManagerItem): class BibleMediaItem(MediaManagerItem):
""" """
This is the custom media manager item for Bibles. This is the custom media manager item for Bibles.
@ -83,18 +92,17 @@ class BibleMediaItem(MediaManagerItem):
u'quickSecondComboBox') u'quickSecondComboBox')
self.quickSecondLabel.setBuddy(self.quickSecondComboBox) self.quickSecondLabel.setBuddy(self.quickSecondComboBox)
self.quickLayout.addRow(self.quickSecondLabel, 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 = QtGui.QLabel(self.quickTab)
self.quickSearchLabel.setObjectName(u'quickSearchLabel') self.quickSearchLabel.setObjectName(u'quickSearchLabel')
self.quickSearchEdit = QtGui.QLineEdit(self.quickTab) self.quickSearchEdit = SearchEdit(self.quickTab)
self.quickSearchEdit.setObjectName(u'quickSearchEdit') self.quickSearchEdit.setObjectName(u'quickSearchEdit')
self.quickSearchLabel.setBuddy(self.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.quickLayout.addRow(self.quickSearchLabel, self.quickSearchEdit)
self.quickClearLabel = QtGui.QLabel(self.quickTab) self.quickClearLabel = QtGui.QLabel(self.quickTab)
self.quickClearLabel.setObjectName(u'quickClearLabel') self.quickClearLabel.setObjectName(u'quickClearLabel')
@ -196,8 +204,8 @@ class BibleMediaItem(MediaManagerItem):
QtCore.SIGNAL(u'activated(int)'), self.onAdvancedFromVerse) QtCore.SIGNAL(u'activated(int)'), self.onAdvancedFromVerse)
QtCore.QObject.connect(self.advancedToChapter, QtCore.QObject.connect(self.advancedToChapter,
QtCore.SIGNAL(u'activated(int)'), self.onAdvancedToChapter) QtCore.SIGNAL(u'activated(int)'), self.onAdvancedToChapter)
QtCore.QObject.connect(self.quickSearchComboBox, QtCore.QObject.connect(self.quickSearchEdit,
QtCore.SIGNAL(u'activated(int)'), self.updateAutoCompleter) QtCore.SIGNAL(u'searchTypeChanged(int)'), self.updateAutoCompleter)
QtCore.QObject.connect(self.quickVersionComboBox, QtCore.QObject.connect(self.quickVersionComboBox,
QtCore.SIGNAL(u'activated(int)'), self.updateAutoCompleter) QtCore.SIGNAL(u'activated(int)'), self.updateAutoCompleter)
# Buttons # Buttons
@ -231,8 +239,6 @@ class BibleMediaItem(MediaManagerItem):
translate('BiblesPlugin.MediaItem', 'Version:')) translate('BiblesPlugin.MediaItem', 'Version:'))
self.quickSecondLabel.setText( self.quickSecondLabel.setText(
translate('BiblesPlugin.MediaItem', 'Second:')) translate('BiblesPlugin.MediaItem', 'Second:'))
self.quickSearchTypeLabel.setText(
translate('BiblesPlugin.MediaItem', 'Search type:'))
self.quickSearchLabel.setText( self.quickSearchLabel.setText(
translate('BiblesPlugin.MediaItem', 'Find:')) translate('BiblesPlugin.MediaItem', 'Find:'))
self.quickSearchButton.setText( self.quickSearchButton.setText(
@ -257,10 +263,6 @@ class BibleMediaItem(MediaManagerItem):
translate('BiblesPlugin.MediaItem', 'Results:')) translate('BiblesPlugin.MediaItem', 'Results:'))
self.advancedSearchButton.setText( self.advancedSearchButton.setText(
translate('BiblesPlugin.MediaItem', 'Search')) translate('BiblesPlugin.MediaItem', 'Search'))
self.quickSearchComboBox.addItem(
translate('BiblesPlugin.MediaItem', 'Verse Search'))
self.quickSearchComboBox.addItem(
translate('BiblesPlugin.MediaItem', 'Text Search'))
self.quickClearComboBox.addItem( self.quickClearComboBox.addItem(
translate('BiblesPlugin.MediaItem', 'Clear')) translate('BiblesPlugin.MediaItem', 'Clear'))
self.quickClearComboBox.addItem( self.quickClearComboBox.addItem(
@ -358,11 +360,11 @@ class BibleMediaItem(MediaManagerItem):
""" """
This updates the bible book completion list for the search field. The 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 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 = [] books = []
# We have to do a 'Verse Search'. # We have to do a 'Reference Search'.
if self.quickSearchComboBox.currentIndex() == 0: if self.quickSearchEdit.currentSearchType() == BibleSearch.Reference:
bibles = self.parent.manager.get_bibles() bibles = self.parent.manager.get_bibles()
bible = unicode(self.quickVersionComboBox.currentText()) bible = unicode(self.quickVersionComboBox.currentText())
if bible: if bible:
@ -491,7 +493,7 @@ class BibleMediaItem(MediaManagerItem):
def onQuickSearchButton(self): def onQuickSearchButton(self):
""" """
Does a quick search and saves the search results. Quick search can 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') log.debug(u'Quick Search Button pressed')
self.quickSearchButton.setEnabled(False) self.quickSearchButton.setEnabled(False)
@ -499,8 +501,8 @@ class BibleMediaItem(MediaManagerItem):
bible = unicode(self.quickVersionComboBox.currentText()) bible = unicode(self.quickVersionComboBox.currentText())
second_bible = unicode(self.quickSecondComboBox.currentText()) second_bible = unicode(self.quickSecondComboBox.currentText())
text = unicode(self.quickSearchEdit.text()) text = unicode(self.quickSearchEdit.text())
if self.quickSearchComboBox.currentIndex() == 0: if self.quickSearchEdit.currentSearchType() == BibleSearch.Reference:
# We are doing a 'Verse Search'. # We are doing a 'Reference Search'.
self.search_results = self.parent.manager.get_verses(bible, text) self.search_results = self.parent.manager.get_verses(bible, text)
if second_bible and self.search_results: if second_bible and self.search_results:
self.second_search_results = self.parent.manager.get_verses( self.second_search_results = self.parent.manager.get_verses(

View File

@ -30,7 +30,6 @@ from forms import EditCustomForm
from openlp.core.lib import Plugin, StringContent, build_icon, translate from openlp.core.lib import Plugin, StringContent, build_icon, translate
from openlp.core.lib.db import Manager from openlp.core.lib.db import Manager
from openlp.core.lib.ui import UiStrings
from openlp.plugins.custom.lib import CustomMediaItem, CustomTab from openlp.plugins.custom.lib import CustomMediaItem, CustomTab
from openlp.plugins.custom.lib.db import CustomSlide, init_schema from openlp.plugins.custom.lib.db import CustomSlide, init_schema
@ -106,13 +105,20 @@ class CustomPlugin(Plugin):
u'title': translate('CustomsPlugin', 'Custom', 'container title') u'title': translate('CustomsPlugin', 'Custom', 'container title')
} }
# Middle Header Bar # Middle Header Bar
## Import Action ## tooltips = {
self.textStrings[StringContent.Import] = { u'load': translate('CustomsPlugin', 'Load a new Custom'),
u'title': UiStrings.Import, u'import': translate('CustomsPlugin', 'Import a Custom'),
u'tooltip': translate('CustomsPlugin', u'new': translate('CustomsPlugin', 'Add a new Custom'),
'Import a 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): def finalise(self):
""" """

View File

@ -69,4 +69,15 @@ class ImagePlugin(Plugin):
u'title': translate('ImagePlugin', 'Images', 'container title') u'title': translate('ImagePlugin', 'Images', 'container title')
} }
# Middle Header Bar # 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

@ -32,6 +32,7 @@ from PyQt4 import QtCore, QtGui
from openlp.core.lib import MediaManagerItem, build_icon, ItemCapabilities, \ from openlp.core.lib import MediaManagerItem, build_icon, ItemCapabilities, \
SettingsManager, translate, check_item_selected, Receiver SettingsManager, translate, check_item_selected, Receiver
from openlp.core.lib.ui import UiStrings, critical_error_message_box from openlp.core.lib.ui import UiStrings, critical_error_message_box
from PyQt4.phonon import Phonon
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -48,9 +49,13 @@ class MediaMediaItem(MediaManagerItem):
u':/media/media_video.png').toImage() u':/media/media_video.png').toImage()
MediaManagerItem.__init__(self, parent, self, icon) MediaManagerItem.__init__(self, parent, self, icon)
self.singleServiceItem = False self.singleServiceItem = False
self.mediaObject = Phonon.MediaObject(self)
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'video_background_replaced'), QtCore.SIGNAL(u'video_background_replaced'),
self.videobackgroundReplaced) self.videobackgroundReplaced)
QtCore.QObject.connect(self.mediaObject,
QtCore.SIGNAL(u'stateChanged(Phonon::State, Phonon::State)'),
self.videoStart)
def retranslateUi(self): def retranslateUi(self):
self.OnNewPrompt = translate('MediaPlugin.MediaItem', 'Select Media') self.OnNewPrompt = translate('MediaPlugin.MediaItem', 'Select Media')
@ -120,6 +125,11 @@ class MediaMediaItem(MediaManagerItem):
return False return False
filename = unicode(item.data(QtCore.Qt.UserRole).toString()) filename = unicode(item.data(QtCore.Qt.UserRole).toString())
if os.path.exists(filename): 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( service_item.title = unicode(
translate('MediaPlugin.MediaItem', 'Media')) translate('MediaPlugin.MediaItem', 'Media'))
service_item.add_capability(ItemCapabilities.RequiresMedia) service_item.add_capability(ItemCapabilities.RequiresMedia)
@ -128,6 +138,9 @@ class MediaMediaItem(MediaManagerItem):
service_item.theme = -1 service_item.theme = -1
frame = u':/media/image_clapperboard.png' frame = u':/media/image_clapperboard.png'
(path, name) = os.path.split(filename) (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) service_item.add_from_command(path, name, frame)
return True return True
else: else:
@ -165,3 +178,12 @@ class MediaMediaItem(MediaManagerItem):
item_name.setIcon(build_icon(img)) item_name.setIcon(build_icon(img))
item_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(file)) item_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(file))
self.listView.addItem(item_name) 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

@ -95,4 +95,15 @@ class MediaPlugin(Plugin):
u'title': translate('MediaPlugin', 'Media', 'container title') u'title': translate('MediaPlugin', 'Media', 'container title')
} }
# Middle Header Bar # 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

@ -147,8 +147,10 @@ class PowerpointDocument(PresentationDocument):
""" """
if self.check_thumbnails(): if self.check_thumbnails():
return return
self.presentation.Export(os.path.join(self.get_thumbnail_folder(), ''), for num in range(0, self.presentation.Slides.Count):
'png', 320, 240) self.presentation.Slides(num + 1).Export(os.path.join(
self.get_thumbnail_folder(), 'slide%d.png' % (num + 1)),
'png', 320, 240)
def close_presentation(self): def close_presentation(self):
""" """

View File

@ -154,8 +154,9 @@ class PptviewDocument(PresentationDocument):
being shut down being shut down
""" """
log.debug(u'ClosePresentation') log.debug(u'ClosePresentation')
self.controller.process.ClosePPT(self.pptid) if self.controller.process:
self.pptid = -1 self.controller.process.ClosePPT(self.pptid)
self.pptid = -1
self.controller.remove_doc(self) self.controller.remove_doc(self)
def is_loaded(self): def is_loaded(self):

View File

@ -167,4 +167,18 @@ class PresentationPlugin(Plugin):
'container title') 'container title')
} }
# Middle Header Bar # 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

@ -161,6 +161,7 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
def newSong(self): def newSong(self):
log.debug(u'New Song') log.debug(u'New Song')
self.song = None
self.initialise() self.initialise()
self.songTabWidget.setCurrentIndex(0) self.songTabWidget.setCurrentIndex(0)
self.titleEdit.setText(u'') self.titleEdit.setText(u'')
@ -226,10 +227,6 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
self.copyrightEdit.setText(u'') self.copyrightEdit.setText(u'')
self.verseListWidget.clear() self.verseListWidget.clear()
self.verseListWidget.setRowCount(0) self.verseListWidget.setRowCount(0)
if self.song.verse_order:
self.verseOrderEdit.setText(self.song.verse_order)
else:
self.verseOrderEdit.setText(u'')
if self.song.comments: if self.song.comments:
self.commentsEdit.setPlainText(self.song.comments) self.commentsEdit.setPlainText(self.song.comments)
else: else:
@ -249,15 +246,31 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
# This is just because occasionally the lyrics come back as a "buffer" # This is just because occasionally the lyrics come back as a "buffer"
if isinstance(self.song.lyrics, buffer): if isinstance(self.song.lyrics, buffer):
self.song.lyrics = unicode(self.song.lyrics) self.song.lyrics = unicode(self.song.lyrics)
verse_tags_translated = False
if self.song.lyrics.startswith(u'<?xml version='): if self.song.lyrics.startswith(u'<?xml version='):
songXML = SongXML() songXML = SongXML()
verseList = songXML.get_verses(self.song.lyrics) verseList = songXML.get_verses(self.song.lyrics)
for count, verse in enumerate(verseList): for count, verse in enumerate(verseList):
self.verseListWidget.setRowCount( self.verseListWidget.setRowCount(
self.verseListWidget.rowCount() + 1) self.verseListWidget.rowCount() + 1)
variant = u'%s:%s' % (verse[0][u'type'], verse[0][u'label']) # This silently migrates from localized verse type markup.
# If we trusted the database, this would be unnecessary.
verse_tag = verse[0][u'type']
index = None
if len(verse_tag) > 1:
index = VerseType.from_translated_string(verse_tag)
if index is None:
index = VerseType.from_string(verse_tag)
else:
verse_tags_translated = True
if index is None:
index = VerseType.from_tag(verse_tag)
if index is None:
index = VerseType.Other
verse[0][u'type'] = VerseType.Tags[index]
verse_def = u'%s%s' % (verse[0][u'type'], verse[0][u'label'])
item = QtGui.QTableWidgetItem(verse[1]) item = QtGui.QTableWidgetItem(verse[1])
item.setData(QtCore.Qt.UserRole, QtCore.QVariant(variant)) item.setData(QtCore.Qt.UserRole, QtCore.QVariant(verse_def))
self.verseListWidget.setItem(count, 0, item) self.verseListWidget.setItem(count, 0, item)
else: else:
verses = self.song.lyrics.split(u'\n\n') verses = self.song.lyrics.split(u'\n\n')
@ -265,10 +278,24 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
self.verseListWidget.setRowCount( self.verseListWidget.setRowCount(
self.verseListWidget.rowCount() + 1) self.verseListWidget.rowCount() + 1)
item = QtGui.QTableWidgetItem(verse) item = QtGui.QTableWidgetItem(verse)
variant = u'%s:%s' % \ verse_def = u'%s%s' % \
(VerseType.to_string(VerseType.Verse), unicode(count + 1)) (VerseType.Tags[VerseType.Verse], unicode(count + 1))
item.setData(QtCore.Qt.UserRole, QtCore.QVariant(variant)) item.setData(QtCore.Qt.UserRole, QtCore.QVariant(verse_def))
self.verseListWidget.setItem(count, 0, item) self.verseListWidget.setItem(count, 0, item)
if self.song.verse_order:
# we translate verse order
translated = []
for verse_def in self.song.verse_order.split():
verse_index = None
if verse_tags_translated:
verse_index = VerseType.from_translated_tag(verse_def[0])
if verse_index is None:
verse_index = VerseType.from_tag(verse_def[0])
verse_tag = VerseType.TranslatedTags[verse_index].upper()
translated.append(u'%s%s' % (verse_tag, verse_def[1:]))
self.verseOrderEdit.setText(u' '.join(translated))
else:
self.verseOrderEdit.setText(u'')
self.verseListWidget.resizeRowsToContents() self.verseListWidget.resizeRowsToContents()
self.tagRows() self.tagRows()
# clear the results # clear the results
@ -293,14 +320,14 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
""" """
Tag the Song List rows based on the verse list Tag the Song List rows based on the verse list
""" """
rowLabel = [] row_label = []
for row in range(0, self.verseListWidget.rowCount()): for row in range(0, self.verseListWidget.rowCount()):
item = self.verseListWidget.item(row, 0) item = self.verseListWidget.item(row, 0)
data = unicode(item.data(QtCore.Qt.UserRole).toString()) verse_def = unicode(item.data(QtCore.Qt.UserRole).toString())
bit = data.split(u':') verse_tag = VerseType.translated_tag(verse_def[0])
rowTag = u'%s%s' % (bit[0][0:1], bit[1]) row_def = u'%s%s' % (verse_tag, verse_def[1:])
rowLabel.append(rowTag) row_label.append(row_def)
self.verseListWidget.setVerticalHeaderLabels(rowLabel) self.verseListWidget.setVerticalHeaderLabels(row_label)
def onAuthorAddButtonClicked(self): def onAuthorAddButtonClicked(self):
item = int(self.authorsComboBox.currentIndex()) item = int(self.authorsComboBox.currentIndex())
@ -419,11 +446,11 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
def onVerseAddButtonClicked(self): def onVerseAddButtonClicked(self):
self.verse_form.setVerse(u'', True) self.verse_form.setVerse(u'', True)
if self.verse_form.exec_(): if self.verse_form.exec_():
afterText, verse, subVerse = self.verse_form.getVerse() after_text, verse_tag, verse_num = self.verse_form.getVerse()
data = u'%s:%s' % (verse, subVerse) verse_def = u'%s%s' % (verse_tag, verse_num)
item = QtGui.QTableWidgetItem(afterText) item = QtGui.QTableWidgetItem(after_text)
item.setData(QtCore.Qt.UserRole, QtCore.QVariant(data)) item.setData(QtCore.Qt.UserRole, QtCore.QVariant(verse_def))
item.setText(afterText) item.setText(after_text)
self.verseListWidget.setRowCount( self.verseListWidget.setRowCount(
self.verseListWidget.rowCount() + 1) self.verseListWidget.rowCount() + 1)
self.verseListWidget.setItem( self.verseListWidget.setItem(
@ -439,12 +466,12 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
verseId = unicode(item.data(QtCore.Qt.UserRole).toString()) verseId = unicode(item.data(QtCore.Qt.UserRole).toString())
self.verse_form.setVerse(tempText, True, verseId) self.verse_form.setVerse(tempText, True, verseId)
if self.verse_form.exec_(): if self.verse_form.exec_():
afterText, verse, subVerse = self.verse_form.getVerse() after_text, verse_tag, verse_num = self.verse_form.getVerse()
data = u'%s:%s' % (verse, subVerse) verse_def = u'%s%s' % (verse_tag, verse_num)
item.setData(QtCore.Qt.UserRole, QtCore.QVariant(data)) item.setData(QtCore.Qt.UserRole, QtCore.QVariant(verse_def))
item.setText(afterText) item.setText(after_text)
# number of lines has change so repaint the list moving the data # number of lines has change so repaint the list moving the data
if len(tempText.split(u'\n')) != len(afterText.split(u'\n')): if len(tempText.split(u'\n')) != len(after_text.split(u'\n')):
tempList = {} tempList = {}
tempId = {} tempId = {}
for row in range(0, self.verseListWidget.rowCount()): for row in range(0, self.verseListWidget.rowCount()):
@ -466,7 +493,9 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
for row in range(0, self.verseListWidget.rowCount()): for row in range(0, self.verseListWidget.rowCount()):
item = self.verseListWidget.item(row, 0) item = self.verseListWidget.item(row, 0)
field = unicode(item.data(QtCore.Qt.UserRole).toString()) field = unicode(item.data(QtCore.Qt.UserRole).toString())
verse_list += u'---[%s]---\n' % field verse_tag = VerseType.translated_name(field[0])
verse_num = field[1:]
verse_list += u'---[%s:%s]---\n' % (verse_tag, verse_num)
verse_list += item.text() verse_list += item.text()
verse_list += u'\n' verse_list += u'\n'
self.verse_form.setVerse(verse_list) self.verse_form.setVerse(verse_list)
@ -482,15 +511,32 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
for count, parts in enumerate(match.split(u']---\n')): for count, parts in enumerate(match.split(u']---\n')):
if len(parts) > 1: if len(parts) > 1:
if count == 0: if count == 0:
# make sure the tag is correctly cased # handling carefully user inputted versetags
variant = u'%s%s' % \ separator = parts.find(u':')
(parts[0:1].upper(), parts[1:].lower()) if separator >= 0:
verse_name = parts[0:separator].strip()
verse_num = parts[separator+1:].strip()
else:
verse_name = parts
verse_num = u'1'
verse_index = \
VerseType.from_loose_input(verse_name)
verse_tag = VerseType.Tags[verse_index]
# Later we need to handle v1a as well.
#regex = re.compile(r'(\d+\w.)')
regex = re.compile(r'\D*(\d+)\D*')
match = regex.match(verse_num)
if match:
verse_num = match.group(1)
else:
verse_num = u'1'
verse_def = u'%s%s' % (verse_tag, verse_num)
else: else:
if parts.endswith(u'\n'): if parts.endswith(u'\n'):
parts = parts.rstrip(u'\n') parts = parts.rstrip(u'\n')
item = QtGui.QTableWidgetItem(parts) item = QtGui.QTableWidgetItem(parts)
item.setData(QtCore.Qt.UserRole, item.setData(QtCore.Qt.UserRole,
QtCore.QVariant(variant)) QtCore.QVariant(verse_def))
self.verseListWidget.setRowCount( self.verseListWidget.setRowCount(
self.verseListWidget.rowCount() + 1) self.verseListWidget.rowCount() + 1)
self.verseListWidget.setItem( self.verseListWidget.setItem(
@ -542,25 +588,31 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
order_names = unicode(self.verseOrderEdit.text()).split() order_names = unicode(self.verseOrderEdit.text()).split()
for item in order_names: for item in order_names:
if len(item) == 1: if len(item) == 1:
order.append(item.lower() + u'1') verse_index = VerseType.from_translated_tag(item)
if verse_index is not None:
order.append(VerseType.Tags[verse_index] + u'1')
else:
order.append(u'') # it matches no verses anyway
else: else:
order.append(item.lower()) verse_index = VerseType.from_translated_tag(item[0])
if verse_index is None:
order.append(u'') # same as above
else:
verse_tag = VerseType.Tags[verse_index]
verse_num = item[1:].lower()
order.append(verse_tag + verse_num)
verses = [] verses = []
verse_names = [] verse_names = []
for index in range (0, self.verseListWidget.rowCount()): for index in range(0, self.verseListWidget.rowCount()):
verse = self.verseListWidget.item(index, 0) verse = self.verseListWidget.item(index, 0)
verse = unicode(verse.data(QtCore.Qt.UserRole).toString()) verse = unicode(verse.data(QtCore.Qt.UserRole).toString())
if verse not in verse_names: if verse not in verse_names:
verses.append( verses.append(verse)
re.sub(r'(.)[^:]*:(.*)', r'\1\2', verse.lower())) verse_names.append(u'%s%s' % (
verse_names.append(verse) VerseType.translated_tag(verse[0]), verse[1:]))
for count, item in enumerate(order): for count, item in enumerate(order):
if item not in verses: if item not in verses:
self.songTabWidget.setCurrentIndex(0) valid = u', '.join(verse_names)
self.verseOrderEdit.setFocus()
valid = verses.pop(0)
for verse in verses:
valid = valid + u', ' + verse
critical_error_message_box( critical_error_message_box(
message=unicode(translate('SongsPlugin.EditSongForm', message=unicode(translate('SongsPlugin.EditSongForm',
'The verse order is invalid. There is no verse ' 'The verse order is invalid. There is no verse '
@ -576,7 +628,7 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
unicode(translate('SongsPlugin.EditSongForm', unicode(translate('SongsPlugin.EditSongForm',
'You have not used %s anywhere in the verse ' 'You have not used %s anywhere in the verse '
'order. Are you sure you want to save the song ' 'order. Are you sure you want to save the song '
'like this?')) % verse_names[count].replace(u':', u' '), 'like this?')) % verse_names[count],
QtGui.QMessageBox.Yes | QtGui.QMessageBox.No) QtGui.QMessageBox.Yes | QtGui.QMessageBox.No)
if answer == QtGui.QMessageBox.No: if answer == QtGui.QMessageBox.No:
return False return False
@ -683,7 +735,14 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
else: else:
self.song.search_title = self.song.title self.song.search_title = self.song.title
self.song.comments = unicode(self.commentsEdit.toPlainText()) self.song.comments = unicode(self.commentsEdit.toPlainText())
self.song.verse_order = unicode(self.verseOrderEdit.text()) ordertext = unicode(self.verseOrderEdit.text())
order = []
for item in ordertext.split():
verse_tag = VerseType.Tags[
VerseType.from_translated_tag(item[0])]
verse_num = item[1:].lower()
order.append(u'%s%s' % (verse_tag, verse_num))
self.song.verse_order = u' '.join(order)
self.song.ccli_number = unicode(self.CCLNumberEdit.text()) self.song.ccli_number = unicode(self.CCLNumberEdit.text())
self.song.song_number = unicode(self.songBookNumberEdit.text()) self.song.song_number = unicode(self.songBookNumberEdit.text())
book_name = unicode(self.songBookComboBox.currentText()) book_name = unicode(self.songBookComboBox.currentText())
@ -726,12 +785,14 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
for i in range(0, self.verseListWidget.rowCount()): for i in range(0, self.verseListWidget.rowCount()):
item = self.verseListWidget.item(i, 0) item = self.verseListWidget.item(i, 0)
verseId = unicode(item.data(QtCore.Qt.UserRole).toString()) verseId = unicode(item.data(QtCore.Qt.UserRole).toString())
bits = verseId.split(u':') verse_tag = verseId[0]
sxml.add_verse_to_lyrics(bits[0], bits[1], unicode(item.text())) verse_num = verseId[1:]
sxml.add_verse_to_lyrics(verse_tag, verse_num,
unicode(item.text()))
text = text + self.whitespace.sub(u' ', text = text + self.whitespace.sub(u' ',
unicode(self.verseListWidget.item(i, 0).text())) + u' ' unicode(self.verseListWidget.item(i, 0).text())) + u' '
if (bits[1] > u'1') and (bits[0][0] not in multiple): if (verse_num > u'1') and (verse_tag not in multiple):
multiple.append(bits[0][0]) multiple.append(verse_tag)
self.song.search_lyrics = text.lower() self.song.search_lyrics = text.lower()
self.song.lyrics = unicode(sxml.extract_xml(), u'utf-8') self.song.lyrics = unicode(sxml.extract_xml(), u'utf-8')
for verse in multiple: for verse in multiple:

View File

@ -70,19 +70,19 @@ class Ui_EditVerseDialog(object):
translate('SongsPlugin.EditVerseForm', 'Edit Verse')) translate('SongsPlugin.EditVerseForm', 'Edit Verse'))
self.verseTypeLabel.setText( self.verseTypeLabel.setText(
translate('SongsPlugin.EditVerseForm', '&Verse type:')) translate('SongsPlugin.EditVerseForm', '&Verse type:'))
self.verseTypeComboBox.setItemText(0, self.verseTypeComboBox.setItemText(VerseType.Verse,
VerseType.to_string(VerseType.Verse)) VerseType.TranslatedNames[VerseType.Verse])
self.verseTypeComboBox.setItemText(1, self.verseTypeComboBox.setItemText(VerseType.Chorus,
VerseType.to_string(VerseType.Chorus)) VerseType.TranslatedNames[VerseType.Chorus])
self.verseTypeComboBox.setItemText(2, self.verseTypeComboBox.setItemText(VerseType.Bridge,
VerseType.to_string(VerseType.Bridge)) VerseType.TranslatedNames[VerseType.Bridge])
self.verseTypeComboBox.setItemText(3, self.verseTypeComboBox.setItemText(VerseType.PreChorus,
VerseType.to_string(VerseType.PreChorus)) VerseType.TranslatedNames[VerseType.PreChorus])
self.verseTypeComboBox.setItemText(4, self.verseTypeComboBox.setItemText(VerseType.Intro,
VerseType.to_string(VerseType.Intro)) VerseType.TranslatedNames[VerseType.Intro])
self.verseTypeComboBox.setItemText(5, self.verseTypeComboBox.setItemText(VerseType.Ending,
VerseType.to_string(VerseType.Ending)) VerseType.TranslatedNames[VerseType.Ending])
self.verseTypeComboBox.setItemText(6, self.verseTypeComboBox.setItemText(VerseType.Other,
VerseType.to_string(VerseType.Other)) VerseType.TranslatedNames[VerseType.Other])
self.insertButton.setText( self.insertButton.setText(
translate('SongsPlugin.EditVerseForm', '&Insert')) translate('SongsPlugin.EditVerseForm', '&Insert'))

View File

@ -57,22 +57,23 @@ class EditVerseForm(QtGui.QDialog, Ui_EditVerseDialog):
QtCore.QObject.connect(self.verseTypeComboBox, QtCore.QObject.connect(self.verseTypeComboBox,
QtCore.SIGNAL(u'currentIndexChanged(int)'), QtCore.SIGNAL(u'currentIndexChanged(int)'),
self.onVerseTypeComboBoxChanged) self.onVerseTypeComboBoxChanged)
self.verse_regex = re.compile(r'---\[([-\w]+):([\d]+)\]---') self.verse_regex = re.compile(r'---\[(.+):\D*(\d*)\D*.*\]---')
def contextMenu(self, point): def contextMenu(self, point):
item = self.serviceManagerList.itemAt(point) item = self.serviceManagerList.itemAt(point)
def insertVerse(self, title, num=1): def insertVerse(self, verse_tag, verse_num=1):
if self.verseTextEdit.textCursor().columnNumber() != 0: if self.verseTextEdit.textCursor().columnNumber() != 0:
self.verseTextEdit.insertPlainText(u'\n') self.verseTextEdit.insertPlainText(u'\n')
self.verseTextEdit.insertPlainText(u'---[%s:%s]---\n' % (title, num)) verse_tag = VerseType.translated_name(verse_tag)
self.verseTextEdit.insertPlainText(u'---[%s:%s]---\n' %
(verse_tag, verse_num))
self.verseTextEdit.setFocus() self.verseTextEdit.setFocus()
def onInsertButtonClicked(self): def onInsertButtonClicked(self):
verse_type = self.verseTypeComboBox.currentIndex() verse_type_index = self.verseTypeComboBox.currentIndex()
if VerseType.to_string(verse_type) is not None: self.insertVerse(VerseType.Tags[verse_type_index],
self.insertVerse(VerseType.to_string(verse_type), self.verseNumberBox.value())
self.verseNumberBox.value())
def onVerseTypeComboBoxChanged(self): def onVerseTypeComboBoxChanged(self):
""" """
@ -81,10 +82,11 @@ class EditVerseForm(QtGui.QDialog, Ui_EditVerseDialog):
""" """
position = self.verseTextEdit.textCursor().position() position = self.verseTextEdit.textCursor().position()
text = unicode(self.verseTextEdit.toPlainText()) text = unicode(self.verseTextEdit.toPlainText())
verse_type = VerseType.to_string(self.verseTypeComboBox.currentIndex()) verse_name = VerseType.TranslatedNames[
self.verseTypeComboBox.currentIndex()]
if not text: if not text:
return return
position = text.rfind(u'---[%s' % verse_type, 0, position) position = text.rfind(u'---[%s' % verse_name, 0, position)
if position == -1: if position == -1:
self.verseNumberBox.setValue(1) self.verseNumberBox.setValue(1)
return return
@ -95,11 +97,11 @@ class EditVerseForm(QtGui.QDialog, Ui_EditVerseDialog):
text = text[:position + 4] text = text[:position + 4]
match = self.verse_regex.match(text) match = self.verse_regex.match(text)
if match: if match:
verse_type = match.group(1) verse_tag = match.group(1)
verse_number = int(match.group(2)) verse_num = int(match.group(2))
verse_type_index = VerseType.from_string(verse_type) verse_type_index = VerseType.from_loose_input(verse_tag)
if verse_type_index is not None: if verse_type_index is not None:
self.verseNumberBox.setValue(verse_number) self.verseNumberBox.setValue(verse_num)
def onCursorPositionChanged(self): def onCursorPositionChanged(self):
""" """
@ -124,25 +126,26 @@ class EditVerseForm(QtGui.QDialog, Ui_EditVerseDialog):
match = self.verse_regex.match(text) match = self.verse_regex.match(text)
if match: if match:
verse_type = match.group(1) verse_type = match.group(1)
verse_type_index = VerseType.from_loose_input(verse_type)
verse_number = int(match.group(2)) verse_number = int(match.group(2))
verse_type_index = VerseType.from_string(verse_type)
if verse_type_index is not None: if verse_type_index is not None:
self.verseTypeComboBox.setCurrentIndex(verse_type_index) self.verseTypeComboBox.setCurrentIndex(verse_type_index)
self.verseNumberBox.setValue(verse_number) self.verseNumberBox.setValue(verse_number)
def setVerse(self, text, single=False, def setVerse(self, text, single=False,
tag=u'%s:1' % VerseType.to_string(VerseType.Verse)): tag=u'%s1' % VerseType.Tags[VerseType.Verse]):
self.hasSingleVerse = single self.hasSingleVerse = single
if single: if single:
verse_type, verse_number = tag.split(u':') verse_type_index = VerseType.from_tag(tag[0])
verse_type_index = VerseType.from_string(verse_type) verse_number = tag[1:]
if verse_type_index is not None: if verse_type_index is not None:
self.verseTypeComboBox.setCurrentIndex(verse_type_index) self.verseTypeComboBox.setCurrentIndex(verse_type_index)
self.verseNumberBox.setValue(int(verse_number)) self.verseNumberBox.setValue(int(verse_number))
self.insertButton.setVisible(False) self.insertButton.setVisible(False)
else: else:
if not text: if not text:
text = u'---[%s:1]---\n' % VerseType.to_string(VerseType.Verse) text = u'---[%s:1]---\n' % \
VerseType.TranslatedNames[VerseType.Verse]
self.verseTypeComboBox.setCurrentIndex(0) self.verseTypeComboBox.setCurrentIndex(0)
self.verseNumberBox.setValue(1) self.verseNumberBox.setValue(1)
self.insertButton.setVisible(True) self.insertButton.setVisible(True)
@ -152,14 +155,14 @@ class EditVerseForm(QtGui.QDialog, Ui_EditVerseDialog):
def getVerse(self): def getVerse(self):
return self.verseTextEdit.toPlainText(), \ return self.verseTextEdit.toPlainText(), \
VerseType.to_string(self.verseTypeComboBox.currentIndex()), \ VerseType.Tags[self.verseTypeComboBox.currentIndex()], \
unicode(self.verseNumberBox.value()) unicode(self.verseNumberBox.value())
def getVerseAll(self): def getVerseAll(self):
text = self.verseTextEdit.toPlainText() text = self.verseTextEdit.toPlainText()
if not text.startsWith(u'---['): if not text.startsWith(u'---['):
text = u'---[%s:1]---\n%s' % (VerseType.to_string(VerseType.Verse), text = u'---[%s:1]---\n%s' % \
text) (VerseType.TranslatedNames[VerseType.Verse], text)
return text return text
def accept(self): def accept(self):

View File

@ -252,6 +252,7 @@ class SongExportForm(OpenLPWizard):
self.availableListWidget.clear() self.availableListWidget.clear()
self.selectedListWidget.clear() self.selectedListWidget.clear()
self.directoryLineEdit.clear() self.directoryLineEdit.clear()
self.searchLineEdit.clear()
# Load the list of songs. # Load the list of songs.
Receiver.send_message(u'cursor_busy') Receiver.send_message(u'cursor_busy')
songs = self.plugin.manager.get_all_objects(Song) songs = self.plugin.manager.get_all_objects(Song)
@ -340,19 +341,21 @@ class SongExportForm(OpenLPWizard):
def onUncheckButtonClicked(self): def onUncheckButtonClicked(self):
""" """
The *uncheckButton* has been clicked. Set all songs unchecked. The *uncheckButton* has been clicked. Set all visible songs unchecked.
""" """
for row in range(self.availableListWidget.count()): for row in range(self.availableListWidget.count()):
item = self.availableListWidget.item(row) item = self.availableListWidget.item(row)
item.setCheckState(QtCore.Qt.Unchecked) if not item.isHidden():
item.setCheckState(QtCore.Qt.Unchecked)
def onCheckButtonClicked(self): def onCheckButtonClicked(self):
""" """
The *checkButton* has been clicked. Set all songs checked. The *checkButton* has been clicked. Set all visible songs checked.
""" """
for row in range(self.availableListWidget.count()): for row in range(self.availableListWidget.count()):
item = self.availableListWidget.item(row) item = self.availableListWidget.item(row)
item.setCheckState(QtCore.Qt.Checked) if not item.isHidden():
item.setCheckState(QtCore.Qt.Checked)
def onDirectoryButtonClicked(self): def onDirectoryButtonClicked(self):
""" """

View File

@ -504,7 +504,7 @@ class SongImportForm(OpenLPWizard):
The file extension filters. It should contain the file descriptions The file extension filters. It should contain the file descriptions
as well as the file extensions. For example:: as well as the file extensions. For example::
u'SongBeamer files (*.sng)' u'SongBeamer Files (*.sng)'
""" """
if filters: if filters:
filters += u';;' filters += u';;'
@ -633,7 +633,7 @@ class SongImportForm(OpenLPWizard):
'Select Songs of Fellowship Files'), 'Select Songs of Fellowship Files'),
self.songsOfFellowshipFileListWidget, u'%s (*.rtf)' self.songsOfFellowshipFileListWidget, u'%s (*.rtf)'
% translate('SongsPlugin.ImportWizardForm', % translate('SongsPlugin.ImportWizardForm',
'Songs Of Felloship Song Files') 'Songs Of Fellowship Song Files')
) )
def onSongsOfFellowshipRemoveButtonClicked(self): def onSongsOfFellowshipRemoveButtonClicked(self):
@ -683,7 +683,7 @@ class SongImportForm(OpenLPWizard):
translate('SongsPlugin.ImportWizardForm', translate('SongsPlugin.ImportWizardForm',
'Select SongBeamer Files'), 'Select SongBeamer Files'),
self.songBeamerFileListWidget, u'%s (*.sng)' % self.songBeamerFileListWidget, u'%s (*.sng)' %
translate('SongsPlugin.ImportWizardForm', 'SongBeamer files') translate('SongsPlugin.ImportWizardForm', 'SongBeamer Files')
) )
def onSongBeamerRemoveButtonClicked(self): def onSongBeamerRemoveButtonClicked(self):

View File

@ -457,7 +457,7 @@ class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog):
def onTopicDeleteButtonClick(self): def onTopicDeleteButtonClick(self):
""" """
Delete the Book is the Book is not attached to any songs. Delete the Book if the Book is not attached to any songs.
""" """
self._deleteItem(Topic, self.topicsListWidget, self.resetTopics, self._deleteItem(Topic, self.topicsListWidget, self.resetTopics,
translate('SongsPlugin.SongMaintenanceForm', 'Delete Topic'), translate('SongsPlugin.SongMaintenanceForm', 'Delete Topic'),
@ -470,7 +470,7 @@ class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog):
def onBookDeleteButtonClick(self): def onBookDeleteButtonClick(self):
""" """
Delete the Book is the Book is not attached to any songs. Delete the Book if the Book is not attached to any songs.
""" """
self._deleteItem(Book, self.booksListWidget, self.resetBooks, self._deleteItem(Book, self.booksListWidget, self.resetBooks,
translate('SongsPlugin.SongMaintenanceForm', 'Delete Book'), translate('SongsPlugin.SongMaintenanceForm', 'Delete Book'),

View File

@ -40,68 +40,147 @@ class VerseType(object):
Ending = 5 Ending = 5
Other = 6 Other = 6
@staticmethod Names = [
def to_string(verse_type): u'Verse',
""" u'Chorus',
Return a string for a given VerseType u'Bridge',
u'Pre-Chorus',
u'Intro',
u'Ending',
u'Other']
Tags = [name[0].lower() for name in Names]
``verse_type`` TranslatedNames = [
The type to return a string for unicode(translate('SongsPlugin.VerseType', 'Verse')),
""" unicode(translate('SongsPlugin.VerseType', 'Chorus')),
if not isinstance(verse_type, int): unicode(translate('SongsPlugin.VerseType', 'Bridge')),
verse_type = verse_type.lower() unicode(translate('SongsPlugin.VerseType', 'Pre-Chorus')),
if verse_type == VerseType.Verse or verse_type == \ unicode(translate('SongsPlugin.VerseType', 'Intro')),
unicode(VerseType.to_string(VerseType.Verse)).lower()[0]: unicode(translate('SongsPlugin.VerseType', 'Ending')),
return translate('SongsPlugin.VerseType', 'Verse') unicode(translate('SongsPlugin.VerseType', 'Other'))]
elif verse_type == VerseType.Chorus or verse_type == \ TranslatedTags = [name[0].lower() for name in TranslatedNames]
unicode(VerseType.to_string(VerseType.Chorus)).lower()[0]:
return translate('SongsPlugin.VerseType', 'Chorus')
elif verse_type == VerseType.Bridge or verse_type == \
unicode(VerseType.to_string(VerseType.Bridge)).lower()[0]:
return translate('SongsPlugin.VerseType', 'Bridge')
elif verse_type == VerseType.PreChorus or verse_type == \
unicode(VerseType.to_string(VerseType.PreChorus)).lower()[0]:
return translate('SongsPlugin.VerseType', 'Pre-Chorus')
elif verse_type == VerseType.Intro or verse_type == \
unicode(VerseType.to_string(VerseType.Intro)).lower()[0]:
return translate('SongsPlugin.VerseType', 'Intro')
elif verse_type == VerseType.Ending or verse_type == \
unicode(VerseType.to_string(VerseType.Ending)).lower()[0]:
return translate('SongsPlugin.VerseType', 'Ending')
elif verse_type == VerseType.Other or verse_type == \
unicode(VerseType.to_string(VerseType.Other)).lower()[0]:
return translate('SongsPlugin.VerseType', 'Other')
@staticmethod @staticmethod
def from_string(verse_type): def translated_tag(verse_tag, strict=False):
"""
Return the translated UPPERCASE tag for a given tag,
used to show translated verse tags in UI
``verse_tag``
The string to return a VerseType for
``strict``
Determines if the default Other or None should be returned
"""
if strict:
not_found_value = None
else:
not_found_value = VerseType.TranslatedTags[VerseType.Other].upper()
verse_tag = verse_tag[0].lower()
for num, tag in enumerate(VerseType.Tags):
if verse_tag == tag:
return VerseType.TranslatedTags[num].upper()
return not_found_value
@staticmethod
def translated_name(verse_tag, strict=False):
"""
Return the translated name for a given tag
``verse_tag``
The string to return a VerseType for
``strict``
Determines if the default Other or None should be returned
"""
if strict:
not_found_value = None
else:
not_found_value = VerseType.TranslatedNames[VerseType.Other]
verse_tag = verse_tag[0].lower()
for num, tag in enumerate(VerseType.Tags):
if verse_tag == tag:
return VerseType.TranslatedNames[num]
return not_found_value
@staticmethod
def from_tag(verse_tag, strict=False):
"""
Return the VerseType for a given tag
``verse_tag``
The string to return a VerseType for
``strict``
Determines if the default Other or None should be returned
"""
if strict:
no_return_value = None
else:
no_return_value = VerseType.Other
verse_tag = verse_tag[0].lower()
for num, tag in enumerate(VerseType.Tags):
if verse_tag == tag:
return num
return no_return_value
@staticmethod
def from_translated_tag(verse_tag):
"""
Return the VerseType for a given tag
``verse_tag``
The string to return a VerseType for
"""
verse_tag = verse_tag[0].lower()
for num, tag in enumerate(VerseType.TranslatedTags):
if verse_tag == tag:
return num
@staticmethod
def from_string(verse_name):
""" """
Return the VerseType for a given string Return the VerseType for a given string
``verse_type`` ``verse_name``
The string to return a VerseType for The string to return a VerseType for
""" """
verse_type = verse_type.lower() verse_name = verse_name.lower()
if verse_type == unicode(VerseType.to_string(VerseType.Verse)).lower(): for num, name in enumerate(VerseType.Names):
return VerseType.Verse if verse_name == name.lower():
elif verse_type == \ return num
unicode(VerseType.to_string(VerseType.Chorus)).lower():
return VerseType.Chorus
elif verse_type == \
unicode(VerseType.to_string(VerseType.Bridge)).lower():
return VerseType.Bridge
elif verse_type == \
unicode(VerseType.to_string(VerseType.PreChorus)).lower():
return VerseType.PreChorus
elif verse_type == \
unicode(VerseType.to_string(VerseType.Intro)).lower():
return VerseType.Intro
elif verse_type == \
unicode(VerseType.to_string(VerseType.Ending)).lower():
return VerseType.Ending
elif verse_type == \
unicode(VerseType.to_string(VerseType.Other)).lower():
return VerseType.Other
@staticmethod
def from_translated_string(verse_name):
"""
Return the VerseType for a given string
``verse_name``
The string to return a VerseType for
"""
verse_name = verse_name.lower()
for num, translation in enumerate(VerseType.TranslatedNames):
if verse_name == translation.lower():
return num
@staticmethod
def from_loose_input(verse_name):
"""
Return the VerseType for a given string, Other if not found
``verse_name``
The string to return a VerseType for
"""
verse_index = None
if len(verse_name) > 1:
verse_index = VerseType.from_translated_string(verse_name)
if verse_index is None:
verse_index = VerseType.from_string(verse_name)
if verse_index is None:
verse_index = VerseType.from_translated_tag(verse_name)
if verse_index is None:
verse_index = VerseType.from_tag(verse_name)
return verse_index
def retrieve_windows_encoding(recommendation=None): def retrieve_windows_encoding(recommendation=None):
""" """

View File

@ -81,14 +81,16 @@ class EasiSlidesImport(SongImport):
def _parse_song(self, song): def _parse_song(self, song):
self._success = True self._success = True
self._add_unicode_attribute(self.title, song.Title1, True) self._add_unicode_attribute(u'title', song.Title1, True)
self._add_unicode_attribute(self.alternate_title, song.Title2) self._add_unicode_attribute(u'alternate_title', song.Title2)
self._add_unicode_attribute(self.song_number, song.SongNumber) self._add_unicode_attribute(u'song_number', song.SongNumber)
if self.song_number == u'0': if self.song_number == u'0':
self.song_number = u'' self.song_number = u''
self._add_authors(song) self._add_authors(song)
self._add_copyright(song) self._add_copyright(song.Copyright)
self._add_unicode_attribute(self.song_book_name, song.BookReference) self._add_copyright(song.LicenceAdmin1)
self._add_copyright(song.LicenceAdmin2)
self._add_unicode_attribute(u'song_book_name', song.BookReference)
self._parse_and_add_lyrics(song) self._parse_and_add_lyrics(song)
return self._success return self._success
@ -110,7 +112,7 @@ class EasiSlidesImport(SongImport):
Signals that this attribute must exist in a valid song. Signals that this attribute must exist in a valid song.
""" """
try: try:
self_attribute = unicode(import_attribute).strip() setattr(self, self_attribute, unicode(import_attribute).strip())
except UnicodeDecodeError: except UnicodeDecodeError:
log.exception(u'UnicodeDecodeError decoding %s' % import_attribute) log.exception(u'UnicodeDecodeError decoding %s' % import_attribute)
self._success = False self._success = False
@ -124,7 +126,7 @@ class EasiSlidesImport(SongImport):
authors = unicode(song.Writer).split(u',') authors = unicode(song.Writer).split(u',')
for author in authors: for author in authors:
author = author.strip() author = author.strip()
if len(author) > 0: if len(author):
self.authors.append(author) self.authors.append(author)
except UnicodeDecodeError: except UnicodeDecodeError:
log.exception(u'Unicode decode error while decoding Writer') log.exception(u'Unicode decode error while decoding Writer')
@ -132,35 +134,18 @@ class EasiSlidesImport(SongImport):
except AttributeError: except AttributeError:
pass pass
def _add_copyright(self, song): def _add_copyright(self, element):
"""
Assign the copyright information from the import to the song being
created.
``song``
The current song being imported.
"""
copyright_list = []
self.__add_copyright_element(copyright_list, song.Copyright)
self.__add_copyright_element(copyright_list, song.LicenceAdmin1)
self.__add_copyright_element(copyright_list, song.LicenceAdmin2)
self.add_copyright(u' '.join(copyright_list))
def __add_copyright_element(self, copyright_list, element):
""" """
Add a piece of copyright to the total copyright information for the Add a piece of copyright to the total copyright information for the
song. song.
``copyright_list``
The array to add the information to.
``element`` ``element``
The imported variable to get the data from. The imported variable to get the data from.
""" """
try: try:
copyright_list.append(unicode(element).strip()) self.add_copyright(unicode(element).strip())
except UnicodeDecodeError: except UnicodeDecodeError:
log.exception(u'Unicode error decoding %s' % element) log.exception(u'Unicode error on decoding copyright: %s' % element)
self._success = False self._success = False
except AttributeError: except AttributeError:
pass pass
@ -285,10 +270,12 @@ class EasiSlidesImport(SongImport):
# as these appeared originally in the file # as these appeared originally in the file
for [reg, vt, vn, inst] in our_verse_order: for [reg, vt, vn, inst] in our_verse_order:
if self._listHas(verses, [reg, vt, vn, inst]): if self._listHas(verses, [reg, vt, vn, inst]):
# this is false, but needs user input
lang = None
versetag = u'%s%s' % (vt, vn) versetag = u'%s%s' % (vt, vn)
versetags.append(versetag) versetags.append(versetag)
lines = u'\n'.join(verses[reg][vt][vn][inst]) lines = u'\n'.join(verses[reg][vt][vn][inst])
self.verses.append([versetag, lines]) self.verses.append([versetag, lines, lang])
SeqTypes = { SeqTypes = {
u'p': u'P1', u'p': u'P1',

View File

@ -69,12 +69,12 @@ class SongFormat(object):
CCLI = 5 CCLI = 5
SongsOfFellowship = 6 SongsOfFellowship = 6
Generic = 7 Generic = 7
#CSV = 8
EasiSlides = 8 EasiSlides = 8
EasyWorship = 9 EasyWorship = 9
SongBeamer = 10 SongBeamer = 10
SongShowPlus = 11 SongShowPlus = 11
FoilPresenter = 12 FoilPresenter = 12
#CSV = 13
@staticmethod @staticmethod
def get_class(format): def get_class(format):

View File

@ -36,7 +36,7 @@ from openlp.core.lib import MediaManagerItem, Receiver, ItemCapabilities, \
from openlp.core.lib.ui import UiStrings from openlp.core.lib.ui import UiStrings
from openlp.plugins.songs.forms import EditSongForm, SongMaintenanceForm, \ from openlp.plugins.songs.forms import EditSongForm, SongMaintenanceForm, \
SongImportForm, SongExportForm SongImportForm, SongExportForm
from openlp.plugins.songs.lib import OpenLyrics, SongXML from openlp.plugins.songs.lib import OpenLyrics, SongXML, VerseType
from openlp.plugins.songs.lib.db import Author, Song from openlp.plugins.songs.lib.db import Author, Song
from openlp.core.lib.searchedit import SearchEdit from openlp.core.lib.searchedit import SearchEdit
@ -344,24 +344,49 @@ class SongMediaItem(MediaManagerItem):
if song.lyrics.startswith(u'<?xml version='): if song.lyrics.startswith(u'<?xml version='):
verseList = SongXML().get_verses(song.lyrics) verseList = SongXML().get_verses(song.lyrics)
# no verse list or only 1 space (in error) # no verse list or only 1 space (in error)
if not song.verse_order or not song.verse_order.strip(): verse_tags_translated = False
if VerseType.from_translated_string(unicode(
verseList[0][0][u'type'])) is not None:
verse_tags_translated = True
if not song.verse_order.strip():
for verse in verseList: for verse in verseList:
verseTag = u'%s:%s' % ( # We cannot use from_loose_input() here, because database
verse[0][u'type'], verse[0][u'label']) # is supposed to contain English lowercase singlechar tags.
verse_tag = verse[0][u'type']
verse_index = None
if len(verse_tag) > 1:
verse_index = \
VerseType.from_translated_string(verse_tag)
if verse_index is None:
verse_index = VerseType.from_string(verse_tag)
if verse_index is None:
verse_index = VerseType.from_tag(verse_tag)
verse_tag = VerseType.TranslatedTags[verse_index].upper()
verse_def = u'%s%s' % (verse_tag, verse[0][u'label'])
service_item.add_from_text( service_item.add_from_text(
verse[1][:30], unicode(verse[1]), verseTag) verse[1][:30], unicode(verse[1]), verse_def)
else: else:
# Loop through the verse list and expand the song accordingly. # Loop through the verse list and expand the song accordingly.
for order in song.verse_order.upper().split(): for order in song.verse_order.lower().split():
if len(order) == 0: if len(order) == 0:
break break
for verse in verseList: for verse in verseList:
if verse[0][u'type'][0] == order[0] and \ if verse[0][u'type'][0].lower() == order[0] and \
(verse[0][u'label'] == order[1:] or not order[1:]): (verse[0][u'label'].lower() == order[1:] or \
verseTag = u'%s:%s' % \ not order[1:]):
(verse[0][u'type'], verse[0][u'label']) if verse_tags_translated:
verse_index = VerseType.from_translated_tag(
verse[0][u'type'])
else:
verse_index = VerseType.from_tag(
verse[0][u'type'])
if verse_index is None:
verse_index = VerseType.Other
verse_tag = VerseType.TranslatedTags[verse_index]
verse_def = u'%s%s' % (verse_tag,
verse[0][u'label'])
service_item.add_from_text( service_item.add_from_text(
verse[1][:30], verse[1], verseTag) verse[1][:30], verse[1], verse_def)
else: else:
verses = song.lyrics.split(u'\n\n') verses = song.lyrics.split(u'\n\n')
for slide in verses: for slide in verses:

View File

@ -149,23 +149,25 @@ class OpenSongImport(SongImport):
unicode(translate('SongsPlugin.ImportWizardForm', unicode(translate('SongsPlugin.ImportWizardForm',
'Importing %s...')) % parts[-1]) 'Importing %s...')) % parts[-1])
songfile = z.open(song) songfile = z.open(song)
self.do_import_file(songfile) if self.do_import_file(songfile) and self.commit and \
if self.commit: not self.stop_import_flag:
self.finish() self.finish()
if self.stop_import_flag: else:
success = False success = False
break break
else: else:
# not a zipfile # not a zipfile
log.info(u'Direct import %s', filename) log.info(u'Direct import %s', filename)
self.import_wizard.incrementProgressBar( self.import_wizard.incrementProgressBar(
unicode(translate('SongsPlugin.ImportWizardForm', unicode(translate('SongsPlugin.ImportWizardForm',
'Importing %s...')) % os.path.split(filename)[-1]) 'Importing %s...')) % os.path.split(filename)[-1])
file = open(filename) song_file = open(filename)
self.do_import_file(file) if self.do_import_file(song_file) and self.commit and \
if self.commit: not self.stop_import_flag:
self.finish() self.finish()
else:
success = False
break
return success return success
def do_import_file(self, file): def do_import_file(self, file):
@ -178,7 +180,7 @@ class OpenSongImport(SongImport):
tree = objectify.parse(file) tree = objectify.parse(file)
except (Error, LxmlError): except (Error, LxmlError):
log.exception(u'Error parsing XML') log.exception(u'Error parsing XML')
return return False
root = tree.getroot() root = tree.getroot()
fields = dir(root) fields = dir(root)
decode = { decode = {
@ -196,114 +198,103 @@ class OpenSongImport(SongImport):
setattr(self, fn_or_string, ustring) setattr(self, fn_or_string, ustring)
else: else:
fn_or_string(ustring) fn_or_string(ustring)
if not len(self.title):
# to prevent creation of empty songs from wrong files
return False
if u'theme' in fields and unicode(root.theme) not in self.topics: if u'theme' in fields and unicode(root.theme) not in self.topics:
self.topics.append(unicode(root.theme)) self.topics.append(unicode(root.theme))
if u'alttheme' in fields and unicode(root.alttheme) not in self.topics: if u'alttheme' in fields and unicode(root.alttheme) not in self.topics:
self.topics.append(unicode(root.alttheme)) self.topics.append(unicode(root.alttheme))
# data storage while importing # data storage while importing
verses = {} verses = {}
# keep track of a "default" verse order, in case none is specified # keep track of verses appearance order
our_verse_order = [] our_verse_order = []
verses_seen = {} # default verse
# in the absence of any other indication, verses are the default, verse_tag = u'v'
# erm, versetype! verse_num = u'1'
versetype = u'V' # for the case where song has several sections with same marker
versenum = None inst = 1
lyrics = unicode(root.lyrics) lyrics = unicode(root.lyrics)
for thisline in lyrics.split(u'\n'): for this_line in lyrics.split(u'\n'):
# remove comments # remove comments
semicolon = thisline.find(u';') semicolon = this_line.find(u';')
if semicolon >= 0: if semicolon >= 0:
thisline = thisline[:semicolon] this_line = this_line[:semicolon]
thisline = thisline.strip() this_line = this_line.strip()
if len(thisline) == 0: if not len(this_line):
continue continue
# skip inthisline guitar chords and page and column breaks # skip guitar chords and page and column breaks
if thisline[0] == u'.' or thisline.startswith(u'---') \ if this_line.startswith(u'.') or this_line.startswith(u'---') \
or thisline.startswith(u'-!!'): or this_line.startswith(u'-!!'):
continue continue
# verse/chorus/etc. marker # verse/chorus/etc. marker
if thisline[0] == u'[': if this_line.startswith(u'['):
# drop the square brackets # drop the square brackets
right_bracket = thisline.find(u']') right_bracket = this_line.find(u']')
content = thisline[1:right_bracket].upper() content = this_line[1:right_bracket].lower()
# have we got any digits? # have we got any digits?
# If so, versenumber is everything from the digits # If so, verse number is everything from the digits
# to the end (even if there are some alpha chars on the end) # to the end (even if there are some alpha chars on the end)
match = re.match(u'(.*)(\d+.*)', content) match = re.match(u'(.*)(\d+.*)', content)
if match is not None: if match is not None:
versetype = match.group(1) verse_tag = match.group(1)
versenum = match.group(2) verse_num = match.group(2)
else: else:
# otherwise we assume number 1 and take the whole prefix as # otherwise we assume number 1 and take the whole prefix as
# the versetype # the verse tag
versetype = content verse_tag = content
versenum = u'1' verse_num = u'1'
inst = 1
if [verse_tag, verse_num, inst] in our_verse_order \
and verses.has_key(verse_tag) \
and verses[verse_tag].has_key(verse_num):
inst = len(verses[verse_tag][verse_num])+1
our_verse_order.append([verse_tag, verse_num, inst])
continue continue
words = None
# number at start of line.. it's verse number # number at start of line.. it's verse number
if thisline[0].isdigit(): if this_line[0].isdigit():
versenum = thisline[0] verse_num = this_line[0]
words = thisline[1:].strip() this_line = this_line[1:].strip()
if words is None: our_verse_order.append([verse_tag, verse_num, inst])
words = thisline if not verses.has_key(verse_tag):
if not versenum: verses[verse_tag] = {}
versenum = u'1' if not verses[verse_tag].has_key(verse_num):
if versenum is not None: verses[verse_tag][verse_num] = {}
versetag = u'%s%s' % (versetype, versenum) if not verses[verse_tag][verse_num].has_key(inst):
if not verses.has_key(versetype): verses[verse_tag][verse_num][inst] = []
verses[versetype] = {} # Tidy text and remove the ____s from extended words
if not verses[versetype].has_key(versenum): this_line = self.tidy_text(this_line)
# storage for lines in this verse this_line = this_line.replace(u'_', u'')
verses[versetype][versenum] = [] this_line = this_line.replace(u'|', u'\n')
if not verses_seen.has_key(versetag): verses[verse_tag][verse_num][inst].append(this_line)
verses_seen[versetag] = 1
our_verse_order.append(versetag)
if words:
# Tidy text and remove the ____s from extended words
words = self.tidy_text(words)
words = words.replace('_', '')
verses[versetype][versenum].append(words)
# done parsing # done parsing
versetypes = verses.keys() # add verses in original order
versetypes.sort() for (verse_tag, verse_num, inst) in our_verse_order:
versetags = {} verse_def = u'%s%s' % (verse_tag, verse_num)
for versetype in versetypes: lines = u'\n'.join(verses[verse_tag][verse_num][inst])
our_verse_type = versetype self.add_verse(lines, verse_def)
if our_verse_type == u'': # figure out the presentation order, if present
our_verse_type = u'V'
versenums = verses[versetype].keys()
versenums.sort()
for num in versenums:
versetag = u'%s%s' % (our_verse_type, num)
lines = u'\n'.join(verses[versetype][num])
self.add_verse(lines, versetag)
# Keep track of what we have for error checking later
versetags[versetag] = 1
# now figure out the presentation order
order = []
if u'presentation' in fields and root.presentation != u'': if u'presentation' in fields and root.presentation != u'':
order = unicode(root.presentation) order = unicode(root.presentation)
# We make all the tags in the lyrics upper case, so match that here # We make all the tags in the lyrics lower case, so match that here
# and then split into a list on the whitespace # and then split into a list on the whitespace
order = order.upper().split() order = order.lower().split()
else: for verse_def in order:
if len(our_verse_order) > 0: match = re.match(u'(.*)(\d+.*)', verse_def)
order = our_verse_order if match is not None:
else: verse_tag = match.group(1)
log.warn(u'No verse order available for %s, skipping.', verse_num = match.group(2)
self.title) if not len(verse_tag):
# TODO: make sure that the default order list will be overwritten, if verse_tag = u'v'
# the songs provides its own order list. else:
for tag in order: # Assume it's no.1 if there are no digits
if tag[0].isdigit(): verse_tag = verse_def
# Assume it's a verse if it has no prefix verse_num = u'1'
tag = u'V' + tag verse_def = u'%s%s' % (verse_tag, verse_num)
elif not re.search('\d+', tag): if verses.has_key(verse_tag) \
# Assume it's no.1 if there's no digits and verses[verse_tag].has_key(verse_num):
tag = tag + u'1' self.verse_order_list.append(verse_def)
if not versetags.has_key(tag): else:
log.info(u'Got order %s but not in versetags, dropping this' log.info(u'Got order %s but not in verse tags, dropping'
u'item from presentation order', tag) u'this item from presentation order', verse_def)
else: return True
self.verse_order_list.append(tag)

View File

@ -75,9 +75,11 @@ class SongImport(QtCore.QObject):
self.media_files = [] self.media_files = []
self.song_book_name = u'' self.song_book_name = u''
self.song_book_pub = u'' self.song_book_pub = u''
self.verse_order_list_generated_useful = False
self.verse_order_list_generated = []
self.verse_order_list = [] self.verse_order_list = []
self.verses = [] self.verses = []
self.versecounts = {} self.verse_counts = {}
self.copyright_string = unicode(translate( self.copyright_string = unicode(translate(
'SongsPlugin.SongImport', 'copyright')) 'SongsPlugin.SongImport', 'copyright'))
self.copyright_symbol = unicode(translate( self.copyright_symbol = unicode(translate(
@ -128,20 +130,20 @@ class SongImport(QtCore.QObject):
return text return text
def process_song_text(self, text): def process_song_text(self, text):
versetexts = text.split(u'\n\n') verse_texts = text.split(u'\n\n')
for versetext in versetexts: for verse_text in verse_texts:
if versetext.strip() != u'': if verse_text.strip() != u'':
self.process_verse_text(versetext.strip()) self.process_verse_text(verse_text.strip())
def process_verse_text(self, text): def process_verse_text(self, text):
lines = text.split(u'\n') lines = text.split(u'\n')
if text.lower().find(self.copyright_string) >= 0 \ if text.lower().find(self.copyright_string) >= 0 \
or text.lower().find(self.copyright_symbol) >= 0: or text.find(self.copyright_symbol) >= 0:
copyright_found = False copyright_found = False
for line in lines: for line in lines:
if (copyright_found or if (copyright_found or
line.lower().find(self.copyright_string) >= 0 or line.lower().find(self.copyright_string) >= 0 or
line.lower().find(self.copyright_symbol) >= 0): line.find(self.copyright_symbol) >= 0):
copyright_found = True copyright_found = True
self.add_copyright(line) self.add_copyright(line)
else: else:
@ -198,45 +200,46 @@ class SongImport(QtCore.QObject):
return return
self.media_files.append(filename) self.media_files.append(filename)
def add_verse(self, versetext, versetag=u'V', lang=None): def add_verse(self, verse_text, verse_def=u'v', lang=None):
""" """
Add a verse. This is the whole verse, lines split by \\n. It will also Add a verse. This is the whole verse, lines split by \\n. It will also
attempt to detect duplicates. In this case it will just add to the verse attempt to detect duplicates. In this case it will just add to the verse
order. order.
``versetext`` ``verse_text``
The text of the verse. The text of the verse.
``versetag`` ``verse_def``
The verse tag can be V1/C1/B etc, or 'V' and 'C' (will count the The verse tag can be v1/c1/b etc, or 'v' and 'c' (will count the
verses/choruses itself) or None, where it will assume verse. verses/choruses itself) or None, where it will assume verse.
``lang`` ``lang``
The language code (ISO-639) of the verse, for example *en* or *de*. The language code (ISO-639) of the verse, for example *en* or *de*.
""" """
for (oldversetag, oldverse, oldlang) in self.verses: for (old_verse_def, old_verse, old_lang) in self.verses:
if oldverse.strip() == versetext.strip(): if old_verse.strip() == verse_text.strip():
self.verse_order_list.append(oldversetag) self.verse_order_list_generated.append(old_verse_def)
self.verse_order_list_generated_useful = True
return return
if versetag[0] in self.versecounts: if verse_def[0] in self.verse_counts:
self.versecounts[versetag[0]] += 1 self.verse_counts[verse_def[0]] += 1
else: else:
self.versecounts[versetag[0]] = 1 self.verse_counts[verse_def[0]] = 1
if len(versetag) == 1: if len(verse_def) == 1:
versetag += unicode(self.versecounts[versetag[0]]) verse_def += unicode(self.verse_counts[verse_def[0]])
elif int(versetag[1:]) > self.versecounts[versetag[0]]: elif int(verse_def[1:]) > self.verse_counts[verse_def[0]]:
self.versecounts[versetag[0]] = int(versetag[1:]) self.verse_counts[verse_def[0]] = int(verse_def[1:])
self.verses.append([versetag, versetext.rstrip(), lang]) self.verses.append([verse_def, verse_text.rstrip(), lang])
self.verse_order_list.append(versetag) self.verse_order_list_generated.append(verse_def)
if versetag.startswith(u'V') and u'C1' in self.verse_order_list:
self.verse_order_list.append(u'C1')
def repeat_verse(self): def repeat_verse(self):
""" """
Repeat the previous verse in the verse order Repeat the previous verse in the verse order
""" """
self.verse_order_list.append(self.verse_order_list[-1]) self.verse_order_list_generated.append(
self.verse_order_list_generated[-1])
self.verse_order_list_generated_useful = True
def check_complete(self): def check_complete(self):
""" """
@ -273,34 +276,29 @@ class SongImport(QtCore.QObject):
verses_changed_to_other = {} verses_changed_to_other = {}
sxml = SongXML() sxml = SongXML()
other_count = 1 other_count = 1
for (versetag, versetext, lang) in self.verses: for (verse_def, verse_text, lang) in self.verses:
if versetag[0] == u'C': if verse_def[0].lower() in VerseType.Tags:
versetype = VerseType.to_string(VerseType.Chorus) verse_tag = verse_def[0].lower()
elif versetag[0] == u'V':
versetype = VerseType.to_string(VerseType.Verse)
elif versetag[0] == u'B':
versetype = VerseType.to_string(VerseType.Bridge)
elif versetag[0] == u'I':
versetype = VerseType.to_string(VerseType.Intro)
elif versetag[0] == u'P':
versetype = VerseType.to_string(VerseType.PreChorus)
elif versetag[0] == u'E':
versetype = VerseType.to_string(VerseType.Ending)
else: else:
newversetag = u'O%d' % other_count new_verse_def = u'%s%d' % (VerseType.Tags[VerseType.Other],
verses_changed_to_other[versetag] = newversetag other_count)
verses_changed_to_other[verse_def] = new_verse_def
other_count += 1 other_count += 1
versetype = VerseType.to_string(VerseType.Other) verse_tag = VerseType.Tags[VerseType.Other]
log.info(u'Versetype %s changing to %s' , versetag, newversetag) log.info(u'Versetype %s changing to %s' , verse_def,
versetag = newversetag new_verse_def)
sxml.add_verse_to_lyrics(versetype, versetag[1:], versetext, lang) verse_def = new_verse_def
song.search_lyrics += u' ' + self.remove_punctuation(versetext) sxml.add_verse_to_lyrics(verse_tag, verse_def[1:], verse_text, lang)
song.search_lyrics += u' ' + self.remove_punctuation(verse_text)
song.search_lyrics = song.search_lyrics.lower() song.search_lyrics = song.search_lyrics.lower()
song.lyrics = unicode(sxml.extract_xml(), u'utf-8') song.lyrics = unicode(sxml.extract_xml(), u'utf-8')
for i, current_verse_tag in enumerate(self.verse_order_list): if not len(self.verse_order_list) and \
if verses_changed_to_other.has_key(current_verse_tag): self.verse_order_list_generated_useful:
self.verse_order_list = self.verse_order_list_generated
for i, current_verse_def in enumerate(self.verse_order_list):
if verses_changed_to_other.has_key(current_verse_def):
self.verse_order_list[i] = \ self.verse_order_list[i] = \
verses_changed_to_other[current_verse_tag] verses_changed_to_other[current_verse_def]
song.verse_order = u' '.join(self.verse_order_list) song.verse_order = u' '.join(self.verse_order_list)
song.copyright = self.copyright song.copyright = self.copyright
song.comments = self.comments song.comments = self.comments
@ -345,9 +343,10 @@ class SongImport(QtCore.QObject):
+ u'========================================' + u'========================================'
print u'TITLE: ' + self.title print u'TITLE: ' + self.title
print u'ALT TITLE: ' + self.alternate_title print u'ALT TITLE: ' + self.alternate_title
for (versetag, versetext, lang) in self.verses: for (verse_def, verse_text, lang) in self.verses:
print u'VERSE ' + versetag + u': ' + versetext print u'VERSE ' + verse_def + u': ' + verse_text
print u'ORDER: ' + u' '.join(self.verse_order_list) print u'ORDER: ' + u' '.join(self.verse_order_list)
print u'GENERATED ORDER: ' + u' '.join(self.verse_order_list_generated)
for author in self.authors: for author in self.authors:
print u'AUTHOR: ' + author print u'AUTHOR: ' + author
if self.copyright: if self.copyright:

View File

@ -107,7 +107,6 @@ class SongShowPlusImport(SongImport):
self.import_wizard.progressBar.setMaximum(len(self.import_source)) self.import_wizard.progressBar.setMaximum(len(self.import_source))
for file in self.import_source: for file in self.import_source:
author = u'' author = u''
copyright = u''
self.sspVerseOrderList = [] self.sspVerseOrderList = []
otherCount = 0 otherCount = 0
otherList = {} otherList = {}
@ -116,29 +115,28 @@ class SongShowPlusImport(SongImport):
u'Importing %s' % (file_name), 0) u'Importing %s' % (file_name), 0)
songData = open(file, 'rb') songData = open(file, 'rb')
while (1): while (1):
blockKey, = struct.unpack("I",songData.read(4)) blockKey, = struct.unpack("I", songData.read(4))
# The file ends with 4 NUL's # The file ends with 4 NUL's
if blockKey == 0: if blockKey == 0:
break break
nextBlockStarts, = struct.unpack("I",songData.read(4)) nextBlockStarts, = struct.unpack("I", songData.read(4))
if blockKey == VERSE or blockKey == CHORUS: if blockKey == VERSE or blockKey == CHORUS:
null, verseNo, = struct.unpack("BB",songData.read(2)) null, verseNo, = struct.unpack("BB", songData.read(2))
elif blockKey == CUSTOM_VERSE: elif blockKey == CUSTOM_VERSE:
null, verseNameLength, = struct.unpack("BB", null, verseNameLength, = struct.unpack("BB",
songData.read(2)) songData.read(2))
verseName = songData.read(verseNameLength) verseName = songData.read(verseNameLength)
lengthDescriptorSize, = struct.unpack("B",songData.read(1)) lengthDescriptorSize, = struct.unpack("B", songData.read(1))
# Detect if/how long the length descriptor is # Detect if/how long the length descriptor is
if lengthDescriptorSize == 12: if lengthDescriptorSize == 12:
lengthDescriptor, = struct.unpack("I",songData.read(4)) lengthDescriptor, = struct.unpack("I", songData.read(4))
elif lengthDescriptorSize == 2: elif lengthDescriptorSize == 2:
lengthDescriptor = 1 lengthDescriptor = 1
elif lengthDescriptorSize == 9: elif lengthDescriptorSize == 9:
lengthDescriptor = 0 lengthDescriptor = 0
else: else:
lengthDescriptor, = struct.unpack("B",songData.read(1)) lengthDescriptor, = struct.unpack("B", songData.read(1))
data = songData.read(lengthDescriptor) data = songData.read(lengthDescriptor)
if blockKey == TITLE: if blockKey == TITLE:
self.title = unicode(data, u'cp1252') self.title = unicode(data, u'cp1252')
elif blockKey == AUTHOR: elif blockKey == AUTHOR:
@ -146,8 +144,8 @@ class SongShowPlusImport(SongImport):
for author in authors: for author in authors:
if author.find(",") !=-1: if author.find(",") !=-1:
authorParts = author.split(", ") authorParts = author.split(", ")
author = authorParts[1] + " " + authorParts[0] author = authorParts[1] + " " + authorParts[0]
self.parse_author(unicode(author, u'cp1252')) self.parse_author(unicode(author, u'cp1252'))
elif blockKey == COPYRIGHT: elif blockKey == COPYRIGHT:
self.add_copyright(unicode(data, u'cp1252')) self.add_copyright(unicode(data, u'cp1252'))
elif blockKey == CCLI_NO: elif blockKey == CCLI_NO:
@ -184,7 +182,7 @@ class SongShowPlusImport(SongImport):
return True return True
def toOpenLPVerseTag(self, verseName): def toOpenLPVerseTag(self, verseName):
if verseName.find(" ")!=-1: if verseName.find(" ") !=-1:
verseParts = verseName.split(" ") verseParts = verseName.split(" ")
verseType = verseParts[0] verseType = verseParts[0]
verseNumber = verseParts[1] verseNumber = verseParts[1]
@ -203,7 +201,7 @@ class SongShowPlusImport(SongImport):
elif verseType == "bridge": elif verseType == "bridge":
verseTag = "B" verseTag = "B"
else: else:
if not self.otherList.has_key(verseName): if not self.otherList.has_key(verseName):
self.otherCount = self.otherCount + 1 self.otherCount = self.otherCount + 1
self.otherList[verseName] = str(self.otherCount) self.otherList[verseName] = str(self.otherCount)
verseTag = "O" verseTag = "O"

View File

@ -464,7 +464,8 @@ class OpenLyrics(object):
text += u'\n' text += u'\n'
text += u'\n'.join([unicode(line) for line in lines.line]) text += u'\n'.join([unicode(line) for line in lines.line])
verse_name = self._get(verse, u'name') verse_name = self._get(verse, u'name')
verse_type = unicode(VerseType.to_string(verse_name[0])) verse_type_index = VerseType.from_tag(verse_name[0])
verse_type = VerseType.Names[verse_type_index]
verse_number = re.compile(u'[a-zA-Z]*').sub(u'', verse_name) verse_number = re.compile(u'[a-zA-Z]*').sub(u'', verse_name)
verse_part = re.compile(u'[0-9]*').sub(u'', verse_name[1:]) verse_part = re.compile(u'[0-9]*').sub(u'', verse_name[1:])
# OpenLyrics allows e. g. "c", but we need "c1". # OpenLyrics allows e. g. "c", but we need "c1".

View File

@ -228,7 +228,18 @@ class SongsPlugin(Plugin):
u'title': translate('SongsPlugin', 'Songs', 'container title') u'title': translate('SongsPlugin', 'Songs', 'container title')
} }
# Middle Header Bar # 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): def finalise(self):
""" """

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 335 B

View File

@ -21,6 +21,10 @@
<file>song_topic_edit.png</file> <file>song_topic_edit.png</file>
<file>song_book_edit.png</file> <file>song_book_edit.png</file>
</qresource> </qresource>
<qresource prefix="bibles">
<file>bibles_search_text.png</file>
<file>bibles_search_reference.png</file>
</qresource>
<qresource prefix="plugins"> <qresource prefix="plugins">
<file>plugin_alerts.png</file> <file>plugin_alerts.png</file>
<file>plugin_bibles.png</file> <file>plugin_bibles.png</file>

View File

@ -68,6 +68,7 @@ Source: ..\..\dist\OpenLP\*; DestDir: {app}; Flags: ignoreversion recursesubdirs
[Icons] [Icons]
Name: {group}\{#AppName}; Filename: {app}\{#AppExeName} Name: {group}\{#AppName}; Filename: {app}\{#AppExeName}
Name: {group}\{#AppName} (Debug); Filename: {app}\{#AppExeName}; Parameters: -l debug
Name: {group}\{cm:ProgramOnTheWeb,{#AppName}}; Filename: {#AppURL} Name: {group}\{cm:ProgramOnTheWeb,{#AppName}}; Filename: {#AppURL}
Name: {group}\{cm:UninstallProgram,{#AppName}}; Filename: {uninstallexe} Name: {group}\{cm:UninstallProgram,{#AppName}}; Filename: {uninstallexe}
Name: {commondesktop}\{#AppName}; Filename: {app}\{#AppExeName}; Tasks: desktopicon Name: {commondesktop}\{#AppName}; Filename: {app}\{#AppExeName}; Tasks: desktopicon