This commit is contained in:
Tim Bentley 2011-02-04 16:39:12 +00:00
commit b1c9905bf9
21 changed files with 410 additions and 1131 deletions

View File

@ -1,124 +0,0 @@
openlp.org 2.x Song Database Structure
========================================================================
Introduction
------------
The song database in openlp.org 2.x is similar to the 1.x format. The
biggest differences are the addition of extra tables, and the use of
SQLite version 3.
The song database contains the following tables:
- authors
- authors_songs
- song_books
- songs
- songs_topics
- topics
"authors" Table
---------------
This table holds the names of all the authors. It has the following
columns:
* id
* first_name
* last_name
* display_name
"authors_songs" Table
---------------------
This is a bridging table between the "authors" and "songs" tables, which
serves to create a many-to-many relationship between the two tables. It
has the following columns:
* author_id
* song_id
"song_books" Table
------------------
The "song_books" table holds a list of books that a congregation gets
their songs from, or old hymnals now no longer used. This table has the
following columns:
* id
* name
* publisher
"songs" Table
-------------
This table contains the songs, and each song has a list of attributes.
The "songs" table has the following columns:
* id
* song_book_id
* title
* lyrics
* verse_order
* copyright
* comments
* ccli_number
* song_number
* theme_name
* search_title
* search_lyrics
"songs_topics" Table
--------------------
This is a bridging table between the "songs" and "topics" tables, which
serves to create a many-to-many relationship between the two tables. It
has the following columns:
* song_id
* topic_id
"topics" Table
--------------
The topics table holds a selection of topics that songs can cover. This
is useful when a worship leader wants to select songs with a certain
theme. This table has the following columns:
* id
* name
The lyrics definition (more or less similar to interformat to/from ChangingSong
The tags <i></i><b></b><u></u> can also be used within the lyrics test.
! Please note that this format has been checked at http://validator.w3.org/#validate_by_upload
<lyrics lang="en_US">
<title>Amazing Grace</title>
<verse name="v1">
<theme>name of verse specific theme (optional)</theme>
<comment>any text (optional)</comment>
<part name="men">
Amazing grace, how ...
</part>
<part name="women">
A b c
D e f
</part>
...
</verse>
<verse name="c">
<theme>name of verse specific theme (optional)</theme>
<comment>any text (optional)</comment>
...
</verse>
</lyrics>
<lyrics lang="de_DE">
<title>Erstaunliche Anmut</title>
<verse name="v1">
Erstaunliche Anmut, wie
...
</verse>
<verse name="c">
...
</verse>
</lyrics>

View File

@ -31,6 +31,8 @@ import logging
from PyQt4 import QtGui
from openlp.core.lib import build_icon
log = logging.getLogger(__name__)
class OpenLPDockWidget(QtGui.QDockWidget):
@ -47,4 +49,4 @@ class OpenLPDockWidget(QtGui.QDockWidget):
if name:
self.setObjectName(name)
if icon:
self.setWindowIcon(icon)
self.setWindowIcon(build_icon(icon))

View File

@ -366,33 +366,34 @@ class MediaManagerItem(QtGui.QWidget):
count += 1
return filelist
def validate(self, file, thumb):
def validate(self, image, thumb):
"""
Validates to see if the file still exists or thumbnail is up to date
Validates whether an image still exists and, if it does, is the
thumbnail representation of the image up to date.
"""
if not os.path.exists(file):
if not os.path.exists(image):
return False
if os.path.exists(thumb):
filedate = os.stat(file).st_mtime
thumbdate = os.stat(thumb).st_mtime
# if file updated rebuild icon
if filedate > thumbdate:
self.iconFromFile(file, thumb)
imageDate = os.stat(image).st_mtime
thumbDate = os.stat(thumb).st_mtime
# If image has been updated rebuild icon
if imageDate > thumbDate:
self.iconFromFile(image, thumb)
else:
self.iconFromFile(file, thumb)
self.iconFromFile(image, thumb)
return True
def iconFromFile(self, file, thumb):
def iconFromFile(self, image, thumb):
"""
Create a thumbnail icon from a given file
Create a thumbnail icon from a given image.
``file``
The file to create the icon from
``image``
The image file to create the icon from.
``thumb``
The filename to save the thumbnail to
"""
icon = build_icon(unicode(file))
icon = build_icon(unicode(image))
pixmap = icon.pixmap(QtCore.QSize(88, 50))
ext = os.path.splitext(thumb)[1].lower()
pixmap.save(thumb, ext[1:])
@ -403,12 +404,16 @@ class MediaManagerItem(QtGui.QWidget):
u'defined by the plugin')
def onNewClick(self):
raise NotImplementedError(u'MediaManagerItem.onNewClick needs to be '
u'defined by the plugin')
"""
Hook for plugins to define behaviour for adding new items.
"""
pass
def onEditClick(self):
raise NotImplementedError(u'MediaManagerItem.onEditClick needs to be '
u'defined by the plugin')
"""
Hook for plugins to define behaviour for editing items.
"""
pass
def onDeleteClick(self):
raise NotImplementedError(u'MediaManagerItem.onDeleteClick needs to '

View File

@ -30,7 +30,7 @@ import logging
from PyQt4 import QtCore, QtGui
from openlp.core.lib import translate
from openlp.core.lib import build_icon, Receiver, translate
log = logging.getLogger(__name__)
@ -108,3 +108,77 @@ def media_item_combo_box(parent, name):
combo.setSizeAdjustPolicy(QtGui.QComboBox.AdjustToMinimumContentsLength)
combo.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Fixed)
return combo
def delete_push_button(parent, icon=None):
"""
Return a standard push button with delete label.
"""
delete_button = QtGui.QPushButton(parent)
delete_button.setObjectName(u'deleteButton')
delete_icon = icon if icon else u':/general/general_delete.png'
delete_button.setIcon(build_icon(delete_icon))
delete_button.setText(translate('OpenLP.Ui', '&Delete'))
delete_button.setToolTip(
translate('OpenLP.Ui', 'Delete the selected item.'))
QtCore.QObject.connect(delete_button,
QtCore.SIGNAL(u'clicked()'), parent.onDeleteButtonClicked)
return delete_button
def up_down_push_button_set(parent):
"""
Return a standard set of two push buttons for up and down use with lists.
"""
up_button = QtGui.QPushButton(parent)
up_button.setIcon(build_icon(u':/services/service_up.png'))
up_button.setObjectName(u'upButton')
up_button.setToolTip(
translate('OpenLP.Ui', 'Move selection up one position.'))
down_button = QtGui.QPushButton(parent)
down_button.setIcon(build_icon(u':/services/service_down.png'))
down_button.setObjectName(u'downButton')
down_button.setToolTip(
translate('OpenLP.Ui', 'Move selection down one position.'))
QtCore.QObject.connect(up_button,
QtCore.SIGNAL(u'clicked()'), parent.onUpButtonClicked)
QtCore.QObject.connect(down_button,
QtCore.SIGNAL(u'clicked()'), parent.onDownButtonClicked)
return up_button, down_button
def base_action(parent, name):
"""
Return the most basic action with the object name set.
"""
action = QtGui.QAction(parent)
action.setObjectName(name)
return action
def checkable_action(parent, name, checked=None):
"""
Return a standard action with the checkable attribute set.
"""
action = base_action(parent, name)
action.setCheckable(True)
if checked is not None:
action.setChecked(checked)
return action
def icon_action(parent, name, icon, checked=None):
"""
Return a standard action with an icon.
"""
if checked is not None:
action = checkable_action(parent, name, checked)
else:
action = base_action(parent, name)
action.setIcon(build_icon(icon))
return action
def shortcut_action(parent, text, shortcuts, function):
"""
Return a shortcut enabled action.
"""
action = QtGui.QAction(text, parent)
action.setShortcuts(shortcuts)
action.setShortcutContext(QtCore.Qt.WidgetWithChildrenShortcut)
QtCore.QObject.connect(action, QtCore.SIGNAL(u'triggered()'), function)
return action

View File

@ -28,11 +28,12 @@ import logging
from PyQt4 import QtCore, QtGui
from openlp.core.lib import RenderManager, build_icon, OpenLPDockWidget, \
SettingsManager, PluginManager, Receiver, translate
from openlp.core.lib.ui import base_action, checkable_action, icon_action
from openlp.core.ui import AboutForm, SettingsForm, ServiceManager, \
ThemeManager, SlideController, PluginForm, MediaDockManager, \
ShortcutListForm
from openlp.core.lib import RenderManager, build_icon, OpenLPDockWidget, \
SettingsManager, PluginManager, Receiver, translate
from openlp.core.utils import AppLocation, add_actions, LanguageManager, \
ActionList
@ -124,9 +125,8 @@ class Ui_MainWindow(object):
self.DefaultThemeLabel.setObjectName(u'DefaultThemeLabel')
self.StatusBar.addPermanentWidget(self.DefaultThemeLabel)
# Create the MediaManager
self.MediaManagerDock = OpenLPDockWidget(
mainWindow, u'MediaManagerDock',
build_icon(u':/system/system_mediamanager.png'))
self.MediaManagerDock = OpenLPDockWidget(mainWindow,
u'MediaManagerDock', u':/system/system_mediamanager.png')
self.MediaManagerDock.setStyleSheet(MEDIA_MANAGER_STYLE)
self.MediaManagerDock.setMinimumWidth(
self.settingsmanager.mainwindow_left)
@ -137,9 +137,8 @@ class Ui_MainWindow(object):
mainWindow.addDockWidget(QtCore.Qt.LeftDockWidgetArea,
self.MediaManagerDock)
# Create the service manager
self.ServiceManagerDock = OpenLPDockWidget(
mainWindow, u'ServiceManagerDock',
build_icon(u':/system/system_servicemanager.png'))
self.ServiceManagerDock = OpenLPDockWidget(mainWindow,
u'ServiceManagerDock', u':/system/system_servicemanager.png')
self.ServiceManagerDock.setMinimumWidth(
self.settingsmanager.mainwindow_right)
self.ServiceManagerContents = ServiceManager(mainWindow,
@ -148,9 +147,8 @@ class Ui_MainWindow(object):
mainWindow.addDockWidget(QtCore.Qt.RightDockWidgetArea,
self.ServiceManagerDock)
# Create the theme manager
self.ThemeManagerDock = OpenLPDockWidget(
mainWindow, u'ThemeManagerDock',
build_icon(u':/system/system_thememanager.png'))
self.ThemeManagerDock = OpenLPDockWidget(mainWindow,
u'ThemeManagerDock', u':/system/system_thememanager.png')
self.ThemeManagerDock.setMinimumWidth(
self.settingsmanager.mainwindow_right)
self.ThemeManagerContents = ThemeManager(mainWindow,
@ -160,103 +158,70 @@ class Ui_MainWindow(object):
mainWindow.addDockWidget(QtCore.Qt.RightDockWidgetArea,
self.ThemeManagerDock)
# Create the menu items
self.FileNewItem = QtGui.QAction(mainWindow)
self.FileNewItem.setIcon(build_icon(u':/general/general_new.png'))
self.FileNewItem.setObjectName(u'FileNewItem')
self.FileNewItem = icon_action(mainWindow, u'FileNewItem',
u':/general/general_new.png')
mainWindow.actionList.add_action(self.FileNewItem, u'File')
self.FileOpenItem = QtGui.QAction(mainWindow)
self.FileOpenItem.setIcon(build_icon(u':/general/general_open.png'))
self.FileOpenItem.setObjectName(u'FileOpenItem')
self.FileOpenItem = icon_action(mainWindow, u'FileOpenItem',
u':/general/general_open.png')
mainWindow.actionList.add_action(self.FileOpenItem, u'File')
self.FileSaveItem = QtGui.QAction(mainWindow)
self.FileSaveItem.setIcon(build_icon(u':/general/general_save.png'))
self.FileSaveItem.setObjectName(u'FileSaveItem')
self.FileSaveItem = icon_action(mainWindow, u'FileSaveItem',
u':/general/general_save.png')
mainWindow.actionList.add_action(self.FileSaveItem, u'File')
self.FileSaveAsItem = QtGui.QAction(mainWindow)
self.FileSaveAsItem.setObjectName(u'FileSaveAsItem')
self.FileSaveAsItem = base_action(mainWindow, u'FileSaveAsItem')
mainWindow.actionList.add_action(self.FileSaveAsItem, u'File')
self.printServiceOrderItem = QtGui.QAction(mainWindow)
self.printServiceOrderItem.setObjectName(u'printServiceItem')
self.printServiceOrderItem = base_action(
mainWindow, u'printServiceItem')
mainWindow.actionList.add_action(
self.printServiceOrderItem, u'Print Service Order')
self.FileExitItem = QtGui.QAction(mainWindow)
self.FileExitItem.setIcon(build_icon(u':/system/system_exit.png'))
self.FileExitItem.setObjectName(u'FileExitItem')
self.FileExitItem = icon_action(mainWindow, u'FileExitItem',
u':/system/system_exit.png')
mainWindow.actionList.add_action(self.FileExitItem, u'File')
self.ImportThemeItem = QtGui.QAction(mainWindow)
self.ImportThemeItem.setObjectName(u'ImportThemeItem')
self.ImportThemeItem = base_action(mainWindow, u'ImportThemeItem')
mainWindow.actionList.add_action(self.ImportThemeItem, u'Import')
self.ImportLanguageItem = QtGui.QAction(mainWindow)
self.ImportLanguageItem.setObjectName(u'ImportLanguageItem')
self.ImportLanguageItem = base_action(mainWindow, u'ImportLanguageItem')
mainWindow.actionList.add_action(self.ImportLanguageItem, u'Import')
self.ExportThemeItem = QtGui.QAction(mainWindow)
self.ExportThemeItem.setObjectName(u'ExportThemeItem')
self.ExportThemeItem = base_action(mainWindow, u'ExportThemeItem')
mainWindow.actionList.add_action(self.ExportThemeItem, u'Export')
self.ExportLanguageItem = QtGui.QAction(mainWindow)
self.ExportLanguageItem.setObjectName(u'ExportLanguageItem')
self.ExportLanguageItem = base_action(mainWindow, u'ExportLanguageItem')
mainWindow.actionList.add_action(self.ExportLanguageItem, u'Export')
self.ViewMediaManagerItem = QtGui.QAction(mainWindow)
self.ViewMediaManagerItem.setCheckable(True)
self.ViewMediaManagerItem.setChecked(self.MediaManagerDock.isVisible())
self.ViewMediaManagerItem.setIcon(
build_icon(u':/system/system_mediamanager.png'))
self.ViewMediaManagerItem.setObjectName(u'ViewMediaManagerItem')
self.ViewThemeManagerItem = QtGui.QAction(mainWindow)
self.ViewThemeManagerItem.setCheckable(True)
self.ViewThemeManagerItem.setChecked(self.ThemeManagerDock.isVisible())
self.ViewThemeManagerItem.setIcon(
build_icon(u':/system/system_thememanager.png'))
self.ViewThemeManagerItem.setObjectName(u'ViewThemeManagerItem')
self.ViewMediaManagerItem = icon_action(mainWindow,
u'ViewMediaManagerItem', u':/system/system_mediamanager.png',
self.MediaManagerDock.isVisible())
self.ViewThemeManagerItem = icon_action(mainWindow,
u'ViewThemeManagerItem', u':/system/system_thememanager.png',
self.ThemeManagerDock.isVisible())
mainWindow.actionList.add_action(self.ViewMediaManagerItem, u'View')
self.ViewServiceManagerItem = QtGui.QAction(mainWindow)
self.ViewServiceManagerItem.setCheckable(True)
self.ViewServiceManagerItem.setChecked(
self.ViewServiceManagerItem = icon_action(mainWindow,
u'ViewServiceManagerItem', u':/system/system_servicemanager.png',
self.ServiceManagerDock.isVisible())
self.ViewServiceManagerItem.setIcon(
build_icon(u':/system/system_servicemanager.png'))
self.ViewServiceManagerItem.setObjectName(u'ViewServiceManagerItem')
mainWindow.actionList.add_action(self.ViewServiceManagerItem, u'View')
self.ViewPreviewPanel = QtGui.QAction(mainWindow)
self.ViewPreviewPanel.setCheckable(True)
self.ViewPreviewPanel.setChecked(previewVisible)
self.ViewPreviewPanel.setObjectName(u'ViewPreviewPanel')
self.ViewPreviewPanel = checkable_action(mainWindow,
u'ViewPreviewPanel', previewVisible)
mainWindow.actionList.add_action(self.ViewPreviewPanel, u'View')
self.ViewLivePanel = QtGui.QAction(mainWindow)
self.ViewLivePanel.setCheckable(True)
self.ViewLivePanel.setChecked(liveVisible)
self.ViewLivePanel.setObjectName(u'ViewLivePanel')
self.ViewLivePanel = checkable_action(mainWindow, u'ViewLivePanel',
liveVisible)
mainWindow.actionList.add_action(self.ViewLivePanel, u'View')
self.ModeDefaultItem = QtGui.QAction(mainWindow)
self.ModeDefaultItem.setCheckable(True)
self.ModeDefaultItem.setObjectName(u'ModeDefaultItem')
self.ModeDefaultItem = checkable_action(mainWindow, u'ModeDefaultItem')
mainWindow.actionList.add_action(self.ModeDefaultItem, u'View Mode')
self.ModeSetupItem = QtGui.QAction(mainWindow)
self.ModeSetupItem.setCheckable(True)
self.ModeSetupItem.setObjectName(u'ModeLiveItem')
self.ModeSetupItem = checkable_action(mainWindow, u'ModeLiveItem')
mainWindow.actionList.add_action(self.ModeSetupItem, u'View Mode')
self.ModeLiveItem = QtGui.QAction(mainWindow)
self.ModeLiveItem.setCheckable(True)
self.ModeLiveItem.setObjectName(u'ModeLiveItem')
self.ModeLiveItem = checkable_action(mainWindow, u'ModeLiveItem')
mainWindow.actionList.add_action(self.ModeLiveItem, u'View Mode')
self.ModeGroup = QtGui.QActionGroup(mainWindow)
self.ModeGroup.addAction(self.ModeDefaultItem)
self.ModeGroup.addAction(self.ModeSetupItem)
self.ModeGroup.addAction(self.ModeLiveItem)
self.ModeDefaultItem.setChecked(True)
self.ToolsAddToolItem = QtGui.QAction(mainWindow)
self.ToolsAddToolItem.setIcon(build_icon(u':/tools/tools_add.png'))
self.ToolsAddToolItem.setObjectName(u'ToolsAddToolItem')
self.ToolsAddToolItem = icon_action(mainWindow, u'ToolsAddToolItem',
u':/tools/tools_add.png')
mainWindow.actionList.add_action(self.ToolsAddToolItem, u'Tools')
self.SettingsPluginListItem = QtGui.QAction(mainWindow)
self.SettingsPluginListItem.setIcon(
build_icon(u':/system/settings_plugin_list.png'))
self.SettingsPluginListItem.setObjectName(u'SettingsPluginListItem')
self.SettingsPluginListItem = icon_action(mainWindow,
u'SettingsPluginListItem', u':/system/settings_plugin_list.png')
mainWindow.actionList.add_action(self.SettingsPluginListItem,
u'Settings')
# i18n Language Items
self.AutoLanguageItem = QtGui.QAction(mainWindow)
self.AutoLanguageItem.setObjectName(u'AutoLanguageItem')
self.AutoLanguageItem.setCheckable(True)
self.AutoLanguageItem = checkable_action(mainWindow,
u'AutoLanguageItem')
mainWindow.actionList.add_action(self.AutoLanguageItem, u'Settings')
self.LanguageGroup = QtGui.QActionGroup(mainWindow)
self.LanguageGroup.setExclusive(True)
@ -266,39 +231,28 @@ class Ui_MainWindow(object):
qmList = LanguageManager.get_qm_list()
savedLanguage = LanguageManager.get_language()
for key in sorted(qmList.keys()):
languageItem = QtGui.QAction(mainWindow)
languageItem.setObjectName(key)
languageItem.setCheckable(True)
languageItem = checkable_action(mainWindow, key)
if qmList[key] == savedLanguage:
languageItem.setChecked(True)
add_actions(self.LanguageGroup, [languageItem])
self.SettingsShortcutsItem = QtGui.QAction(mainWindow)
self.SettingsShortcutsItem.setIcon(
build_icon(u':/system/system_configure_shortcuts.png'))
self.SettingsShortcutsItem.setObjectName(u'SettingsShortcutsItem')
self.SettingsConfigureItem = QtGui.QAction(mainWindow)
self.SettingsConfigureItem.setIcon(
build_icon(u':/system/system_settings.png'))
self.SettingsConfigureItem.setObjectName(u'SettingsConfigureItem')
self.SettingsShortcutsItem = icon_action(mainWindow,
u'SettingsShortcutsItem',
u':/system/system_configure_shortcuts.png')
self.SettingsConfigureItem = icon_action(mainWindow,
u'SettingsConfigureItem', u':/system/system_settings.png')
mainWindow.actionList.add_action(self.SettingsShortcutsItem,
u'Settings')
self.HelpDocumentationItem = QtGui.QAction(mainWindow)
self.HelpDocumentationItem.setIcon(
build_icon(u':/system/system_help_contents.png'))
self.HelpDocumentationItem.setObjectName(u'HelpDocumentationItem')
self.HelpDocumentationItem = icon_action(mainWindow,
u'HelpDocumentationItem', u':/system/system_help_contents.png')
self.HelpDocumentationItem.setEnabled(False)
mainWindow.actionList.add_action(self.HelpDocumentationItem, u'Help')
self.HelpAboutItem = QtGui.QAction(mainWindow)
self.HelpAboutItem.setIcon(
build_icon(u':/system/system_about.png'))
self.HelpAboutItem.setObjectName(u'HelpAboutItem')
self.HelpAboutItem = icon_action(mainWindow, u'HelpAboutItem',
u':/system/system_about.png')
mainWindow.actionList.add_action(self.HelpAboutItem, u'Help')
self.HelpOnlineHelpItem = QtGui.QAction(mainWindow)
self.HelpOnlineHelpItem.setObjectName(u'HelpOnlineHelpItem')
self.HelpOnlineHelpItem = base_action(mainWindow, u'HelpOnlineHelpItem')
self.HelpOnlineHelpItem.setEnabled(False)
mainWindow.actionList.add_action(self.HelpOnlineHelpItem, u'Help')
self.HelpWebSiteItem = QtGui.QAction(mainWindow)
self.HelpWebSiteItem.setObjectName(u'HelpWebSiteItem')
self.HelpWebSiteItem = base_action(mainWindow, u'HelpWebSiteItem')
mainWindow.actionList.add_action(self.HelpWebSiteItem, u'Help')
add_actions(self.FileImportMenu,
(self.ImportThemeItem, self.ImportLanguageItem))
@ -999,8 +953,8 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
u'advanced/recent file count', QtCore.QVariant(4)).toInt()[0]
self.FileMenu.clear()
add_actions(self.FileMenu, self.FileMenuActions[:-1])
existingRecentFiles = [file for file in self.recentFiles
if QtCore.QFile.exists(file)]
existingRecentFiles = [recentFile for recentFile in self.recentFiles
if QtCore.QFile.exists(recentFile)]
recentFilesToDisplay = existingRecentFiles[0:recentFileCount]
if recentFilesToDisplay:
self.FileMenu.addSeparator()

View File

@ -26,8 +26,9 @@
from PyQt4 import QtCore, QtGui
from openlp.core.lib import translate, build_icon
from openlp.core.lib.ui import save_cancel_button_box
from openlp.core.lib import translate
from openlp.core.lib.ui import save_cancel_button_box, delete_push_button, \
up_down_push_button_set
class Ui_ServiceItemEditDialog(object):
def setupUi(self, serviceItemEditDialog):
@ -40,17 +41,12 @@ class Ui_ServiceItemEditDialog(object):
self.dialogLayout.addWidget(self.listWidget, 0, 0)
self.buttonLayout = QtGui.QVBoxLayout()
self.buttonLayout.setObjectName(u'buttonLayout')
self.deleteButton = QtGui.QPushButton(serviceItemEditDialog)
self.deleteButton.setObjectName(u'deleteButton')
self.deleteButton = delete_push_button(serviceItemEditDialog)
self.buttonLayout.addWidget(self.deleteButton)
self.buttonLayout.addStretch()
self.upButton = QtGui.QPushButton(serviceItemEditDialog)
self.upButton.setIcon(build_icon(u':/services/service_up.png'))
self.upButton.setObjectName(u'upButton')
self.upButton, self.downButton = up_down_push_button_set(
serviceItemEditDialog)
self.buttonLayout.addWidget(self.upButton)
self.downButton = QtGui.QPushButton(serviceItemEditDialog)
self.downButton.setIcon(build_icon(u':/services/service_down.png'))
self.downButton.setObjectName(u'downButton')
self.buttonLayout.addWidget(self.downButton)
self.dialogLayout.addLayout(self.buttonLayout, 0, 1)
self.dialogLayout.addWidget(
@ -61,5 +57,3 @@ class Ui_ServiceItemEditDialog(object):
def retranslateUi(self, serviceItemEditDialog):
serviceItemEditDialog.setWindowTitle(
translate('OpenLP.ServiceItemEditForm', 'Reorder Service Item'))
self.deleteButton.setText(translate('OpenLP.ServiceItemEditForm',
'Delete'))

View File

@ -39,13 +39,6 @@ class ServiceItemEditForm(QtGui.QDialog, Ui_ServiceItemEditDialog):
QtGui.QDialog.__init__(self, parent)
self.setupUi(self)
self.itemList = []
# enable drop
QtCore.QObject.connect(self.upButton,
QtCore.SIGNAL(u'clicked()'), self.onItemUp)
QtCore.QObject.connect(self.downButton,
QtCore.SIGNAL(u'clicked()'), self.onItemDown)
QtCore.QObject.connect(self.deleteButton,
QtCore.SIGNAL(u'clicked()'), self.onItemDelete)
QtCore.QObject.connect(self.listWidget,
QtCore.SIGNAL(u'currentRowChanged(int)'), self.onCurrentRowChanged)
@ -77,7 +70,7 @@ class ServiceItemEditForm(QtGui.QDialog, Ui_ServiceItemEditDialog):
item_name = QtGui.QListWidgetItem(frame[u'title'])
self.listWidget.addItem(item_name)
def onItemDelete(self):
def onDeleteButtonClicked(self):
"""
Delete the current row.
"""
@ -92,13 +85,13 @@ class ServiceItemEditForm(QtGui.QDialog, Ui_ServiceItemEditDialog):
else:
self.listWidget.setCurrentRow(row)
def onItemUp(self):
def onUpButtonClicked(self):
"""
Move the current row up in the list.
"""
self.__moveItem(u'up')
def onItemDown(self):
def onDownButtonClicked(self):
"""
Move the current row down in the list
"""

View File

@ -30,9 +30,10 @@ import os
from PyQt4 import QtCore, QtGui
from PyQt4.phonon import Phonon
from openlp.core.ui import HideMode, MainDisplay
from openlp.core.lib import OpenLPToolbar, Receiver, resize_image, \
ItemCapabilities, translate
from openlp.core.lib.ui import shortcut_action
from openlp.core.ui import HideMode, MainDisplay
log = logging.getLogger(__name__)
@ -317,18 +318,8 @@ class SlideController(QtGui.QWidget):
self.mediabar.setVisible(False)
if self.isLive:
self.setLiveHotkeys(self)
self.previewListWidget.addActions(
[self.previousItem,
self.nextItem,
self.previousService,
self.nextService,
self.escapeItem])
self.display.addActions(
[self.previousItem,
self.nextItem,
self.previousService,
self.nextService,
self.escapeItem])
self.__addActionsToWidget(self.previewListWidget)
self.__addActionsToWidget(self.display)
else:
self.setPreviewHotkeys()
self.previewListWidget.addActions(
@ -390,28 +381,17 @@ class SlideController(QtGui.QWidget):
self.nextItem.setShortcuts([QtCore.Qt.Key_Down, QtCore.Qt.Key_PageDown])
self.nextItem.setShortcutContext(QtCore.Qt.WidgetWithChildrenShortcut)
actionList.add_action(self.nextItem, u'Live')
self.previousService = QtGui.QAction(translate(
'OpenLP.SlideController', 'Previous Service'), parent)
self.previousService.setShortcuts([QtCore.Qt.Key_Left, 0])
self.previousService.setShortcutContext(
QtCore.Qt.WidgetWithChildrenShortcut)
QtCore.QObject.connect(self.previousService,
QtCore.SIGNAL(u'triggered()'), self.servicePrevious)
self.previousService = shortcut_action(parent,
translate('OpenLP.SlideController', 'Previous Service'),
[QtCore.Qt.Key_Left, 0], self.servicePrevious)
actionList.add_action(self.previousService, u'Live')
self.nextService = QtGui.QAction(translate(
'OpenLP.SlideController', 'Next Service'), parent)
self.nextService.setShortcuts([QtCore.Qt.Key_Right, 0])
self.nextService.setShortcutContext(
QtCore.Qt.WidgetWithChildrenShortcut)
QtCore.QObject.connect(self.nextService,
QtCore.SIGNAL(u'triggered()'), self.serviceNext)
self.nextService = shortcut_action(parent,
translate('OpenLP.SlideController', 'Next Service'),
[QtCore.Qt.Key_Right, 0], self.serviceNext)
actionList.add_action(self.nextService, u'Live')
self.escapeItem = QtGui.QAction(translate(
'OpenLP.SlideController', 'Escape Item'), parent)
self.escapeItem.setShortcuts([QtCore.Qt.Key_Escape, 0])
self.escapeItem.setShortcutContext(QtCore.Qt.WidgetWithChildrenShortcut)
QtCore.QObject.connect(self.escapeItem,
QtCore.SIGNAL(u'triggered()'), self.liveEscape)
self.escapeItem = shortcut_action(parent,
translate('OpenLP.SlideController', 'Escape Item'),
[QtCore.Qt.Key_Escape, 0], self.liveEscape)
actionList.add_action(self.escapeItem, u'Live')
def liveEscape(self):
@ -435,12 +415,7 @@ class SlideController(QtGui.QWidget):
self.display.alertTab = self.alertTab
self.display.setup()
if self.isLive:
self.display.addActions(
[self.previousItem,
self.nextItem,
self.previousService,
self.nextService,
self.escapeItem])
self.__addActionsToWidget(self.display)
# The SlidePreview's ratio.
self.ratio = float(self.screens.current[u'size'].width()) / \
float(self.screens.current[u'size'].height())
@ -448,6 +423,12 @@ class SlideController(QtGui.QWidget):
if self.serviceItem:
self.refreshServiceItem()
def __addActionsToWidget(self, widget):
widget.addActions([
self.previousItem, self.nextItem,
self.previousService, self.nextService,
self.escapeItem])
def previewSizeChanged(self):
"""
Takes care of the SlidePreview's size. Is called when one of the the
@ -575,10 +556,7 @@ class SlideController(QtGui.QWidget):
slideno = 0
# If service item is the same as the current on only change slide
if item.__eq__(self.serviceItem):
if slideno + 1 < self.previewListWidget.rowCount():
self.previewListWidget.scrollToItem(
self.previewListWidget.item(slideno + 1, 0))
self.previewListWidget.selectRow(slideno)
self.__checkUpdateSelectedSlide(slideno)
self.onSlideSelected()
return
self._processItem(item, slideno)
@ -677,10 +655,7 @@ class SlideController(QtGui.QWidget):
self.previewListWidget.selectRow(
self.previewListWidget.rowCount() - 1)
else:
if slideno + 1 < self.previewListWidget.rowCount():
self.previewListWidget.scrollToItem(
self.previewListWidget.item(slideno + 1, 0))
self.previewListWidget.selectRow(slideno)
self.__checkUpdateSelectedSlide(slideno)
def onTextRequest(self):
"""
@ -729,10 +704,7 @@ class SlideController(QtGui.QWidget):
[self.serviceItem, self.isLive, index])
self.updatePreview()
else:
if index + 1 < self.previewListWidget.rowCount():
self.previewListWidget.scrollToItem(
self.previewListWidget.item(index + 1, 0))
self.previewListWidget.selectRow(index)
self.__checkUpdateSelectedSlide(index)
self.onSlideSelected()
def mainDisplaySetBackground(self):
@ -891,10 +863,7 @@ class SlideController(QtGui.QWidget):
"""
The slide has been changed. Update the slidecontroller accordingly
"""
if row + 1 < self.previewListWidget.rowCount():
self.previewListWidget.scrollToItem(
self.previewListWidget.item(row + 1, 0))
self.previewListWidget.selectRow(row)
self.__checkUpdateSelectedSlide(row)
self.updatePreview()
Receiver.send_message(u'slidecontroller_%s_changed' % self.typePrefix,
row)
@ -945,10 +914,7 @@ class SlideController(QtGui.QWidget):
else:
Receiver.send_message('servicemanager_next_item')
return
if row + 1 < self.previewListWidget.rowCount():
self.previewListWidget.scrollToItem(
self.previewListWidget.item(row + 1, 0))
self.previewListWidget.selectRow(row)
self.__checkUpdateSelectedSlide(row)
self.onSlideSelected()
def onSlideSelectedPreviousNoloop(self):
@ -971,12 +937,15 @@ class SlideController(QtGui.QWidget):
row = self.previewListWidget.rowCount() - 1
else:
row = 0
if row + 1 < self.previewListWidget.rowCount():
self.previewListWidget.scrollToItem(
self.previewListWidget.item(row + 1, 0))
self.previewListWidget.selectRow(row)
self.__checkUpdateSelectedSlide(row)
self.onSlideSelected()
def __checkUpdateSelectedSlide(self, row):
if row + 1 < self.previewListWidget.rowCount():
self.previewListWidget.scrollToItem(
self.previewListWidget.item(row + 1, 0))
self.previewListWidget.selectRow(row)
def onSlideSelectedLast(self):
"""
Go to the last slide.

View File

@ -36,6 +36,8 @@ class Ui_ThemeWizard(object):
themeWizard.setWizardStyle(QtGui.QWizard.ModernStyle)
themeWizard.setOptions(QtGui.QWizard.IndependentPages |
QtGui.QWizard.NoBackButtonOnStartPage)
self.spacer = QtGui.QSpacerItem(10, 0,
QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Minimum)
# Welcome Page
add_welcome_page(themeWizard, u':/wizards/wizard_createtheme.bmp')
# Background Page
@ -52,10 +54,8 @@ class Ui_ThemeWizard(object):
self.backgroundComboBox.setObjectName(u'BackgroundComboBox')
self.backgroundTypeLayout.addRow(self.backgroundLabel,
self.backgroundComboBox)
self.backgroundTypeSpacer = QtGui.QSpacerItem(10, 0,
QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Minimum)
self.backgroundTypeLayout.setItem(1, QtGui.QFormLayout.LabelRole,
self.backgroundTypeSpacer)
self.spacer)
self.backgroundLayout.addLayout(self.backgroundTypeLayout)
self.backgroundStack = QtGui.QStackedLayout()
self.backgroundStack.setObjectName(u'BackgroundStack')
@ -69,10 +69,7 @@ class Ui_ThemeWizard(object):
self.colorButton = QtGui.QPushButton(self.colorWidget)
self.colorButton.setObjectName(u'ColorButton')
self.colorLayout.addRow(self.colorLabel, self.colorButton)
self.colorSpacer = QtGui.QSpacerItem(10, 0, QtGui.QSizePolicy.Fixed,
QtGui.QSizePolicy.Minimum)
self.colorLayout.setItem(1, QtGui.QFormLayout.LabelRole,
self.colorSpacer)
self.colorLayout.setItem(1, QtGui.QFormLayout.LabelRole, self.spacer)
self.backgroundStack.addWidget(self.colorWidget)
self.gradientWidget = QtGui.QWidget(self.backgroundPage)
self.gradientWidget.setObjectName(u'GradientWidget')
@ -98,10 +95,7 @@ class Ui_ThemeWizard(object):
self.gradientComboBox.addItems([u'', u'', u'', u'', u''])
self.gradientLayout.addRow(self.gradientTypeLabel,
self.gradientComboBox)
self.gradientSpacer = QtGui.QSpacerItem(10, 0, QtGui.QSizePolicy.Fixed,
QtGui.QSizePolicy.Minimum)
self.gradientLayout.setItem(3, QtGui.QFormLayout.LabelRole,
self.gradientSpacer)
self.gradientLayout.setItem(3, QtGui.QFormLayout.LabelRole, self.spacer)
self.backgroundStack.addWidget(self.gradientWidget)
self.imageWidget = QtGui.QWidget(self.backgroundPage)
self.imageWidget.setObjectName(u'ImageWidget')
@ -121,10 +115,7 @@ class Ui_ThemeWizard(object):
build_icon(u':/general/general_open.png'))
self.imageFileLayout.addWidget(self.imageBrowseButton)
self.imageLayout.addRow(self.imageLabel, self.imageFileLayout)
self.imageSpacer = QtGui.QSpacerItem(10, 0, QtGui.QSizePolicy.Fixed,
QtGui.QSizePolicy.Minimum)
self.imageLayout.setItem(1, QtGui.QFormLayout.LabelRole,
self.imageSpacer)
self.imageLayout.setItem(1, QtGui.QFormLayout.LabelRole, self.spacer)
self.backgroundStack.addWidget(self.imageWidget)
self.backgroundLayout.addLayout(self.backgroundStack)
themeWizard.addPage(self.backgroundPage)
@ -236,6 +227,8 @@ class Ui_ThemeWizard(object):
self.footerSizeSpinBox.setObjectName(u'FooterSizeSpinBox')
self.footerAreaLayout.addRow(self.footerSizeLabel,
self.footerSizeSpinBox)
self.footerAreaLayout.setItem(3, QtGui.QFormLayout.LabelRole,
self.spacer)
themeWizard.addPage(self.footerAreaPage)
# Alignment Page
self.alignmentPage = QtGui.QWizardPage()
@ -261,6 +254,8 @@ class Ui_ThemeWizard(object):
self.transitionsCheckBox.setObjectName(u'TransitionsCheckBox')
self.alignmentLayout.addRow(self.transitionsLabel,
self.transitionsCheckBox)
self.alignmentLayout.setItem(3, QtGui.QFormLayout.LabelRole,
self.spacer)
themeWizard.addPage(self.alignmentPage)
# Area Position Page
self.areaPositionPage = QtGui.QWizardPage()
@ -552,16 +547,6 @@ class Ui_ThemeWizard(object):
translate('OpenLP.ThemeWizard', 'Theme name:'))
# Align all QFormLayouts towards each other.
labelWidth = max(self.backgroundLabel.minimumSizeHint().width(),
self.colorLabel.minimumSizeHint().width(),
self.gradientStartLabel.minimumSizeHint().width(),
self.gradientEndLabel.minimumSizeHint().width(),
self.gradientTypeLabel.minimumSizeHint().width(),
self.imageLabel.minimumSizeHint().width())
self.backgroundTypeSpacer.changeSize(labelWidth, 0,
QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Fixed)
self.colorSpacer.changeSize(labelWidth, 0,
QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Fixed)
self.gradientSpacer.changeSize(labelWidth, 0,
QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Fixed)
self.imageSpacer.changeSize(labelWidth, 0,
self.horizontalLabel.minimumSizeHint().width())
self.spacer.changeSize(labelWidth, 0,
QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Fixed)

View File

@ -27,6 +27,7 @@
from PyQt4 import QtCore, QtGui
from openlp.core.lib import build_icon, translate
from openlp.core.lib.ui import delete_push_button
class Ui_AlertDialog(object):
def setupUi(self, alertDialog):
@ -65,9 +66,8 @@ class Ui_AlertDialog(object):
self.saveButton.setIcon(build_icon(u':/general/general_save.png'))
self.saveButton.setObjectName(u'saveButton')
self.manageButtonLayout.addWidget(self.saveButton)
self.deleteButton = QtGui.QPushButton(alertDialog)
self.deleteButton.setIcon(build_icon(u':/general/general_delete.png'))
self.deleteButton.setObjectName(u'deleteButton')
self.deleteButton = delete_push_button(alertDialog)
self.deleteButton.setEnabled(False)
self.manageButtonLayout.addWidget(self.deleteButton)
self.manageButtonLayout.addStretch()
self.alertDialogLayout.addLayout(self.manageButtonLayout, 1, 1)
@ -75,11 +75,13 @@ class Ui_AlertDialog(object):
self.buttonBox.addButton(QtGui.QDialogButtonBox.Close)
displayIcon = build_icon(u':/general/general_live.png')
self.displayButton = QtGui.QPushButton(alertDialog)
self.displayButton.setEnabled(False)
self.displayButton.setIcon(displayIcon)
self.displayButton.setObjectName(u'displayButton')
self.buttonBox.addButton(self.displayButton,
QtGui.QDialogButtonBox.ActionRole)
self.displayCloseButton = QtGui.QPushButton(alertDialog)
self.displayCloseButton.setEnabled(False)
self.displayCloseButton.setIcon(displayIcon)
self.displayCloseButton.setObjectName(u'displayCloseButton')
self.buttonBox.addButton(self.displayCloseButton,
@ -101,8 +103,6 @@ class Ui_AlertDialog(object):
translate('AlertsPlugin.AlertForm', '&New'))
self.saveButton.setText(
translate('AlertsPlugin.AlertForm', '&Save'))
self.deleteButton.setText(
translate('AlertsPlugin.AlertForm', '&Delete'))
self.displayButton.setText(
translate('AlertsPlugin.AlertForm', 'Displ&ay'))
self.displayCloseButton.setText(

View File

@ -44,22 +44,22 @@ class AlertForm(QtGui.QDialog, Ui_AlertDialog):
self.item_id = None
QtGui.QDialog.__init__(self, plugin.formparent)
self.setupUi(self)
QtCore.QObject.connect(self.displayButton, QtCore.SIGNAL(u'clicked()'),
self.onDisplayClicked)
QtCore.QObject.connect(self.displayButton,
QtCore.SIGNAL(u'clicked()'), self.onDisplayClicked)
QtCore.QObject.connect(self.displayCloseButton,
QtCore.SIGNAL(u'clicked()'), self.onDisplayCloseClicked)
QtCore.QObject.connect(self.alertTextEdit,
QtCore.SIGNAL(u'textChanged(const QString&)'), self.onTextChanged)
QtCore.QObject.connect(self.newButton, QtCore.SIGNAL(u'clicked()'),
self.onNewClick)
QtCore.QObject.connect(self.deleteButton, QtCore.SIGNAL(u'clicked()'),
self.onDeleteClick)
QtCore.QObject.connect(self.saveButton, QtCore.SIGNAL(u'clicked()'),
self.onSaveClick)
QtCore.QObject.connect(self.newButton,
QtCore.SIGNAL(u'clicked()'), self.onNewClick)
QtCore.QObject.connect(self.saveButton,
QtCore.SIGNAL(u'clicked()'), self.onSaveClick)
QtCore.QObject.connect(self.alertListWidget,
QtCore.SIGNAL(u'doubleClicked(QModelIndex)'), self.onDoubleClick)
QtCore.QObject.connect(self.alertListWidget,
QtCore.SIGNAL(u'clicked(QModelIndex)'), self.onSingleClick)
QtCore.QObject.connect(self.alertListWidget,
QtCore.SIGNAL(u'currentRowChanged(int)'), self.onCurrentRowChanged)
def loadList(self):
"""
@ -72,18 +72,15 @@ class AlertForm(QtGui.QDialog, Ui_AlertDialog):
item_name = QtGui.QListWidgetItem(alert.text)
item_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(alert.id))
self.alertListWidget.addItem(item_name)
self.saveButton.setEnabled(False)
self.deleteButton.setEnabled(False)
def onDisplayClicked(self):
if self.triggerAlert(unicode(self.alertTextEdit.text())):
self.loadList()
self.triggerAlert(unicode(self.alertTextEdit.text()))
def onDisplayCloseClicked(self):
if self.triggerAlert(unicode(self.alertTextEdit.text())):
self.close()
def onDeleteClick(self):
def onDeleteButtonClicked(self):
"""
Deletes the selected item.
"""
@ -95,8 +92,6 @@ class AlertForm(QtGui.QDialog, Ui_AlertDialog):
self.alertListWidget.takeItem(row)
self.item_id = None
self.alertTextEdit.setText(u'')
self.saveButton.setEnabled(False)
self.deleteButton.setEnabled(False)
def onNewClick(self):
if len(self.alertTextEdit.text()) == 0:
@ -135,30 +130,26 @@ class AlertForm(QtGui.QDialog, Ui_AlertDialog):
"""
List item has been double clicked to display it
"""
items = self.alertListWidget.selectedIndexes()
for item in items:
bitem = self.alertListWidget.item(item.row())
self.triggerAlert(unicode(bitem.text()))
self.alertTextEdit.setText(unicode(bitem.text()))
self.item_id = (bitem.data(QtCore.Qt.UserRole)).toInt()[0]
item = self.alertListWidget.selectedIndexes()[0]
bitem = self.alertListWidget.item(item.row())
self.triggerAlert(unicode(bitem.text()))
self.alertTextEdit.setText(unicode(bitem.text()))
self.item_id = (bitem.data(QtCore.Qt.UserRole)).toInt()[0]
self.saveButton.setEnabled(False)
self.deleteButton.setEnabled(True)
def onSingleClick(self):
"""
List item has been single clicked to add it to
the edit field so it can be changed.
"""
items = self.alertListWidget.selectedIndexes()
for item in items:
bitem = self.alertListWidget.item(item.row())
self.alertTextEdit.setText(unicode(bitem.text()))
self.item_id = (bitem.data(QtCore.Qt.UserRole)).toInt()[0]
item = self.alertListWidget.selectedIndexes()[0]
bitem = self.alertListWidget.item(item.row())
self.alertTextEdit.setText(unicode(bitem.text()))
self.item_id = (bitem.data(QtCore.Qt.UserRole)).toInt()[0]
# If the alert does not contain '<>' we clear the ParameterEdit field.
if unicode(self.alertTextEdit.text()).find(u'<>') == -1:
self.parameterEdit.setText(u'')
self.saveButton.setEnabled(False)
self.deleteButton.setEnabled(True)
def triggerAlert(self, text):
"""
@ -167,30 +158,49 @@ class AlertForm(QtGui.QDialog, Ui_AlertDialog):
``text``
The alert text (unicode).
"""
if text:
# We found '<>' in the alert text, but the ParameterEdit field is
# empty.
if text.find(u'<>') != -1 and not self.parameterEdit.text() and \
QtGui.QMessageBox.question(self,
translate('AlertPlugin.AlertForm', 'No Parameter found'),
translate('AlertPlugin.AlertForm', 'You have not entered a '
'parameter to be replaced.\nDo you want to continue anyway?'),
QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.No |
QtGui.QMessageBox.Yes)) == QtGui.QMessageBox.No:
self.parameterEdit.setFocus()
return False
# The ParameterEdit field is not empty, but we have not found '<>'
# in the alert text.
elif text.find(u'<>') == -1 and self.parameterEdit.text() and \
QtGui.QMessageBox.question(self,
translate('AlertPlugin.AlertForm', 'No Placeholder found'),
translate('AlertPlugin.AlertForm', 'The alert text does not'
' contain \'<>\'.\nDo want to continue anyway?'),
QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.No |
QtGui.QMessageBox.Yes)) == QtGui.QMessageBox.No:
self.parameterEdit.setFocus()
return False
text = text.replace(u'<>', unicode(self.parameterEdit.text()))
self.parent.alertsmanager.displayAlert(text)
return True
return False
if not text:
return False
# We found '<>' in the alert text, but the ParameterEdit field is empty.
if text.find(u'<>') != -1 and not self.parameterEdit.text() and \
QtGui.QMessageBox.question(self,
translate('AlertPlugin.AlertForm', 'No Parameter found'),
translate('AlertPlugin.AlertForm', 'You have not entered a '
'parameter to be replaced.\nDo you want to continue anyway?'),
QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.No |
QtGui.QMessageBox.Yes)) == QtGui.QMessageBox.No:
self.parameterEdit.setFocus()
return False
# The ParameterEdit field is not empty, but we have not found '<>'
# in the alert text.
elif text.find(u'<>') == -1 and self.parameterEdit.text() and \
QtGui.QMessageBox.question(self,
translate('AlertPlugin.AlertForm', 'No Placeholder found'),
translate('AlertPlugin.AlertForm', 'The alert text does not'
' contain \'<>\'.\nDo want to continue anyway?'),
QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.No |
QtGui.QMessageBox.Yes)) == QtGui.QMessageBox.No:
self.parameterEdit.setFocus()
return False
text = text.replace(u'<>', unicode(self.parameterEdit.text()))
self.parent.alertsmanager.displayAlert(text)
return True
def onCurrentRowChanged(self, row):
"""
Called when the *alertListWidget*'s current row has been changed. This
enables or disables buttons which require an item to act on.
``row``
The row (int). If there is no current row, the value is -1.
"""
if row == -1:
self.displayButton.setEnabled(False)
self.displayCloseButton.setEnabled(False)
self.saveButton.setEnabled(False)
self.deleteButton.setEnabled(False)
else:
self.displayButton.setEnabled(True)
self.displayCloseButton.setEnabled(True)
self.deleteButton.setEnabled(True)
# We do not need to enable the save button, as it is only enabled
# when typing text in the "alertTextEdit".

View File

@ -157,10 +157,9 @@ class BibleImportForm(OpenLPWizard):
self.formatComboBox.addItems([u'', u'', u'', u'', u''])
self.formatComboBox.setObjectName(u'FormatComboBox')
self.formatLayout.addRow(self.formatLabel, self.formatComboBox)
self.formatSpacer = QtGui.QSpacerItem(10, 0, QtGui.QSizePolicy.Fixed,
self.spacer = QtGui.QSpacerItem(10, 0, QtGui.QSizePolicy.Fixed,
QtGui.QSizePolicy.Minimum)
self.formatLayout.setItem(1, QtGui.QFormLayout.LabelRole,
self.formatSpacer)
self.formatLayout.setItem(1, QtGui.QFormLayout.LabelRole, self.spacer)
self.selectPageLayout.addLayout(self.formatLayout)
self.selectStack = QtGui.QStackedLayout()
self.selectStack.setObjectName(u'SelectStack')
@ -181,9 +180,7 @@ class BibleImportForm(OpenLPWizard):
self.osisBrowseButton.setObjectName(u'OsisBrowseButton')
self.osisFileLayout.addWidget(self.osisBrowseButton)
self.osisLayout.addRow(self.osisFileLabel, self.osisFileLayout)
self.osisSpacer = QtGui.QSpacerItem(10, 0, QtGui.QSizePolicy.Fixed,
QtGui.QSizePolicy.Minimum)
self.osisLayout.setItem(1, QtGui.QFormLayout.LabelRole, self.osisSpacer)
self.osisLayout.setItem(1, QtGui.QFormLayout.LabelRole, self.spacer)
self.selectStack.addWidget(self.osisWidget)
self.csvWidget = QtGui.QWidget(self.selectPage)
self.csvWidget.setObjectName(u'CsvWidget')
@ -226,9 +223,7 @@ class BibleImportForm(OpenLPWizard):
self.csvVersesButton.setObjectName(u'CsvVersesButton')
self.csvVersesLayout.addWidget(self.csvVersesButton)
self.csvLayout.addRow(self.csvVersesLabel, self.csvVersesLayout)
self.csvSpacer = QtGui.QSpacerItem(10, 0, QtGui.QSizePolicy.Fixed,
QtGui.QSizePolicy.Minimum)
self.csvLayout.setItem(3, QtGui.QFormLayout.LabelRole, self.csvSpacer)
self.csvLayout.setItem(3, QtGui.QFormLayout.LabelRole, self.spacer)
self.selectStack.addWidget(self.csvWidget)
self.openSongWidget = QtGui.QWidget(self.selectPage)
self.openSongWidget.setObjectName(u'OpenSongWidget')
@ -248,10 +243,7 @@ class BibleImportForm(OpenLPWizard):
self.openSongFileLayout.addWidget(self.openSongBrowseButton)
self.openSongLayout.addRow(self.openSongFileLabel,
self.openSongFileLayout)
self.openSongSpacer = QtGui.QSpacerItem(10, 0, QtGui.QSizePolicy.Fixed,
QtGui.QSizePolicy.Minimum)
self.openSongLayout.setItem(1, QtGui.QFormLayout.LabelRole,
self.openSongSpacer)
self.openSongLayout.setItem(1, QtGui.QFormLayout.LabelRole, self.spacer)
self.selectStack.addWidget(self.openSongWidget)
self.webTabWidget = QtGui.QTabWidget(self.selectPage)
self.webTabWidget.setObjectName(u'WebTabWidget')
@ -330,10 +322,7 @@ class BibleImportForm(OpenLPWizard):
self.openlp1DisabledLabel.setWordWrap(True)
self.openlp1DisabledLabel.setObjectName(u'Openlp1DisabledLabel')
self.openlp1Layout.addRow(self.openlp1DisabledLabel)
self.openlp1Spacer = QtGui.QSpacerItem(10, 0, QtGui.QSizePolicy.Fixed,
QtGui.QSizePolicy.Minimum)
self.openlp1Layout.setItem(1, QtGui.QFormLayout.LabelRole,
self.openlp1Spacer)
self.openlp1Layout.setItem(1, QtGui.QFormLayout.LabelRole, self.spacer)
self.selectStack.addWidget(self.openlp1Widget)
self.selectPageLayout.addLayout(self.selectStack)
self.addPage(self.selectPage)
@ -401,17 +390,17 @@ class BibleImportForm(OpenLPWizard):
self.formatComboBox.setItemText(4,
translate('BiblesPlugin.ImportWizardForm', 'openlp.org 1.x'))
self.openlp1FileLabel.setText(
translate('BiblesPlugin.ImportWizardForm', 'File location:'))
translate('BiblesPlugin.ImportWizardForm', 'Bible file:'))
self.osisFileLabel.setText(
translate('BiblesPlugin.ImportWizardForm', 'File location:'))
translate('BiblesPlugin.ImportWizardForm', 'Bible file:'))
self.csvTestamentsLabel.setText(
translate('BiblesPlugin.ImportWizardForm', 'Testaments location:'))
translate('BiblesPlugin.ImportWizardForm', 'Testaments file:'))
self.csvBooksLabel.setText(
translate('BiblesPlugin.ImportWizardForm', 'Books location:'))
translate('BiblesPlugin.ImportWizardForm', 'Books file:'))
self.csvVersesLabel.setText(
translate('BiblesPlugin.ImportWizardForm', 'Verse location:'))
translate('BiblesPlugin.ImportWizardForm', 'Verses file:'))
self.openSongFileLabel.setText(
translate('BiblesPlugin.ImportWizardForm', 'Bible filename:'))
translate('BiblesPlugin.ImportWizardForm', 'Bible file:'))
self.webSourceLabel.setText(
translate('BiblesPlugin.ImportWizardForm', 'Location:'))
self.webSourceComboBox.setItemText(0,
@ -462,19 +451,12 @@ class BibleImportForm(OpenLPWizard):
# Align all QFormLayouts towards each other.
labelWidth = max(self.formatLabel.minimumSizeHint().width(),
self.osisFileLabel.minimumSizeHint().width(),
self.csvTestamentsLabel.minimumSizeHint().width(),
self.csvBooksLabel.minimumSizeHint().width(),
self.csvVersesLabel.minimumSizeHint().width(),
self.openSongFileLabel.minimumSizeHint().width(),
self.openlp1FileLabel.minimumSizeHint().width())
self.formatSpacer.changeSize(labelWidth, 0,
QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Fixed)
self.osisSpacer.changeSize(labelWidth, 0,
QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Fixed)
self.csvSpacer.changeSize(labelWidth, 0,
QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Fixed)
self.openSongSpacer.changeSize(labelWidth, 0,
QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Fixed)
self.openlp1Spacer.changeSize(labelWidth, 0,
self.spacer.changeSize(labelWidth, 0,
QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Fixed)
def validateCurrentPage(self):

View File

@ -77,9 +77,9 @@ def parse_reference(reference):
- After a verse reference all further single values are treat as verse in
the last selected chapter.
``John 3:16-18`` refers to John chapter 3 verses 16 to 18
- After a list separator it is possible to refer to additional verses. They
are build analog to the first ones. This way it is possible to define
each number of verse references. It is not possible to refer to verses in
- After a list separator it is possible to refer to additional verses. They
are build analog to the first ones. This way it is possible to define each
number of verse references. It is not possible to refer to verses in
additional books.
``John 3:16,18`` refers to John chapter 3 verses 16 and 18
``John 3:16-18,20`` refers to John chapter 3 verses 16 to 18 and 20
@ -91,7 +91,7 @@ def parse_reference(reference):
``range_string`` is a regular expression which matches for verse range
declarations:
1. ``(?:(?P<from_chapter>[0-9]+)%(sep_v)s)?'
1. ``(?:(?P<from_chapter>[0-9]+)%(sep_v)s)?``
It starts with a optional chapter reference ``from_chapter`` followed by
a verse separator.
2. ``(?P<from_verse>[0-9]+)``
@ -105,7 +105,7 @@ def parse_reference(reference):
5. ``(?P<to_verse>[0-9]+)``
The ``to_verse`` reference is equivalent to group 2.
The full reference is matched against get_reference_match(u'full'). This
The full reference is matched against get_reference_match(u'full'). This
regular expression looks like this:
1. ``^\s*(?!\s)(?P<book>[\d]*[^\d]+)(?<!\s)\s*``
@ -113,7 +113,7 @@ def parse_reference(reference):
are optional leading digits followed by non-digits. The group ends
before the whitspace in front of the next digit.
2. ``(?P<ranges>(?:`` + range_string + ``(?:%(sep_l)s|(?=\s*$)))+)\s*$``
The second group contains all ``ranges``. This can be multiple
The second group contains all ``ranges``. This can be multiple
declarations of a range_string separated by a list separator.
The reference list is a list of tuples, with each tuple structured like

View File

@ -27,7 +27,8 @@
from PyQt4 import QtCore, QtGui
from openlp.core.lib import build_icon, translate
from openlp.core.lib.ui import save_cancel_button_box
from openlp.core.lib.ui import save_cancel_button_box, delete_push_button, \
up_down_push_button_set
class Ui_CustomEditDialog(object):
def setupUi(self, customEditDialog):
@ -64,17 +65,12 @@ class Ui_CustomEditDialog(object):
self.editAllButton = QtGui.QPushButton(customEditDialog)
self.editAllButton.setObjectName(u'editAllButton')
self.buttonLayout.addWidget(self.editAllButton)
self.deleteButton = QtGui.QPushButton(customEditDialog)
self.deleteButton.setObjectName(u'deleteButton')
self.deleteButton = delete_push_button(customEditDialog)
self.buttonLayout.addWidget(self.deleteButton)
self.buttonLayout.addStretch()
self.upButton = QtGui.QPushButton(customEditDialog)
self.upButton.setIcon(build_icon(u':/services/service_up.png'))
self.upButton.setObjectName(u'upButton')
self.upButton, self.downButton = up_down_push_button_set(
customEditDialog)
self.buttonLayout.addWidget(self.upButton)
self.downButton = QtGui.QPushButton(customEditDialog)
self.downButton.setIcon(build_icon(u':/services/service_down.png'))
self.downButton.setObjectName(u'downButton')
self.buttonLayout.addWidget(self.downButton)
self.centralLayout.addLayout(self.buttonLayout)
self.dialogLayout.addLayout(self.centralLayout)
@ -102,12 +98,6 @@ class Ui_CustomEditDialog(object):
def retranslateUi(self, customEditDialog):
customEditDialog.setWindowTitle(
translate('CustomPlugin.EditCustomForm', 'Edit Custom Slides'))
self.upButton.setToolTip(
translate('CustomPlugin.EditCustomForm', 'Move slide up one '
'position.'))
self.downButton.setToolTip(
translate('CustomPlugin.EditCustomForm', 'Move slide down one '
'position.'))
self.titleLabel.setText(
translate('CustomPlugin.EditCustomForm', '&Title:'))
self.addButton.setText(
@ -125,11 +115,6 @@ class Ui_CustomEditDialog(object):
self.editAllButton.setToolTip(
translate('CustomPlugin.EditCustomForm', 'Edit all the slides at '
'once.'))
self.deleteButton.setText(
translate('CustomPlugin.EditCustomForm', '&Delete'))
self.deleteButton.setToolTip(
translate('CustomPlugin.EditCustomForm', 'Delete the selected '
'slide.'))
self.themeLabel.setText(
translate('CustomPlugin.EditCustomForm', 'The&me:'))
self.creditLabel.setText(

View File

@ -62,12 +62,6 @@ class EditCustomForm(QtGui.QDialog, Ui_CustomEditDialog):
QtCore.SIGNAL(u'pressed()'), self.onEditButtonPressed)
QtCore.QObject.connect(self.editAllButton,
QtCore.SIGNAL(u'pressed()'), self.onEditAllButtonPressed)
QtCore.QObject.connect(self.deleteButton,
QtCore.SIGNAL(u'pressed()'), self.onDeleteButtonPressed)
QtCore.QObject.connect(self.upButton,
QtCore.SIGNAL(u'pressed()'), self.onUpButtonPressed)
QtCore.QObject.connect(self.downButton,
QtCore.SIGNAL(u'pressed()'), self.onDownButtonPressed)
QtCore.QObject.connect(self.slideListView,
QtCore.SIGNAL(u'itemClicked(QListWidgetItem*)'),
self.onSlideListViewPressed)
@ -168,14 +162,14 @@ class EditCustomForm(QtGui.QDialog, Ui_CustomEditDialog):
self.customSlide.theme_name = unicode(self.themeComboBox.currentText())
return self.manager.save_object(self.customSlide)
def onUpButtonPressed(self):
def onUpButtonClicked(self):
selectedRow = self.slideListView.currentRow()
if selectedRow != 0:
qw = self.slideListView.takeItem(selectedRow)
self.slideListView.insertItem(selectedRow - 1, qw)
self.slideListView.setCurrentRow(selectedRow - 1)
def onDownButtonPressed(self):
def onDownButtonClicked(self):
selectedRow = self.slideListView.currentRow()
# zero base arrays
if selectedRow != self.slideListView.count() - 1:
@ -243,7 +237,7 @@ class EditCustomForm(QtGui.QDialog, Ui_CustomEditDialog):
self.slideListView.addItem(slide)
self.slideListView.repaint()
def onDeleteButtonPressed(self):
def onDeleteButtonClicked(self):
self.slideListView.takeItem(self.slideListView.currentRow())
self.editButton.setEnabled(True)
self.editAllButton.setEnabled(True)

View File

@ -123,19 +123,19 @@ class ImageMediaItem(MediaManagerItem):
self.settingsSection, self.getFileList())
def loadList(self, list):
for file in list:
filename = os.path.split(unicode(file))[1]
for imageFile in list:
filename = os.path.split(unicode(imageFile))[1]
thumb = os.path.join(self.servicePath, filename)
if os.path.exists(thumb):
if self.validate(file, thumb):
if self.validate(imageFile, thumb):
icon = build_icon(thumb)
else:
icon = build_icon(u':/general/general_delete.png')
else:
icon = self.iconFromFile(file, thumb)
icon = self.iconFromFile(imageFile, thumb)
item_name = QtGui.QListWidgetItem(filename)
item_name.setIcon(icon)
item_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(file))
item_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(imageFile))
self.listView.addItem(item_name)
def generateSlideData(self, service_item, item=None, xmlVersion=False):

View File

@ -162,6 +162,8 @@ class SongImportForm(OpenLPWizard):
self.formatLayout.setItem(1, QtGui.QFormLayout.LabelRole,
self.formatSpacer)
self.sourceLayout.addLayout(self.formatLayout)
self.stackSpacer = QtGui.QSpacerItem(10, 0, QtGui.QSizePolicy.Fixed,
QtGui.QSizePolicy.Expanding)
self.formatStack = QtGui.QStackedLayout()
self.formatStack.setObjectName(u'FormatStack')
# OpenLP 2.0
@ -807,10 +809,8 @@ class SongImportForm(OpenLPWizard):
browseButton.setIcon(self.openIcon)
browseButton.setObjectName(obj_prefix + u'BrowseButton')
fileLayout.addWidget(browseButton)
formSpacer = QtGui.QSpacerItem(10, 0, QtGui.QSizePolicy.Fixed,
QtGui.QSizePolicy.Expanding)
importLayout.addLayout(fileLayout)
importLayout.addSpacerItem(formSpacer)
importLayout.addSpacerItem(self.stackSpacer)
else:
fileListWidget = QtGui.QListWidget(importWidget)
fileListWidget.setSelectionMode(
@ -859,6 +859,7 @@ class SongImportForm(OpenLPWizard):
disabledLabel.setWordWrap(True)
disabledLabel.setObjectName(obj_prefix + u'DisabledLabel')
disabledLayout.addWidget(disabledLabel)
disabledLayout.addSpacerItem(self.stackSpacer)
layout.addWidget(disabledWidget)
importWidget = QtGui.QWidget(page)
importWidget.setObjectName(obj_prefix + u'ImportWidget')

View File

@ -483,19 +483,19 @@ class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog):
def onAuthorsListRowChanged(self, row):
"""
Called when the *authorsListWidget*s current row has changed.
Called when the *authorsListWidget*'s current row has changed.
"""
self.__rowChange(row, self.authorsEditButton, self.authorsDeleteButton)
def onTopicsListRowChanged(self, row):
"""
Called when the *topicsListWidget*s current row has changed.
Called when the *topicsListWidget*'s current row has changed.
"""
self.__rowChange(row, self.topicsEditButton, self.topicsDeleteButton)
def onBooksListRowChanged(self, row):
"""
Called when the *booksListWidget*s current row has changed.
Called when the *booksListWidget*'s current row has changed.
"""
self.__rowChange(row, self.booksEditButton, self.booksDeleteButton)

View File

@ -39,6 +39,7 @@ class Author(BaseModel):
"""
pass
class Book(BaseModel):
"""
Book model
@ -47,30 +48,115 @@ class Book(BaseModel):
return u'<Book id="%s" name="%s" publisher="%s" />' % (
str(self.id), self.name, self.publisher)
class MediaFile(BaseModel):
"""
MediaFile model
"""
pass
class Song(BaseModel):
"""
Song model
"""
pass
class Topic(BaseModel):
"""
Topic model
"""
pass
def init_schema(url):
"""
Setup the songs database connection and initialise the database schema
Setup the songs database connection and initialise the database schema.
``url``
The database to setup
The song database contains the following tables:
* authors
* authors_songs
* media_files
* media_files_songs
* song_books
* songs
* songs_topics
* topics
**authors** Table
This table holds the names of all the authors. It has the following
columns:
* id
* first_name
* last_name
* display_name
**authors_songs Table**
This is a bridging table between the *authors* and *songs* tables, which
serves to create a many-to-many relationship between the two tables. It
has the following columns:
* author_id
* song_id
**media_files Table**
* id
* file_name
* type
**media_files_songs Table**
* media_file_id
* song_id
**song_books Table**
The *song_books* table holds a list of books that a congregation gets
their songs from, or old hymnals now no longer used. This table has the
following columns:
* id
* name
* publisher
**songs Table**
This table contains the songs, and each song has a list of attributes.
The *songs* table has the following columns:
* id
* song_book_id
* title
* alternate_title
* lyrics
* verse_order
* copyright
* comments
* ccli_number
* song_number
* theme_name
* search_title
* search_lyrics
**songs_topics Table**
This is a bridging table between the *songs* and *topics* tables, which
serves to create a many-to-many relationship between the two tables. It
has the following columns:
* song_id
* topic_id
**topics Table**
The topics table holds a selection of topics that songs can cover. This
is useful when a worship leader wants to select songs with a certain
theme. This table has the following columns:
* id
* name
"""
session, metadata = init_db(url)

View File

@ -1,308 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2010 Raoul Snyman #
# Portions copyright (c) 2008-2010 Tim Bentley, Jonathan Corwin, Michael #
# Gorven, Scott Guerrieri, Meinert Jordan, Andreas Preikschat, Christian #
# Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon Tibble, #
# Carsten Tinggaard, Frode Woldsund #
# --------------------------------------------------------------------------- #
# This program is free software; you can redistribute it and/or modify it #
# under the terms of the GNU General Public License as published by the Free #
# Software Foundation; version 2 of the License. #
# #
# This program is distributed in the hope that it will be useful, but WITHOUT #
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
# more details. #
# #
# You should have received a copy of the GNU General Public License along #
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
import sys
import os
import sqlite
import sqlite3
from optparse import OptionParser
from traceback import format_tb as get_traceback
# Some global options to be used throughout the import process
verbose = False
debug = False
old_cursor = None
new_cursor = None
# SQL create statments
create_statements = [
(u'table "book"', u"""CREATE TABLE book (
id INTEGER NOT NULL,
testament_id INTEGER,
name VARCHAR(30),
abbreviation VARCHAR(5),
PRIMARY KEY (id),
FOREIGN KEY(testament_id) REFERENCES testament (id)
)"""),
(u'table "metadata"', u"""CREATE TABLE metadata (
"key" VARCHAR(255) NOT NULL,
value VARCHAR(255),
PRIMARY KEY ("key")
)"""),
(u'table "testament"', u"""CREATE TABLE testament (
id INTEGER NOT NULL,
name VARCHAR(30),
PRIMARY KEY (id)
)"""),
(u'table "verse"', u"""CREATE TABLE verse (
id INTEGER NOT NULL,
book_id INTEGER,
chapter INTEGER,
verse INTEGER,
text TEXT,
PRIMARY KEY (id),
FOREIGN KEY(book_id) REFERENCES book (id)
)"""),
(u'index "idx_abbrev"',
u"""CREATE INDEX idx_abbrev ON book (abbreviation, id)"""),
(u'index "idx_chapter_verse_book',
u"""CREATE INDEX idx_chapter_verse_book ON verse (chapter, verse, book_id, id)"""),
(u'index "idx_chapter_verse_text"',
u"""CREATE INDEX idx_chapter_verse_text ON verse (text, verse, book_id, id)"""),
(u'index "idx_name"',
u"""CREATE INDEX idx_name ON book (name, id)""")
]
def display_sql(sql, params):
prepared_params = []
for param in params:
if isinstance(param, basestring):
prepared_params.append(u'"%s"' % param)
elif isinstance(param, (int, long)):
prepared_params.append(u'%d' % param)
elif isinstance(param, (float, complex)):
prepared_params.append(u'%f' % param)
else:
prepared_params.append(u'"%s"' % str(param))
for prepared_param in prepared_params:
sql = sql.replace(u'?', prepared_param, 1)
return sql
def create_database():
global new_cursor, create_statements
if debug or verbose:
print 'Creating new database:'
else:
print 'Creating new database...',
for statement_type, sql_create in create_statements:
if debug:
print '... ', sql_create.replace('\n', ' ').replace(' ', ' ')
elif verbose:
print '... creating %s...' % statement_type,
new_cursor.execute(sql_create)
if verbose and not debug:
print 'done.'
if not verbose and not debug:
print 'done.'
def import_bible():
global old_cursor, new_cursor, debug, verbose
if debug or verbose:
print 'Importing metadata:'
else:
print 'Importing metadata...',
if debug:
print '... SELECT "key", "value" FROM metadata'
elif verbose:
print '... fetching metadata from old database...',
old_cursor.execute(u'SELECT "key", "value" FROM metadata')
rows = old_cursor.fetchall()
if not debug and verbose:
print 'done.'
for row in rows:
key = unicode(row[0], u'cp1252')
value = unicode(row[1], u'cp1252')
if key == u'Permission':
key = u'Permissions'
sql_insert = u'INSERT INTO metadata '\
'("key", "value") '\
'VALUES (?, ?)'
sql_params = (key, value)
if debug:
print '...', display_sql(sql_insert, sql_params)
elif verbose:
print '... importing "%s"' % key
new_cursor.execute(sql_insert, sql_params)
if not verbose and not debug:
print 'done.'
if debug or verbose:
print 'Importing testaments:'
else:
print 'Importing testaments...',
if debug:
print '... SELECT id, name FROM testament'
elif verbose:
print '... fetching testaments from old database...',
old_cursor.execute(u'SELECT id, name FROM testament')
rows = old_cursor.fetchall()
if not debug and verbose:
print 'done.'
for row in rows:
id = int(row[0])
name = unicode(row[1], u'cp1252')
sql_insert = u'INSERT INTO testament '\
'(id, name) '\
'VALUES (?, ?)'
sql_params = (id, name)
if debug:
print '...', display_sql(sql_insert, sql_params)
elif verbose:
print '... importing "%s"' % name
new_cursor.execute(sql_insert, sql_params)
if not verbose and not debug:
print 'done.'
if debug or verbose:
print 'Importing books:'
else:
print 'Importing books...',
if debug:
print '... SELECT id, testament_id, name, abbreviation FROM book'
elif verbose:
print '... fetching books from old database...',
old_cursor.execute(u'SELECT id, testament_id, name, abbreviation FROM book')
rows = old_cursor.fetchall()
if not debug and verbose:
print 'done.'
book_map = {}
for row in rows:
testament_id = int(row[1])
name = unicode(row[2], u'cp1252')
abbreviation = unicode(row[3], u'cp1252')
sql_insert = u'INSERT INTO book '\
'(id, testament_id, name, abbreviation) '\
'VALUES (NULL, ?, ?, ?)'
sql_params = (testament_id, name, abbreviation)
if debug:
print '...', display_sql(sql_insert, sql_params)
elif verbose:
print '... importing "%s"' % name
new_cursor.execute(sql_insert, sql_params)
book_map[row[0]] = new_cursor.lastrowid
if debug:
print ' >>> (old) books.id =', row[0], ' (new) books.id =', book_map[row[0]]
if not verbose and not debug:
print 'done.'
if debug or verbose:
print 'Importing verses:'
else:
print 'Importing verses...',
if debug:
print '... SELECT id, book_id, chapter, verse, text || \'\' AS text FROM verse...',
elif verbose:
print '... fetching verses from old database...',
old_cursor.execute(u'SELECT id, book_id, chapter, verse, text || \'\' AS text FROM verse')
rows = old_cursor.fetchall()
if debug or verbose:
print 'done.'
for row in rows:
book_id = int(row[1])
chapter = int(row[2])
verse = int(row[3])
text = unicode(row[4], u'cp1252')
sql_insert = u'INSERT INTO verse '\
'(id, book_id, chapter, verse, text) '\
'VALUES (NULL, ?, ?, ?, ?)'
sql_params = (book_map[book_id], chapter, verse, text)
if debug:
print '...', display_sql(sql_insert, sql_params)
elif verbose:
print '... importing "%s..."' % text[:17]
new_cursor.execute(sql_insert, sql_params)
if not verbose and not debug:
print 'done.'
def main(old_db, new_db):
global old_cursor, new_cursor, debug
old_connection = None
new_connection = None
try:
old_connection = sqlite.connect(old_db)
except:
if debug:
errormsg = '\n' + ''.join(get_traceback(sys.exc_info()[2]))\
+ str(sys.exc_info()[1])
else:
errormsg = sys.exc_info()[1]
print 'There was a problem connecting to the old database:', errormsg
return 1
try:
new_connection = sqlite3.connect(new_db)
except:
if debug:
errormsg = '\n' + ''.join(get_traceback(sys.exc_info()[2]))\
+ str(sys.exc_info()[1])
else:
errormsg = sys.exc_info()[1]
print 'There was a problem creating the new database:', errormsg
return 1
old_cursor = old_connection.cursor()
new_cursor = new_connection.cursor()
try:
create_database()
except:
if debug:
errormsg = '\n' + ''.join(get_traceback(sys.exc_info()[2]))\
+ str(sys.exc_info()[1])
else:
errormsg = sys.exc_info()[1]
print 'There was a problem creating the database:', errormsg
return 1
try:
import_bible()
new_connection.commit()
except:
new_connection.rollback()
if debug:
errormsg = '\n' + ''.join(get_traceback(sys.exc_info()[2]))\
+ str(sys.exc_info()[1])
else:
errormsg = sys.exc_info()[1]
print 'There was a problem importing songs:', errormsg
return 1
print 'Import complete.'
if __name__ == u'__main__':
option_parser = OptionParser(usage='Usage: %prog [options] OLDDATABASE NEWDATABASE')
option_parser.add_option('-o', '--overwrite', dest='overwrite', default=False,
action=u'store_true', help='Overwrite database file if it already exists.')
option_parser.add_option('-v', '--verbose', dest='verbose', default=False,
action=u'store_true', help='Outputs additional progress data.')
option_parser.add_option('-d', '--debug', dest='debug', default=False,
action=u'store_true', help='Outputs raw SQL statements (overrides verbose).')
options, arguments = option_parser.parse_args()
if len(arguments) < 2:
if len(arguments) == 0:
option_parser.error('Please specify an old database and a new database.')
else:
option_parser.error('Please specify a new database.')
old_db = os.path.abspath(arguments[0])
new_db = os.path.abspath(arguments[1])
if not os.path.isfile(old_db):
option_parser.error('Old database file ("%s") is not a file.' % old_db)
if not os.path.exists(old_db):
option_parser.error('Old database file ("%s") does not exist.' % old_db)
if os.path.exists(new_db):
if not options.overwrite:
option_parser.error('New database file ("%s") exists. If you want to overwrite it, specify the --overwrite option.' % new_db)
else:
if not os.path.isfile(new_db):
option_parser.error('New database file ("%s") is not a file.' % new_db)
os.unlink(new_db)
verbose = options.verbose
debug = options.debug
main(old_db, new_db)

View File

@ -1,323 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2010 Raoul Snyman #
# Portions copyright (c) 2008-2010 Tim Bentley, Jonathan Corwin, Michael #
# Gorven, Scott Guerrieri, Meinert Jordan, Andreas Preikschat, Christian #
# Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon Tibble, #
# Carsten Tinggaard, Frode Woldsund #
# --------------------------------------------------------------------------- #
# This program is free software; you can redistribute it and/or modify it #
# under the terms of the GNU General Public License as published by the Free #
# Software Foundation; version 2 of the License. #
# #
# This program is distributed in the hope that it will be useful, but WITHOUT #
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
# more details. #
# #
# You should have received a copy of the GNU General Public License along #
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
import sys
import os
import sqlite
import sqlite3
import re
from optparse import OptionParser
from traceback import format_tb as get_traceback
# Some global options to be used throughout the import process
dirty_chars = re.compile(r'\W ', re.UNICODE)
verbose = False
debug = False
old_cursor = None
new_cursor = None
# SQL create statments
create_statements = [
(u'table "authors"', u"""CREATE TABLE authors (
id INTEGER NOT NULL,
first_name VARCHAR(128),
last_name VARCHAR(128),
display_name VARCHAR(255) NOT NULL,
PRIMARY KEY (id)
)"""),
(u'table "song_books"', u"""CREATE TABLE song_books (
id INTEGER NOT NULL,
name VARCHAR(128) NOT NULL,
publisher VARCHAR(128),
PRIMARY KEY (id)
)"""),
(u'table "songs"', u"""CREATE TABLE songs (
id INTEGER NOT NULL,
song_book_id INTEGER,
title VARCHAR(255) NOT NULL,
alternate_title VARCHAR(255),
lyrics TEXT NOT NULL,
verse_order VARCHAR(128),
copyright VARCHAR(255),
comments TEXT,
ccli_number VARCHAR(64),
song_number VARCHAR(64),
theme_name VARCHAR(128),
search_title VARCHAR(255) NOT NULL,
search_lyrics TEXT NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY(song_book_id) REFERENCES song_books (id)
)"""),
(u'table "topics"', u"""CREATE TABLE topics (
id INTEGER NOT NULL,
name VARCHAR(128) NOT NULL,
PRIMARY KEY (id)
)"""),
(u'index "ix_songs_search_lyrics"',
u"""CREATE INDEX ix_songs_search_lyrics ON songs (search_lyrics)"""),
(u'index "ix_songs_search_title',
u"""CREATE INDEX ix_songs_search_title ON songs (search_title)"""),
(u'table "authors_songs"', u"""CREATE TABLE authors_songs (
author_id INTEGER NOT NULL,
song_id INTEGER NOT NULL,
PRIMARY KEY (author_id, song_id),
FOREIGN KEY(author_id) REFERENCES authors (id),
FOREIGN KEY(song_id) REFERENCES songs (id)
)"""),
(u'table "songs_topics"', u"""CREATE TABLE songs_topics (
song_id INTEGER NOT NULL,
topic_id INTEGER NOT NULL,
PRIMARY KEY (song_id, topic_id),
FOREIGN KEY(song_id) REFERENCES songs (id),
FOREIGN KEY(topic_id) REFERENCES topics (id)
)""")
]
def prepare_string(dirty):
return dirty_chars.sub(u'', dirty.replace(u'\r\n', u' ').replace(u'\n', u' '))
def display_sql(sql, params):
prepared_params = []
for param in params:
if isinstance(param, basestring):
prepared_params.append(u'"%s"' % param)
elif isinstance(param, (int, long)):
prepared_params.append(u'%d' % param)
elif isinstance(param, (float, complex)):
prepared_params.append(u'%f' % param)
else:
prepared_params.append(u'"%s"' % str(param))
for prepared_param in prepared_params:
sql = sql.replace(u'?', prepared_param, 1)
return sql
def create_database():
global new_cursor, create_statements
if debug or verbose:
print 'Creating new database:'
else:
print 'Creating new database...',
for statement_type, sql_create in create_statements:
if debug:
print '... ', sql_create.replace('\n', ' ').replace(' ', ' ')
elif verbose:
print '... creating %s...' % statement_type,
new_cursor.execute(sql_create)
if verbose and not debug:
print 'done.'
if not verbose and not debug:
print 'done.'
def import_songs():
global old_cursor, new_cursor, debug, verbose
if debug or verbose:
print 'Importing authors:'
else:
print 'Importing authors...',
if debug:
print '... SELECT authorid AS id, authorname AS displayname FROM authors'
elif verbose:
print '... fetching authors from old database...',
old_cursor.execute(u'SELECT authorid AS id, authorname AS displayname FROM authors')
rows = old_cursor.fetchall()
if not debug and verbose:
print 'done.'
author_map = {}
for row in rows:
display_name = unicode(row[1], u'cp1252')
names = display_name.split(u' ')
first_name = names[0]
last_name = u' '.join(names[1:])
if last_name is None:
last_name = u''
sql_insert = u'INSERT INTO authors '\
'(id, first_name, last_name, display_name) '\
'VALUES (NULL, ?, ?, ?)'
sql_params = (first_name, last_name, display_name)
if debug:
print '...', display_sql(sql_insert, sql_params)
elif verbose:
print '... importing "%s"' % display_name
new_cursor.execute(sql_insert, sql_params)
author_map[row[0]] = new_cursor.lastrowid
if debug:
print ' >>> authors.authorid =', row[0], 'authors.id =', author_map[row[0]]
if not verbose and not debug:
print 'done.'
if debug or verbose:
print 'Importing songs:'
else:
print 'Importing songs...',
if debug:
print '... SELECT songid AS id, songtitle AS title, lyrics || \'\' AS lyrics, copyrightinfo AS copyright FROM songs...',
elif verbose:
print '... fetching songs from old database...',
old_cursor.execute(u'SELECT songid AS id, songtitle AS title, lyrics || \'\' AS lyrics, copyrightinfo AS copyright FROM songs')
rows = old_cursor.fetchall()
if debug or verbose:
print 'done.'
song_map = {}
xml_lyrics_template = u'<?xml version="1.0" encoding="utf-8"?><song version="1.0"><lyrics language="en">%s</lyrics></song>'
xml_verse_template = u'<verse label="%d" type="Verse"><![CDATA[%s]]></verse>'
for row in rows:
clean_title = unicode(row[1], u'cp1252')
clean_lyrics = unicode(row[2], u'cp1252').replace(u'\r\n', u'\n')
clean_copyright = unicode(row[3], u'cp1252')
verse_order = u''
text_lyrics = clean_lyrics.split(u'\n\n')
xml_verse = u''
verses = []
for line, verse in enumerate(text_lyrics):
if not verse:
continue
xml_verse += (xml_verse_template % (line + 1, verse))
verses.append(u'V%d' % (line + 1))
verse_order = u' '.join(verses)
xml_lyrics = xml_lyrics_template % xml_verse
search_title = prepare_string(clean_title)
search_lyrics = prepare_string(clean_lyrics)
sql_insert = u'INSERT INTO songs '\
'(id, song_book_id, title, lyrics, verse_order, copyright, search_title, search_lyrics) '\
'VALUES (NULL, 0, ?, ?, ?, ?, ?, ?)'
sql_params = (clean_title, xml_lyrics, verse_order, clean_copyright, search_title, search_lyrics)
if debug:
print '...', display_sql(sql_insert, (sql_params[0], u'%s...' % clean_lyrics[:7], sql_params[2], sql_params[3], sql_params[4], u'%s...' % search_lyrics[:7]))
elif verbose:
print '... importing "%s"' % clean_title
new_cursor.execute(sql_insert, sql_params)
song_map[row[0]] = new_cursor.lastrowid
if debug:
print ' >>> songs.songid =', row[0], 'songs.id =', song_map[row[0]]
if not verbose and not debug:
print 'done.'
if debug or verbose:
print 'Importing song-to-author mapping:'
else:
print 'Importing song-to-author mapping...',
if debug:
print '... SELECT authorid AS author_id, songid AS song_id FROM songauthors'
elif verbose:
print '... fetching song-to-author mapping from old database...',
old_cursor.execute(u'SELECT authorid AS author_id, songid AS song_id FROM songauthors')
rows = old_cursor.fetchall()
if not debug and verbose:
print 'done.'
for row in rows:
sql_insert = u'INSERT INTO authors_songs '\
'(author_id, song_id) '\
'VALUES (?, ?)'
sql_params = (author_map[row[0]], song_map[row[1]])
if debug:
print '... ', display_sql(sql_insert, sql_params)
elif verbose:
print '... Author %d (was %d) => Song %d (was %d)'\
% (int(row[0]), author_map[row[0]],
int(row[1]), song_map[row[1]])
new_cursor.execute(sql_insert, sql_params)
if not verbose and not debug:
print 'done.'
def main(old_db, new_db):
global old_cursor, new_cursor, debug
old_connection = None
new_connection = None
try:
old_connection = sqlite.connect(old_db)
except:
if debug:
errormsg = '\n' + ''.join(get_traceback(sys.exc_info()[2]))\
+ str(sys.exc_info()[1])
else:
errormsg = sys.exc_info()[1]
print 'There was a problem connecting to the old database:', errormsg
return 1
try:
new_connection = sqlite3.connect(new_db)
except:
if debug:
errormsg = '\n' + ''.join(get_traceback(sys.exc_info()[2]))\
+ str(sys.exc_info()[1])
else:
errormsg = sys.exc_info()[1]
print 'There was a problem creating the new database:', errormsg
return 1
old_cursor = old_connection.cursor()
new_cursor = new_connection.cursor()
try:
create_database()
except:
if debug:
errormsg = '\n' + ''.join(get_traceback(sys.exc_info()[2]))\
+ str(sys.exc_info()[1])
else:
errormsg = sys.exc_info()[1]
print 'There was a problem creating the database:', errormsg
return 1
try:
import_songs()
new_connection.commit()
except:
new_connection.rollback()
if debug:
errormsg = '\n' + ''.join(get_traceback(sys.exc_info()[2]))\
+ str(sys.exc_info()[1])
else:
errormsg = sys.exc_info()[1]
print 'There was a problem importing songs:', errormsg
return 1
print 'Import complete.'
if __name__ == u'__main__':
option_parser = OptionParser(usage='Usage: %prog [options] OLDDATABASE NEWDATABASE')
option_parser.add_option('-o', '--overwrite', dest='overwrite', default=False,
action=u'store_true', help='Overwrite database file if it already exists.')
option_parser.add_option('-v', '--verbose', dest='verbose', default=False,
action=u'store_true', help='Outputs additional progress data.')
option_parser.add_option('-d', '--debug', dest='debug', default=False,
action=u'store_true', help='Outputs raw SQL statements (overrides verbose).')
options, arguments = option_parser.parse_args()
if len(arguments) < 2:
if len(arguments) == 0:
option_parser.error('Please specify an old database and a new database.')
else:
option_parser.error('Please specify a new database.')
old_db = os.path.abspath(arguments[0])
new_db = os.path.abspath(arguments[1])
if not os.path.isfile(old_db):
option_parser.error('Old database file ("%s") is not a file.' % old_db)
if not os.path.exists(old_db):
option_parser.error('Old database file ("%s") does not exist.' % old_db)
if os.path.exists(new_db):
if not options.overwrite:
option_parser.error('New database file ("%s") exists. If you want to overwrite it, specify the --overwrite option.' % new_db)
else:
if not os.path.isfile(new_db):
option_parser.error('New database file ("%s") is not a file.' % new_db)
os.unlink(new_db)
verbose = options.verbose
debug = options.debug
main(old_db, new_db)