merged from trunk

This commit is contained in:
andreas 2010-07-02 18:57:56 +02:00
commit 6ee69b81e4
104 changed files with 1637 additions and 2167 deletions

View File

@ -1 +1 @@
1.9.1-bzr821
1.9.2

View File

@ -22,7 +22,6 @@
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
"""
The :mod:`lib` module contains most of the components and libraries that make
OpenLP work.
@ -47,6 +46,10 @@ def translate(context, text, comment=None):
``text``
The text to put into the translation tables for translation.
``comment``
An identifying string for when the same text is used in different roles
within the same context.
"""
return QtCore.QCoreApplication.translate(context, text, comment)
@ -115,6 +118,18 @@ def build_icon(icon):
def context_menu_action(base, icon, text, slot):
"""
Utility method to help build context menus for plugins
``base``
The parent menu to add this menu item to
``icon``
An icon for this action
``text``
The text to display for this action
``slot``
The code to run when this action is triggered
"""
action = QtGui.QAction(text, base)
if icon:
@ -125,6 +140,15 @@ def context_menu_action(base, icon, text, slot):
def context_menu(base, icon, text):
"""
Utility method to help build context menus for plugins
``base``
The parent object to add this menu to
``icon``
An icon for this menu
``text``
The text to display for this menu
"""
action = QtGui.QMenu(text, base)
action.setIcon(build_icon(icon))
@ -133,6 +157,9 @@ def context_menu(base, icon, text):
def context_menu_separator(base):
"""
Add a separator to a context menu
``base``
The menu object to add the separator to
"""
action = QtGui.QAction(u'', base)
action.setSeparator(True)
@ -200,5 +227,4 @@ from themexmlhandler import ThemeXML
from renderer import Renderer
from rendermanager import RenderManager
from mediamanageritem import MediaManagerItem
from basemodel import BaseModel
from baselistwithdnd import BaseListWithDnD

View File

@ -1,40 +0,0 @@
# -*- 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, Christian Richter, Maikel Stuivenberg, Martin #
# Thompson, Jon Tibble, Carsten Tinggaard #
# --------------------------------------------------------------------------- #
# 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 #
###############################################################################
class BaseModel(object):
"""
BaseModel provides a base object with a set of generic functions
"""
@classmethod
def populate(cls, **kwargs):
"""
Creates an instance of a class and populates it, returning the instance
"""
me = cls()
for key in kwargs:
me.__setattr__(key, kwargs[key])
return me

253
openlp/core/lib/db.py Normal file
View File

@ -0,0 +1,253 @@
# -*- 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, Christian Richter, Maikel Stuivenberg, Martin #
# Thompson, Jon Tibble, Carsten Tinggaard #
# --------------------------------------------------------------------------- #
# This program is free software; you can redistribute it and/or modify it #
# under the terms of the GNU General Public License as published by the Free #
# Software Foundation; version 2 of the License. #
# #
# This program is distributed in the hope that it will be useful, but WITHOUT #
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
# more details. #
# #
# You should have received a copy of the GNU General Public License along #
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
"""
The :mod:`db` module provides the core database functionality for OpenLP
"""
import logging
import os
from PyQt4 import QtCore
from sqlalchemy import create_engine, MetaData
from sqlalchemy.exceptions import InvalidRequestError
from sqlalchemy.orm import scoped_session, sessionmaker
from openlp.core.utils import AppLocation
log = logging.getLogger(__name__)
def init_db(url, auto_flush=True, auto_commit=False):
"""
Initialise and return the session and metadata for a database
``url``
The database to initialise connection with
``auto_flush``
Sets the flushing behaviour of the session
``auto_commit``
Sets the commit behaviour of the session
"""
engine = create_engine(url)
metadata = MetaData(bind=engine)
session = scoped_session(sessionmaker(autoflush=auto_flush,
autocommit=auto_commit, bind=engine))
return session, metadata
def delete_database(plugin_name, db_file_name=None):
"""
Remove a database file from the system.
``plugin_name``
The name of the plugin to remove the database for
``db_file_name``
The database file name. Defaults to None resulting in the
plugin_name being used.
"""
db_file_path = None
if db_file_name:
db_file_path = os.path.join(
AppLocation.get_section_data_path(plugin_name), db_file_name)
else:
db_file_path = os.path.join(
AppLocation.get_section_data_path(plugin_name), plugin_name)
try:
os.remove(db_file_path)
return True
except OSError:
return False
class BaseModel(object):
"""
BaseModel provides a base object with a set of generic functions
"""
@classmethod
def populate(cls, **kwargs):
"""
Creates an instance of a class and populates it, returning the instance
"""
me = cls()
for key in kwargs:
me.__setattr__(key, kwargs[key])
return me
class Manager(object):
"""
Provide generic object persistence management
"""
def __init__(self, plugin_name, init_schema, db_file_name=None):
"""
Runs the initialisation process that includes creating the connection
to the database and the tables if they don't exist.
``plugin_name``
The name to setup paths and settings section names
``init_schema``
The init_schema function for this database
``db_file_name``
The file name to use for this database. Defaults to None resulting
in the plugin_name being used.
"""
settings = QtCore.QSettings()
settings.beginGroup(plugin_name)
self.db_url = u''
db_type = unicode(
settings.value(u'db type', QtCore.QVariant(u'sqlite')).toString())
if db_type == u'sqlite':
if db_file_name:
self.db_url = u'sqlite:///%s/%s' % (
AppLocation.get_section_data_path(plugin_name),
db_file_name)
else:
self.db_url = u'sqlite:///%s/%s.sqlite' % (
AppLocation.get_section_data_path(plugin_name), plugin_name)
else:
self.db_url = u'%s://%s:%s@%s/%s' % (db_type,
unicode(settings.value(u'db username').toString()),
unicode(settings.value(u'db password').toString()),
unicode(settings.value(u'db hostname').toString()),
unicode(settings.value(u'db database').toString()))
settings.endGroup()
self.session = init_schema(self.db_url)
def save_object(self, object_instance):
"""
Save an object to the database
``object_instance``
The object to save
"""
try:
self.session.add(object_instance)
self.session.commit()
return True
except InvalidRequestError:
self.session.rollback()
log.exception(u'Object save failed')
return False
def get_object(self, object_class, key=None):
"""
Return the details of an object
``object_class``
The type of object to return
``key``
The unique reference or primary key for the instance to return
"""
if not key:
return object_class()
else:
return self.session.query(object_class).get(key)
def get_object_filtered(self, object_class, filter_clause):
"""
Returns an object matching specified criteria
``object_class``
The type of object to return
``filter_clause``
The criteria to select the object by
"""
return self.session.query(object_class).filter(filter_clause).first()
def get_all_objects(self, object_class, order_by_ref=None):
"""
Returns all the objects from the database
``object_class``
The type of objects to return
``order_by_ref``
Any parameters to order the returned objects by. Defaults to None.
"""
query = self.session.query(object_class)
if order_by_ref:
return query.order_by(order_by_ref).all()
return query.all()
def get_all_objects_filtered(self, object_class, filter_clause,
order_by_ref=None):
"""
Returns a selection of objects from the database
``object_class``
The type of objects to return
``filter_clause``
The filter governing selection of objects to return
``order_by_ref``
Any parameters to order the returned objects by. Defaults to None.
"""
query = self.session.query(object_class).filter(filter_clause)
if order_by_ref:
return query.order_by(order_by_ref).all()
return query.all()
def delete_object(self, object_class, key):
"""
Delete an object from the database
``object_class``
The type of object to delete
``key``
The unique reference or primary key for the instance to be deleted
"""
if key != 0:
object_instance = self.get_object(object_class, key)
try:
self.session.delete(object_instance)
self.session.commit()
return True
except InvalidRequestError:
self.session.rollback()
log.exception(u'Failed to delete object')
return False
else:
return True
def delete_all_objects(self, object_class):
"""
Delete all object records
``object_class``
The type of object to delete
"""
try:
self.session.query(object_class).delete(synchronize_session=False)
self.session.commit()
return True
except InvalidRequestError:
self.session.rollback()
log.exception(u'Failed to delete all %s records',
object_class.__name__)
return False

View File

@ -525,8 +525,7 @@ class MediaManagerItem(QtGui.QWidget):
if self.ServiceItemIconName:
service_item.add_icon(self.ServiceItemIconName)
else:
service_item.add_icon(
u':/media/media_' + self.PluginNameShort.lower() + u'.png')
service_item.add_icon(self.parent.icon)
if self.generateSlideData(service_item, item):
return service_item
else:

View File

@ -242,19 +242,22 @@ class Plugin(QtCore.QObject):
"""
if self.media_item:
self.media_item.initialise()
self.insert_toolbox_item()
def finalise(self):
"""
Called by the plugin Manager to cleanup things.
"""
pass
self.remove_toolbox_item()
def remove_toolbox_item(self):
"""
Called by the plugin to remove toolbar
"""
self.mediadock.remove_dock(self.name)
self.settings_form.removeTab(self.name)
if self.media_item:
self.mediadock.remove_dock(self.name)
if self.settings_tab:
self.settings_form.removeTab(self.name)
def insert_toolbox_item(self):
"""

View File

@ -22,7 +22,10 @@
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
"""
The :mod:`renderer` module enables OpenLP to take the input from plugins and
format it for the output display.
"""
import logging
from PyQt4 import QtGui, QtCore

View File

@ -35,6 +35,7 @@ import uuid
from PyQt4 import QtGui
from openlp.core.lib import build_icon, resize_image
from openlp.core.utils import AppLocation
log = logging.getLogger(__name__)
@ -92,6 +93,7 @@ class ServiceItem(object):
self.is_valid = True
self.cache = {}
self.icon = None
self.serviceItemPath = AppLocation.get_section_data_path(u'serviceItems')
def add_capability(self, capability):
"""
@ -153,9 +155,12 @@ class ServiceItem(object):
del self.cache[len(self._display_frames)]
log.log(15, u'Formatting took %4s' % (time.time() - before))
elif self.service_item_type == ServiceItemType.Image:
for slide in self._raw_frames:
for count, slide in enumerate(self._raw_frames):
slide[u'image'] = resize_image(slide[u'image'],
self.render_manager.width, self.render_manager.height)
path = os.path.join(self.serviceItemPath, self._uuid + unicode(count) + u'.png')
slide[u'image'].save(path)
slide[u'display'] = path
elif self.service_item_type == ServiceItemType.Command:
pass
else:
@ -371,7 +376,8 @@ class ServiceItem(object):
if self.service_item_type == ServiceItemType.Text:
return self.render_individual(row)
else:
return {u'main':self._raw_frames[row][u'image'], u'trans':None}
return {u'main':self._raw_frames[row][u'image'],
u'trans':None, u'display':self._raw_frames[row][u'display']}
def get_frame_title(self, row=0):
"""

View File

@ -168,7 +168,7 @@ class Theme(object):
theme_strings.append(u'_%s_' % (getattr(self, key)))
return u''.join(theme_strings)
def _set_from_XML(self, xml):
def _set_from_xml(self, xml):
"""
Set theme class attributes with data from XML

View File

@ -178,13 +178,11 @@ class Ui_AmendThemeDialog(object):
self.MainFontLayout.setWidget(2, QtGui.QFormLayout.LabelRole,
self.FontMainSize)
self.FontMainSizeSpinBox = QtGui.QSpinBox(self.FontMainGroupBox)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Minimum,
defaultSizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Minimum,
QtGui.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(
defaultSizePolicy.setHeightForWidth(
self.FontMainSizeSpinBox.sizePolicy().hasHeightForWidth())
self.FontMainSizeSpinBox.setSizePolicy(sizePolicy)
self.FontMainSizeSpinBox.setSizePolicy(defaultSizePolicy)
self.FontMainSizeSpinBox.setMinimumSize(QtCore.QSize(70, 0))
self.FontMainSizeSpinBox.setProperty(u'value', QtCore.QVariant(16))
self.FontMainSizeSpinBox.setMaximum(999)
@ -230,8 +228,7 @@ class Ui_AmendThemeDialog(object):
self.FontMainLineSpacingSpinBox)
self.FontMainLinesPageLabel = QtGui.QLabel(self.FontMainGroupBox)
self.FontMainLinesPageLabel.setObjectName(u'FontMainLinesPageLabel')
self.MainFontLayout.setWidget(6, QtGui.QFormLayout.LabelRole,
self.FontMainLinesPageLabel)
self.MainFontLayout.addRow(self.FontMainLinesPageLabel)
spacerItem1 = QtGui.QSpacerItem(20, 40, QtGui.QSizePolicy.Minimum,
QtGui.QSizePolicy.Expanding)
self.MainLeftLayout.addItem(spacerItem1)
@ -275,13 +272,9 @@ class Ui_AmendThemeDialog(object):
self.MainLocationLayout.setWidget(4, QtGui.QFormLayout.LabelRole,
self.FontMainHeightLabel)
self.FontMainXSpinBox = QtGui.QSpinBox(self.MainLocationGroupBox)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Minimum,
QtGui.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(
defaultSizePolicy.setHeightForWidth(
self.FontMainXSpinBox.sizePolicy().hasHeightForWidth())
self.FontMainXSpinBox.setSizePolicy(sizePolicy)
self.FontMainXSpinBox.setSizePolicy(defaultSizePolicy)
self.FontMainXSpinBox.setMinimumSize(QtCore.QSize(78, 0))
self.FontMainXSpinBox.setProperty(u'value', QtCore.QVariant(0))
self.FontMainXSpinBox.setMaximum(9999)
@ -289,39 +282,27 @@ class Ui_AmendThemeDialog(object):
self.MainLocationLayout.setWidget(1, QtGui.QFormLayout.FieldRole,
self.FontMainXSpinBox)
self.FontMainYSpinBox = QtGui.QSpinBox(self.MainLocationGroupBox)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Minimum,
QtGui.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(
defaultSizePolicy.setHeightForWidth(
self.FontMainYSpinBox.sizePolicy().hasHeightForWidth())
self.FontMainYSpinBox.setSizePolicy(sizePolicy)
self.FontMainYSpinBox.setSizePolicy(defaultSizePolicy)
self.FontMainYSpinBox.setMinimumSize(QtCore.QSize(78, 0))
self.FontMainYSpinBox.setMaximum(9999)
self.FontMainYSpinBox.setObjectName(u'FontMainYSpinBox')
self.MainLocationLayout.setWidget(2, QtGui.QFormLayout.FieldRole,
self.FontMainYSpinBox)
self.FontMainWidthSpinBox = QtGui.QSpinBox(self.MainLocationGroupBox)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Minimum,
QtGui.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(
defaultSizePolicy.setHeightForWidth(
self.FontMainWidthSpinBox.sizePolicy().hasHeightForWidth())
self.FontMainWidthSpinBox.setSizePolicy(sizePolicy)
self.FontMainWidthSpinBox.setSizePolicy(defaultSizePolicy)
self.FontMainWidthSpinBox.setMinimumSize(QtCore.QSize(78, 0))
self.FontMainWidthSpinBox.setMaximum(9999)
self.FontMainWidthSpinBox.setObjectName(u'FontMainWidthSpinBox')
self.MainLocationLayout.setWidget(3, QtGui.QFormLayout.FieldRole,
self.FontMainWidthSpinBox)
self.FontMainHeightSpinBox = QtGui.QSpinBox(self.MainLocationGroupBox)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Minimum,
QtGui.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(
defaultSizePolicy.setHeightForWidth(
self.FontMainHeightSpinBox.sizePolicy().hasHeightForWidth())
self.FontMainHeightSpinBox.setSizePolicy(sizePolicy)
self.FontMainHeightSpinBox.setSizePolicy(defaultSizePolicy)
self.FontMainHeightSpinBox.setMinimumSize(QtCore.QSize(78, 0))
self.FontMainHeightSpinBox.setMaximum(9999)
self.FontMainHeightSpinBox.setObjectName(u'FontMainHeightSpinBox')
@ -378,13 +359,9 @@ class Ui_AmendThemeDialog(object):
self.FooterFontLayout.setWidget(2, QtGui.QFormLayout.LabelRole,
self.FontFooterSizeLabel)
self.FontFooterSizeSpinBox = QtGui.QSpinBox(self.FooterFontGroupBox)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Minimum,
QtGui.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(
defaultSizePolicy.setHeightForWidth(
self.FontFooterSizeSpinBox.sizePolicy().hasHeightForWidth())
self.FontFooterSizeSpinBox.setSizePolicy(sizePolicy)
self.FontFooterSizeSpinBox.setSizePolicy(defaultSizePolicy)
self.FontFooterSizeSpinBox.setMinimumSize(QtCore.QSize(70, 0))
self.FontFooterSizeSpinBox.setProperty(u'value', QtCore.QVariant(10))
self.FontFooterSizeSpinBox.setMaximum(999)
@ -453,13 +430,9 @@ class Ui_AmendThemeDialog(object):
self.LocationFooterLayout.setWidget(4, QtGui.QFormLayout.LabelRole,
self.FontFooterHeightLabel)
self.FontFooterXSpinBox = QtGui.QSpinBox(self.LocationFooterGroupBox)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Minimum,
QtGui.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(
defaultSizePolicy.setHeightForWidth(
self.FontFooterXSpinBox.sizePolicy().hasHeightForWidth())
self.FontFooterXSpinBox.setSizePolicy(sizePolicy)
self.FontFooterXSpinBox.setSizePolicy(defaultSizePolicy)
self.FontFooterXSpinBox.setMinimumSize(QtCore.QSize(78, 0))
self.FontFooterXSpinBox.setProperty(u'value', QtCore.QVariant(0))
self.FontFooterXSpinBox.setMaximum(9999)
@ -467,13 +440,9 @@ class Ui_AmendThemeDialog(object):
self.LocationFooterLayout.setWidget(1, QtGui.QFormLayout.FieldRole,
self.FontFooterXSpinBox)
self.FontFooterYSpinBox = QtGui.QSpinBox(self.LocationFooterGroupBox)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Minimum,
QtGui.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(
self.FontFooterYSpinBox.sizePolicy().hasHeightForWidth())
self.FontFooterYSpinBox.setSizePolicy(sizePolicy)
defaultSizePolicy.setHeightForWidth(
self.FontFooterXSpinBox.sizePolicy().hasHeightForWidth())
self.FontFooterYSpinBox.setSizePolicy(defaultSizePolicy)
self.FontFooterYSpinBox.setMinimumSize(QtCore.QSize(78, 0))
self.FontFooterYSpinBox.setProperty(u'value', QtCore.QVariant(0))
self.FontFooterYSpinBox.setMaximum(9999)
@ -901,4 +870,3 @@ class Ui_AmendThemeDialog(object):
self.ThemeTabWidget.indexOf(self.OtherOptionsTab),
translate('AmendThemeForm', '&Other Options'))
self.PreviewGroupBox.setTitle(translate('AmendThemeForm', 'Preview'))

View File

@ -242,4 +242,3 @@ class DisplayTab(SettingsTab):
if self.amend_display_start != self.amend_display:
self.amend_display_start = self.amend_display
Receiver.send_message(u'config_screen_changed')

View File

@ -32,13 +32,16 @@ class GeneralTab(SettingsTab):
GeneralTab is the general settings tab in the settings dialog.
"""
def __init__(self, screens):
"""
Initialise the general settings tab
"""
self.screens = screens
self.MonitorNumber = 0
SettingsTab.__init__(self, u'General')
def preLoad(self):
"""
Set up the display screen and set correct screen
values.
Set up the display screen and set correct screen values.
If not set before default to last screen.
"""
settings = QtCore.QSettings()
@ -47,12 +50,14 @@ class GeneralTab(SettingsTab):
QtCore.QVariant(self.screens.display_count - 1)).toInt()[0]
self.screens.set_current_display(self.MonitorNumber)
self.screens.monitor_number = self.MonitorNumber
self.DisplayOnMonitor = settings.value(
self.screens.display = settings.value(
u'display on monitor', QtCore.QVariant(True)).toBool()
self.screens.display = self.DisplayOnMonitor
settings.endGroup()
def setupUi(self):
"""
Create the user interface for the general settings tab
"""
self.setObjectName(u'GeneralTab')
self.tabTitleVisible = translate('GeneralTab', 'General')
self.GeneralLayout = QtGui.QHBoxLayout(self)
@ -152,31 +157,11 @@ class GeneralTab(SettingsTab):
QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding)
self.GeneralRightLayout.addItem(self.GeneralRightSpacer)
self.GeneralLayout.addWidget(self.GeneralRightWidget)
QtCore.QObject.connect(self.MonitorComboBox,
QtCore.SIGNAL(u'activated(int)'), self.onMonitorComboBoxChanged)
QtCore.QObject.connect(self.DisplayOnMonitorCheck,
QtCore.SIGNAL(u'stateChanged(int)'),
self.onDisplayOnMonitorCheckChanged)
QtCore.QObject.connect(self.WarningCheckBox,
QtCore.SIGNAL(u'stateChanged(int)'), self.onWarningCheckBoxChanged)
QtCore.QObject.connect(self.AutoOpenCheckBox,
QtCore.SIGNAL(u'stateChanged(int)'), self.onAutoOpenCheckBoxChanged)
QtCore.QObject.connect(self.ShowSplashCheckBox,
QtCore.SIGNAL(u'stateChanged(int)'),
self.onShowSplashCheckBoxChanged)
QtCore.QObject.connect(self.SaveCheckServiceCheckBox,
QtCore.SIGNAL(u'stateChanged(int)'),
self.onSaveCheckServiceCheckBox)
QtCore.QObject.connect(self.AutoPreviewCheckBox,
QtCore.SIGNAL(u'stateChanged(int)'), self.onAutoPreviewCheckBox)
QtCore.QObject.connect(self.NumberEdit,
QtCore.SIGNAL(u'editingFinished()'), self.onNumberEditLostFocus)
QtCore.QObject.connect(self.UsernameEdit,
QtCore.SIGNAL(u'editingFinished()'), self.onUsernameEditLostFocus)
QtCore.QObject.connect(self.PasswordEdit,
QtCore.SIGNAL(u'editingFinished()'), self.onPasswordEditLostFocus)
def retranslateUi(self):
"""
Translate the general settings tab to the currently selected language
"""
self.MonitorGroupBox.setTitle(translate('GeneralTab', 'Monitors'))
self.MonitorLabel.setText(
translate('GeneralTab', 'Select monitor for output display:'))
@ -204,37 +189,10 @@ class GeneralTab(SettingsTab):
self.PasswordLabel.setText(
translate('GeneralTab', 'SongSelect Password:'))
def onMonitorComboBoxChanged(self):
self.MonitorNumber = self.MonitorComboBox.currentIndex()
def onDisplayOnMonitorCheckChanged(self, value):
self.DisplayOnMonitor = (value == QtCore.Qt.Checked)
def onAutoOpenCheckBoxChanged(self, value):
self.AutoOpen = (value == QtCore.Qt.Checked)
def onShowSplashCheckBoxChanged(self, value):
self.ShowSplash = (value == QtCore.Qt.Checked)
def onWarningCheckBoxChanged(self, value):
self.Warning = (value == QtCore.Qt.Checked)
def onSaveCheckServiceCheckBox(self, value):
self.PromptSaveService = (value == QtCore.Qt.Checked)
def onAutoPreviewCheckBox(self, value):
self.AutoPreview = (value == QtCore.Qt.Checked)
def onNumberEditLostFocus(self):
self.CCLINumber = self.NumberEdit.displayText()
def onUsernameEditLostFocus(self):
self.Username = self.UsernameEdit.displayText()
def onPasswordEditLostFocus(self):
self.Password = self.PasswordEdit.displayText()
def load(self):
"""
Load the settings to populate the form
"""
settings = QtCore.QSettings()
settings.beginGroup(self.settingsSection)
for screen in self.screens.screen_list:
@ -244,55 +202,54 @@ class GeneralTab(SettingsTab):
screen_name = u'%s (%s)' % (screen_name,
translate('GeneralTab', 'primary'))
self.MonitorComboBox.addItem(screen_name)
# Get the configs
self.Warning = settings.value(
u'blank warning', QtCore.QVariant(False)).toBool()
self.AutoOpen = settings.value(
u'auto open', QtCore.QVariant(False)).toBool()
self.ShowSplash = settings.value(
u'show splash', QtCore.QVariant(True)).toBool()
self.PromptSaveService = settings.value(
u'save prompt', QtCore.QVariant(False)).toBool()
self.AutoPreview = settings.value(
u'auto preview', QtCore.QVariant(False)).toBool()
self.CCLINumber = unicode(settings.value(
u'ccli number', QtCore.QVariant(u'')).toString())
self.Username = unicode(settings.value(
u'songselect username', QtCore.QVariant(u'')).toString())
self.Password = unicode(settings.value(
u'songselect password', QtCore.QVariant(u'')).toString())
settings.endGroup()
self.SaveCheckServiceCheckBox.setChecked(self.PromptSaveService)
# Set a few things up
self.NumberEdit.setText(unicode(settings.value(
u'ccli number', QtCore.QVariant(u'')).toString()))
self.UsernameEdit.setText(unicode(settings.value(
u'songselect username', QtCore.QVariant(u'')).toString()))
self.PasswordEdit.setText(unicode(settings.value(
u'songselect password', QtCore.QVariant(u'')).toString()))
self.SaveCheckServiceCheckBox.setChecked(settings.value(u'save prompt',
QtCore.QVariant(False)).toBool())
self.MonitorComboBox.setCurrentIndex(self.MonitorNumber)
self.DisplayOnMonitorCheck.setChecked(self.DisplayOnMonitor)
self.WarningCheckBox.setChecked(self.Warning)
self.AutoOpenCheckBox.setChecked(self.AutoOpen)
self.ShowSplashCheckBox.setChecked(self.ShowSplash)
self.AutoPreviewCheckBox.setChecked(self.AutoPreview)
self.NumberEdit.setText(self.CCLINumber)
self.UsernameEdit.setText(self.Username)
self.PasswordEdit.setText(self.Password)
self.DisplayOnMonitorCheck.setChecked(self.screens.display)
self.WarningCheckBox.setChecked(settings.value(u'blank warning',
QtCore.QVariant(False)).toBool())
self.AutoOpenCheckBox.setChecked(settings.value(u'auto open',
QtCore.QVariant(False)).toBool())
self.ShowSplashCheckBox.setChecked(settings.value(u'show splash',
QtCore.QVariant(True)).toBool())
self.AutoPreviewCheckBox.setChecked(settings.value(u'auto preview',
QtCore.QVariant(False)).toBool())
settings.endGroup()
def save(self):
"""
Save the settings from the form
"""
self.MonitorNumber = self.MonitorComboBox.currentIndex()
settings = QtCore.QSettings()
settings.beginGroup(self.settingsSection)
settings.setValue(u'monitor', QtCore.QVariant(self.MonitorNumber))
settings.setValue(u'display on monitor',
QtCore.QVariant(self.DisplayOnMonitor))
settings.setValue(u'blank warning', QtCore.QVariant(self.Warning))
settings.setValue(u'auto open', QtCore.QVariant(self.AutoOpen))
settings.setValue(u'show splash', QtCore.QVariant(self.ShowSplash))
QtCore.QVariant(self.DisplayOnMonitorCheck.isChecked()))
settings.setValue(u'blank warning',
QtCore.QVariant(self.WarningCheckBox.isChecked()))
settings.setValue(u'auto open',
QtCore.QVariant(self.AutoOpenCheckBox.isChecked()))
settings.setValue(u'show splash',
QtCore.QVariant(self.ShowSplashCheckBox.isChecked()))
settings.setValue(u'save prompt',
QtCore.QVariant(self.PromptSaveService))
settings.setValue(u'auto preview', QtCore.QVariant(self.AutoPreview))
settings.setValue(u'ccli number', QtCore.QVariant(self.CCLINumber))
QtCore.QVariant(self.SaveCheckServiceCheckBox.isChecked()))
settings.setValue(u'auto preview',
QtCore.QVariant(self.AutoPreviewCheckBox.isChecked()))
settings.setValue(u'ccli number',
QtCore.QVariant(self.NumberEdit.displayText()))
settings.setValue(u'songselect username',
QtCore.QVariant(self.Username))
QtCore.QVariant(self.UsernameEdit.displayText()))
settings.setValue(u'songselect password',
QtCore.QVariant(self.Password))
QtCore.QVariant(self.PasswordEdit.displayText()))
settings.endGroup()
self.screens.display = self.DisplayOnMonitor
self.screens.display = self.DisplayOnMonitorCheck.isChecked()
#Monitor Number has changed.
if self.screens.monitor_number != self.MonitorNumber:
self.screens.monitor_number = self.MonitorNumber

View File

@ -26,14 +26,38 @@
import logging
import os
from PyQt4 import QtCore, QtGui
from PyQt4 import QtCore, QtGui, QtWebKit
from PyQt4.phonon import Phonon
from openlp.core.lib import Receiver, resize_image
from openlp.core.ui import HideMode
from openlp.core.utils import AppLocation
log = logging.getLogger(__name__)
HTMLIMAGE = """<html>
<body>
<img src=\"file://%s\" alt\"Hello\">
</body></html>
"""
#http://www.steveheffernan.com/html5-video-player/demo-video-player.html
HTMLVIDEO = u"""<html>
<script type="text/javascript" charset="utf-8">
var video;
var bodyLoaded = function(){
video = document.getElementById("video");
video.volume = 0;
}
</script>
<body id=\"body\" onload=\"bodyLoaded();>\"
<video id=\"video\" src=\"%s\"
autoplay loop width=%s height=%s autobuffer=\"autobuffer\" preload >
your browser does not support the video tag
</video>
</body></html>
"""
class DisplayManager(QtGui.QWidget):
"""
Wrapper class to hold the display widgets.
@ -45,18 +69,79 @@ class DisplayManager(QtGui.QWidget):
QtGui.QWidget.__init__(self)
self.screens = screens
self.videoDisplay = VideoDisplay(self, screens)
self.audioPlayer = AudioPlayer(self)
self.mainDisplay = MainDisplay(self, screens)
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'maindisplay_hide'), self.hideDisplay)
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'maindisplay_show'), self.showDisplay)
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'videodisplay_start'), self.onStartVideo)
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'videodisplay_stop'), self.onStopVideo)
def setup(self):
self.videoDisplay.setup()
self.mainDisplay.setup()
def hideDisplay(self, message):
"""
Hide the output displays
"""
self.videoDisplay.mediaHide(message)
self.mainDisplay.hideDisplay(message)
def showDisplay(self, message):
"""
Hide the output displays
"""
self.videoDisplay.mediaShow(message)
self.mainDisplay.showDisplay(message)
def addAlert(self, alertMessage, location):
"""
Handles the addition of an Alert Message to the Displays
"""
self.mainDisplay.addAlert(alertMessage, location)
def displayImage(self, path):
"""
Handles the addition of a background Image to the displays
"""
self.mainDisplay.displayImage(path)
def displayVideo(self, path):
"""
Handles the addition of a background Video to the displays
"""
self.mainDisplay.displayVideo(path)
def onStartVideo(self, item):
"""
Handles the Starting of a Video and Display Management
"""
self.videoDisplay.setVisible(True)
self.mainDisplay.setVisible(False)
self.videoDisplay.onMediaQueue(item)
def onStopVideo(self):
"""
Handles the Stopping of a Video and Display Management
"""
self.mainDisplay.setVisible(True)
self.videoDisplay.setVisible(False)
self.videoDisplay.onMediaStop()
def close(self):
"""
Handles the closure of the displays
"""
self.videoDisplay.close()
self.audioPlayer.close()
self.mainDisplay.close()
class DisplayWidget(QtGui.QWidget):
class DisplayWidget(QtGui.QGraphicsView):
"""
Customised version of QTableWidget which can respond to keyboard
events.
@ -117,32 +202,26 @@ class MainDisplay(DisplayWidget):
log.debug(u'Initialisation started')
DisplayWidget.__init__(self, parent)
self.setWindowFlags(QtCore.Qt.Window | QtCore.Qt.FramelessWindowHint)
self.setWindowState(QtCore.Qt.WindowFullScreen)
self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
self.parent = parent
self.setWindowTitle(u'OpenLP Display')
# WA_TranslucentBackground is not available in QT4.4
try:
self.setAttribute(QtCore.Qt.WA_TranslucentBackground)
except AttributeError:
pass
self.screens = screens
self.display_image = QtGui.QLabel(self)
self.display_image.setScaledContents(True)
self.display_text = QtGui.QLabel(self)
self.display_text.setScaledContents(True)
self.display_alert = QtGui.QLabel(self)
self.display_alert.setScaledContents(True)
self.setupScene()
self.setupImage()
self.setupText()
self.setupAlert()
self.setupBlank()
self.primary = True
self.blankFrame = None
self.frame = None
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'videodisplay_start'), self.hideDisplayForVideo)
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'maindisplay_hide'), self.hideDisplay)
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'maindisplay_show'), self.showDisplay)
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'videodisplay_background'), self.hideDisplayForVideo)
#Hide desktop for now until we know where to put it
#and what size it should be.
self.setVisible(False)
def setup(self):
"""
@ -153,12 +232,9 @@ class MainDisplay(DisplayWidget):
self.setVisible(False)
self.screen = self.screens.current
#Sort out screen locations and sizes
self.display_alert.setGeometry(self.screen[u'size'])
self.display_image.resize(
self.screen[u'size'].width(), self.screen[u'size'].height())
self.display_text.resize(
self.screen[u'size'].width(), self.screen[u'size'].height())
self.setGeometry(self.screen[u'size'])
self.scene.setSceneRect(0,0,self.size().width(), self.size().height())
self.webView.setGeometry(0, 0, self.size().width(), self.size().height())
#Build a custom splash screen
self.InitialFrame = QtGui.QImage(
self.screen[u'size'].width(),
@ -172,7 +248,7 @@ class MainDisplay(DisplayWidget):
(self.screen[u'size'].width() - splash_image.width()) / 2,
(self.screen[u'size'].height() - splash_image.height()) / 2,
splash_image)
self.display_image.setPixmap(QtGui.QPixmap.fromImage(self.InitialFrame))
#self.display_image.setPixmap(QtGui.QPixmap.fromImage(self.InitialFrame))
self.repaint()
#Build a Black screen
painter = QtGui.QPainter()
@ -186,30 +262,65 @@ class MainDisplay(DisplayWidget):
self.transparent = QtGui.QPixmap(
self.screen[u'size'].width(), self.screen[u'size'].height())
self.transparent.fill(QtCore.Qt.transparent)
self.display_alert.setPixmap(self.transparent)
self.display_text.setPixmap(self.transparent)
self.frameView(self.transparent)
# self.display_text.setPixmap(self.transparent)
#self.frameView(self.transparent)
# To display or not to display?
if not self.screen[u'primary']:
self.showFullScreen()
self.setVisible(True)
self.primary = False
else:
self.setVisible(False)
self.primary = True
def setupScene(self):
self.scene = QtGui.QGraphicsScene(self)
self.scene.setSceneRect(0,0,self.size().width(), self.size().height())
self.setScene(self.scene)
def setupImage(self):
self.webView = QtWebKit.QWebView()
self.page = self.webView.page()
self.imageDisplay = self.page.mainFrame()
self.imageDisplay.setScrollBarPolicy(QtCore.Qt.Vertical, QtCore.Qt.ScrollBarAlwaysOff)
self.imageDisplay.setScrollBarPolicy(QtCore.Qt.Horizontal, QtCore.Qt.ScrollBarAlwaysOff)
self.proxy = QtGui.QGraphicsProxyWidget()
self.proxy.setWidget(self.webView)
self.proxy.setWindowFlags(QtCore.Qt.Window | QtCore.Qt.FramelessWindowHint)
self.proxy.setZValue(2)
self.scene.addItem(self.proxy)
def setupText(self):
#self.display_text = QtGui.QGraphicsTextItem()
self.display_text = QtGui.QGraphicsPixmapItem()
#self.display_text.setPos(0,0)
#self.display_text.setTextWidth(self.size().width())
self.display_text.setZValue(4)
self.scene.addItem(self.display_text)
def setupAlert(self):
self.alertText = QtGui.QGraphicsTextItem()
self.alertText.setTextWidth(self.size().width())
self.alertText.setZValue(8)
self.scene.addItem(self.alertText)
def setupBlank(self):
self.display_blank = QtGui.QGraphicsPixmapItem()
self.display_blank.setZValue(10)
self.scene.addItem(self.display_blank)
def resetDisplay(self):
log.debug(u'resetDisplay')
Receiver.send_message(u'slidecontroller_live_stop_loop')
if self.primary:
self.setVisible(False)
else:
self.showFullScreen()
self.setVisible(True)
def hideDisplayForVideo(self):
"""
Hides the main display if for the video to be played
"""
self.hideDisplay(HideMode.Screen)
# def hideDisplayForVideo(self):
# """
# Hides the main display if for the video to be played
# """
# self.hideDisplay(HideMode.Screen)
def hideDisplay(self, mode=HideMode.Screen):
"""
@ -217,45 +328,30 @@ class MainDisplay(DisplayWidget):
Store the images so they can be replaced when required
"""
log.debug(u'hideDisplay mode = %d', mode)
self.storeImage = QtGui.QPixmap(self.display_image.pixmap())
self.storeText = QtGui.QPixmap(self.display_text.pixmap())
self.display_alert.setPixmap(self.transparent)
self.display_text.setPixmap(self.transparent)
#self.display_text.setPixmap(self.transparent)
if mode == HideMode.Screen:
self.display_image.setPixmap(self.transparent)
#self.display_image.setPixmap(self.transparent)
self.setVisible(False)
elif mode == HideMode.Blank:
self.display_image.setPixmap(
self.display_blank.setPixmap(
QtGui.QPixmap.fromImage(self.blankFrame))
else:
if self.parent.renderManager.renderer.bg_frame:
self.display_image.setPixmap(QtGui.QPixmap.fromImage(
self.display_blank.setPixmap(QtGui.QPixmap.fromImage(
self.parent.renderManager.renderer.bg_frame))
else:
self.display_image.setPixmap(
self.display_blank.setPixmap(
QtGui.QPixmap.fromImage(self.blankFrame))
self.moveToTop()
def moveToTop(self):
log.debug(u'moveToTop')
self.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint |
QtCore.Qt.FramelessWindowHint | QtCore.Qt.Dialog)
self.show()
def showDisplay(self):
def showDisplay(self, message=u''):
"""
Show the stored layers so the screen reappears as it was
originally.
Make the stored images None to release memory.
"""
log.debug(u'showDisplay')
if self.storeImage:
self.display_image.setPixmap(self.storeImage)
self.display_alert.setPixmap(self.transparent)
if self.storeText:
self.display_text.setPixmap(self.storeText)
self.storeImage = None
self.store = None
self.moveToTop()
self.display_blank.setPixmap(self.transparent)
#Trigger actions when display is active again
Receiver.send_message(u'maindisplay_active')
def addImageWithText(self, frame):
@ -263,57 +359,91 @@ class MainDisplay(DisplayWidget):
frame = resize_image(
frame, self.screen[u'size'].width(), self.screen[u'size'].height())
self.display_image.setPixmap(QtGui.QPixmap.fromImage(frame))
self.moveToTop()
def setAlertSize(self, top, height):
log.debug(u'setAlertSize')
self.display_alert.setGeometry(
QtCore.QRect(0, top,
self.screen[u'size'].width(), height))
def addAlertImage(self, frame, blank=False):
def addAlert(self, message, location):
"""
Places the Alert text on the display at the correct location
``message``
Text to be displayed
``location``
Where on the screen the text should be. From the AlertTab
Combo box.
"""
log.debug(u'addAlertImage')
if blank:
self.display_alert.setPixmap(self.transparent)
if location == 0:
self.alertText.setPos(0, 0)
elif location == 1:
self.alertText.setPos(0,self.size().height()/2)
else:
self.display_alert.setPixmap(frame)
self.moveToTop()
self.alertText.setPos(0,self.size().height() - 76)
self.alertText.setHtml(message)
def frameView(self, frame, transition=False, display=True):
def displayImage(self, path):
"""
Places the Image passed on the display screen
``path``
The path to the image to be displayed
"""
log.debug(u'adddisplayImage')
self.imageDisplay.setHtml(HTMLIMAGE % path)
def displayVideo(self, path):
"""
Places the Video passed on the display screen
``path``
The path to the image to be displayed
"""
log.debug(u'adddisplayVideo')
self.imageDisplay.setHtml(HTMLVIDEO %
(path, self.screen[u'size'].width(), self.screen[u'size'].height()))
def frameView(self, frame, transition=False):
"""
Called from a slide controller to display a frame
if the alert is in progress the alert is added on top
``frame``
Image frame to be rendered
``transition``
Are transitions required.
"""
log.debug(u'frameView %d' % (display))
if display:
if transition:
if self.frame is not None:
self.display_text.setPixmap(
QtGui.QPixmap.fromImage(self.frame))
self.repaint()
self.frame = None
if frame[u'trans'] is not None:
self.display_text.setPixmap(
QtGui.QPixmap.fromImage(frame[u'trans']))
self.repaint()
self.frame = frame[u'trans']
log.debug(u'frameView')
if transition:
if self.frame is not None:
self.display_text.setPixmap(
QtGui.QPixmap.fromImage(frame[u'main']))
self.display_frame = frame[u'main']
QtGui.QPixmap.fromImage(self.frame))
self.update()
self.frame = None
if frame[u'trans'] is not None:
self.display_text.setPixmap(
QtGui.QPixmap.fromImage(frame[u'trans']))
self.repaint()
else:
if isinstance(frame, QtGui.QPixmap):
self.display_text.setPixmap(frame)
else:
self.display_text.setPixmap(QtGui.QPixmap.fromImage(frame))
self.display_frame = frame
if not self.isVisible() and self.screens.display:
self.setVisible(True)
self.showFullScreen()
self.frame = frame[u'trans']
self.display_text.setPixmap(
QtGui.QPixmap.fromImage(frame[u'main']))
self.display_frame = frame[u'main']
self.repaint()
else:
self.storeText = QtGui.QPixmap.fromImage(frame[u'main'])
if isinstance(frame, QtGui.QPixmap):
self.display_text.setPixmap(frame)
else:
self.display_text.setPixmap(QtGui.QPixmap.fromImage(frame))
self.display_frame = frame
if not self.isVisible() and self.screens.display:
self.setVisible(True)
def closeEvent(self, event):
"""
Shutting down cleans up background files
"""
serviceItemPath = AppLocation.get_section_data_path(u'serviceItems')
for file in os.listdir(serviceItemPath):
file_path = os.path.join(serviceItemPath, file)
try:
if os.path.isfile(file_path):
os.remove(file_path)
except OSError:
log.exception(u'Failed to clean up servicePath')
class VideoDisplay(Phonon.VideoWidget):
"""
@ -339,37 +469,29 @@ class VideoDisplay(Phonon.VideoWidget):
self.screens = screens
self.hidden = False
self.message = None
self.mediaActive = False
self.mediaObject = Phonon.MediaObject()
self.setAspectRatio(aspect)
self.audioObject = Phonon.AudioOutput(Phonon.VideoCategory)
Phonon.createPath(self.mediaObject, self)
Phonon.createPath(self.mediaObject, self.audioObject)
flags = QtCore.Qt.FramelessWindowHint | QtCore.Qt.Dialog
# WindowsStaysOnBottomHint is not available in QT4.4
try:
flags = flags | QtCore.Qt.WindowStaysOnBottomHint
except AttributeError:
pass
## # WindowsStaysOnBottomHint is not available in QT4.4
# try:
# flags = flags | QtCore.Qt.WindowStaysOnBottomHint
# except AttributeError:
# pass
self.setWindowFlags(flags)
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'maindisplay_hide'), self.mediaHide)
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'maindisplay_show'), self.mediaShow)
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'videodisplay_start'), self.onMediaQueue)
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'videodisplay_play'), self.onMediaPlay)
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'videodisplay_pause'), self.onMediaPause)
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'videodisplay_stop'), self.onMediaStop)
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'videodisplay_background'), self.onMediaBackground)
# QtCore.QObject.connect(Receiver.get_receiver(),
# QtCore.SIGNAL(u'videodisplay_background'), self.onMediaBackground)
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'config_updated'), self.setup)
QtCore.QObject.connect(self.mediaObject,
QtCore.SIGNAL(u'finished()'), self.onMediaBackground)
QtCore.SIGNAL(u'finished()'), self.onMediaStop)
self.setVisible(False)
def keyPressEvent(self, event):
@ -392,38 +514,48 @@ class VideoDisplay(Phonon.VideoWidget):
#Sort out screen locations and sizes
self.setGeometry(self.screen[u'size'])
# To display or not to display?
if not self.screen[u'primary'] and self.isVisible():
self.showFullScreen()
if not self.screen[u'primary']: # and self.isVisible():
#self.showFullScreen()
self.setVisible(False)
self.primary = False
else:
self.setVisible(False)
self.primary = True
def onMediaBackground(self, message=None):
def closeEvent(self, event):
"""
Play a video triggered from the video plugin with the
file name passed in on the event.
Also triggered from the Finish event so the video will loop
if it is triggered from the plugin
Shutting down so clean up connections
"""
log.debug(u'VideoDisplay Queue new media message %s' % message)
#If not file take the stored one
if not message:
message = self.message
# still no file name then stop as it was a normal video stopping
if message:
self.mediaObject.setCurrentSource(Phonon.MediaSource(message))
self.message = message
self._play()
self.onMediaStop()
for pth in self.outputPaths():
disconnected = pth.disconnect()
# def onMediaBackground(self, message=None):
# """
# Play a video triggered from the video plugin with the
# file name passed in on the event.
# Also triggered from the Finish event so the video will loop
# if it is triggered from the plugin
# """
# log.debug(u'VideoDisplay Queue new media message %s' % message)
# #If not file take the stored one
# if not message:
# message = self.message
# # still no file name then stop as it was a normal video stopping
# if message:
# self.mediaObject.setCurrentSource(Phonon.MediaSource(message))
# self.message = message
# self._play()
def onMediaQueue(self, message):
"""
Set up a video to play from the serviceitem.
"""
log.debug(u'VideoDisplay Queue new media message %s' % message)
file = os.path.join(message[0].get_frame_path(),
message[0].get_frame_title())
file = os.path.join(message.get_frame_path(),
message.get_frame_title())
self.mediaObject.setCurrentSource(Phonon.MediaSource(file))
self.mediaActive = True
self._play()
def onMediaPlay(self):
@ -442,7 +574,6 @@ class VideoDisplay(Phonon.VideoWidget):
log.debug(u'VideoDisplay _play called')
self.mediaObject.play()
self.setVisible(True)
self.showFullScreen()
def onMediaPause(self):
"""
@ -458,6 +589,7 @@ class VideoDisplay(Phonon.VideoWidget):
"""
log.debug(u'VideoDisplay Media stopped by user')
self.message = None
self.mediaActive = False
self.mediaObject.stop()
self.onMediaFinish()
@ -469,7 +601,7 @@ class VideoDisplay(Phonon.VideoWidget):
self.mediaObject.clearQueue()
self.setVisible(False)
def mediaHide(self):
def mediaHide(self, message=u''):
"""
Hide the video display
"""
@ -477,10 +609,90 @@ class VideoDisplay(Phonon.VideoWidget):
self.hidden = True
self.setVisible(False)
def mediaShow(self):
def mediaShow(self, message=''):
"""
Show the video disaply if it was already hidden
"""
if self.hidden:
self.hidden = False
self._play()
if self.mediaActive:
self._play()
class AudioPlayer(QtCore.QObject):
"""
This Class will play audio only allowing components to work witn a
soundtrack which does not take over the user interface.
"""
log.info(u'AudioPlayer Loaded')
def __init__(self, parent):
"""
The constructor for the display form.
``parent``
The parent widget.
``screens``
The list of screens.
"""
log.debug(u'AudioPlayer Initialisation started')
QtCore.QObject.__init__(self)
self.parent = parent
self.message = None
self.mediaObject = Phonon.MediaObject()
self.audioObject = Phonon.AudioOutput(Phonon.VideoCategory)
Phonon.createPath(self.mediaObject, self.audioObject)
def setup(self):
"""
Sets up the Audio Player for use
"""
log.debug(u'AudioPlayer Setup')
def close(self):
"""
Shutting down so clean up connections
"""
self.onMediaStop()
for pth in self.mediaObject.outputPaths():
disconnected = pth.disconnect()
def onMediaQueue(self, message):
"""
Set up a video to play from the serviceitem.
"""
log.debug(u'AudioPlayer Queue new media message %s' % message)
file = os.path.join(message[0].get_frame_path(),
message[0].get_frame_title())
self.mediaObject.setCurrentSource(Phonon.MediaSource(file))
self.onMediaPlay()
def onMediaPlay(self):
"""
We want to play the play so start it
"""
log.debug(u'AudioPlayer _play called')
self.mediaObject.play()
def onMediaPause(self):
"""
Pause the Audio
"""
log.debug(u'AudioPlayer Media paused by user')
self.mediaObject.pause()
def onMediaStop(self):
"""
Stop the Audio and clean up
"""
log.debug(u'AudioPlayer Media stopped by user')
self.message = None
self.mediaObject.stop()
self.onMediaFinish()
def onMediaFinish(self):
"""
Clean up the Object queue
"""
log.debug(u'AudioPlayer Reached end of media playlist')
self.mediaObject.clearQueue()

View File

@ -63,7 +63,7 @@ class VersionThread(QtCore.QThread):
self.parent = parent
self.app_version = app_version
self.version_splitter = re.compile(
r'([0-9]+).([0-9]+).([0-9]+)(?:-bzr([0-9]+))')
r'([0-9]+).([0-9]+).([0-9]+)(?:-bzr([0-9]+))?')
def run(self):
"""
@ -79,14 +79,14 @@ class VersionThread(QtCore.QThread):
remote_version[u'major'] = int(match.group(1))
remote_version[u'minor'] = int(match.group(2))
remote_version[u'release'] = int(match.group(3))
if len(match.groups()) > 3:
if len(match.groups()) > 3 and match.group(4):
remote_version[u'revision'] = int(match.group(4))
match = self.version_splitter.match(self.app_version[u'full'])
if match:
local_version[u'major'] = int(match.group(1))
local_version[u'minor'] = int(match.group(2))
local_version[u'release'] = int(match.group(3))
if len(match.groups()) > 3:
if len(match.groups()) > 3 and match.group(4):
local_version[u'revision'] = int(match.group(4))
if remote_version[u'major'] > local_version[u'major'] or \
remote_version[u'minor'] > local_version[u'minor'] or \
@ -845,7 +845,10 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
recentFileCount = QtCore.QSettings().value(
self.generalSettingsSection + u'/max recent files',
QtCore.QVariant(4)).toInt()[0]
if filename and filename not in self.recentFiles:
if filename:
position = self.recentFiles.indexOf(filename)
if position != -1:
self.recentFiles.removeAt(position)
self.recentFiles.insert(0, QtCore.QString(filename))
while self.recentFiles.count() > recentFileCount:
self.recentFiles.removeLast()

View File

@ -33,7 +33,7 @@ log = logging.getLogger(__name__)
from PyQt4 import QtCore, QtGui
from openlp.core.lib import OpenLPToolbar, ServiceItem, context_menu_action, \
Receiver, build_icon, ItemCapabilities, SettingsManager, translate
Receiver, build_icon, ItemCapabilities, SettingsManager, translate, ThemeLevel
from openlp.core.ui import ServiceNoteForm, ServiceItemEditForm
from openlp.core.utils import AppLocation
@ -134,15 +134,13 @@ class ServiceManager(QtGui.QWidget):
self.ThemeLabel = QtGui.QLabel(translate('ServiceManager', 'Theme:'),
self)
self.ThemeLabel.setMargin(3)
self.Toolbar.addWidget(self.ThemeLabel)
self.Toolbar.addToolbarWidget(u'ThemeLabel', self.ThemeLabel)
self.ThemeComboBox = QtGui.QComboBox(self.Toolbar)
self.ThemeComboBox.setToolTip(translate('ServiceManager',
'Select a theme for the service'))
self.ThemeComboBox.setSizeAdjustPolicy(
QtGui.QComboBox.AdjustToContents)
self.ThemeWidget = QtGui.QWidgetAction(self.Toolbar)
self.ThemeWidget.setDefaultWidget(self.ThemeComboBox)
self.Toolbar.addAction(self.ThemeWidget)
self.Toolbar.addToolbarWidget(u'ThemeWidget', self.ThemeComboBox)
self.Layout.addWidget(self.Toolbar)
# Create the service manager list
self.ServiceManagerList = ServiceManagerList(self)
@ -214,6 +212,8 @@ class ServiceManager(QtGui.QWidget):
QtCore.SIGNAL(u'servicemanager_list_request'), self.listRequest)
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'config_updated'), self.regenerateServiceItems)
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'theme_update_global'), self.themeChange)
# Last little bits of setting up
self.service_theme = unicode(QtCore.QSettings().value(
self.parent.serviceSettingsSection + u'/service theme',
@ -625,13 +625,13 @@ class ServiceManager(QtGui.QWidget):
def onLoadService(self, lastService=False):
if lastService:
filename = SettingsManager.get_last_dir(
self.parent.serviceSettingsSection)
filename = self.parent.recentFiles[0]
else:
filename = QtGui.QFileDialog.getOpenFileName(
self, translate('ServiceManager', 'Open Service'),
SettingsManager.get_last_dir(
self.parent.serviceSettingsSection), u'Services (*.osz)')
filename = QtCore.QDir.toNativeSeparators(filename)
self.loadService(filename)
def loadService(self, filename=None):
@ -756,6 +756,18 @@ class ServiceManager(QtGui.QWidget):
QtCore.QVariant(self.service_theme))
self.regenerateServiceItems()
def themeChange(self):
"""
The theme may have changed in the settings dialog so make
sure the theme combo box is in the correct state.
"""
if self.parent.RenderManager.theme_level == ThemeLevel.Global:
self.Toolbar.actions[u'ThemeLabel'].setVisible(False)
self.Toolbar.actions[u'ThemeWidget'].setVisible(False)
else:
self.Toolbar.actions[u'ThemeLabel'].setVisible(True)
self.Toolbar.actions[u'ThemeWidget'].setVisible(True)
def regenerateServiceItems(self):
"""
Rebuild the service list as things have changed and a

View File

@ -105,9 +105,9 @@ class SlideController(QtGui.QWidget):
self.isLive = isLive
self.parent = parent
self.mainDisplay = self.parent.displayManager.mainDisplay
self.displayManager = self.parent.displayManager
self.loopList = [
u'Start Loop',
u'Stop Loop',
u'Loop Separator',
u'Image SpinBox'
]
@ -196,18 +196,25 @@ class SlideController(QtGui.QWidget):
self.onSlideSelectedLast)
if self.isLive:
self.Toolbar.addToolbarSeparator(u'Close Separator')
self.blankButton = self.Toolbar.addToolbarButton(
u'Blank Screen', u':/slides/slide_blank.png',
translate('SlideController', 'Blank Screen'),
self.onBlankDisplay, True)
self.themeButton = self.Toolbar.addToolbarButton(
u'Display Theme', u':/slides/slide_theme.png',
translate('SlideController', 'Theme Screen'),
self.onThemeDisplay, True)
self.hideButton = self.Toolbar.addToolbarButton(
u'Hide screen', u':/slides/slide_desktop.png',
translate('SlideController', 'Hide Screen'),
self.onHideDisplay, True)
self.HideMenu = QtGui.QToolButton(self.Toolbar)
self.HideMenu.setText(translate('SlideController', 'Hide'))
self.HideMenu.setPopupMode(QtGui.QToolButton.MenuButtonPopup)
self.Toolbar.addToolbarWidget(u'Hide Menu', self.HideMenu)
self.HideMenu.setMenu(QtGui.QMenu(
translate('SlideController', 'Hide'), self.Toolbar))
self.BlankScreen = QtGui.QAction(QtGui.QIcon( u':/slides/slide_blank.png'), u'Blank Screen', self.HideMenu)
self.BlankScreen.setCheckable(True)
QtCore.QObject.connect(self.BlankScreen, QtCore.SIGNAL("triggered(bool)"), self.onBlankDisplay)
self.ThemeScreen = QtGui.QAction(QtGui.QIcon(u':/slides/slide_theme.png'), u'Blank to Theme', self.HideMenu)
self.ThemeScreen.setCheckable(True)
QtCore.QObject.connect(self.ThemeScreen, QtCore.SIGNAL("triggered(bool)"), self.onThemeDisplay)
self.DesktopScreen = QtGui.QAction(QtGui.QIcon(u':/slides/slide_desktop.png'), u'Show Desktop', self.HideMenu)
self.DesktopScreen.setCheckable(True)
QtCore.QObject.connect(self.DesktopScreen, QtCore.SIGNAL("triggered(bool)"), self.onHideDisplay)
self.HideMenu.setDefaultAction(self.BlankScreen)
self.HideMenu.menu().addAction(self.BlankScreen)
self.HideMenu.menu().addAction(self.ThemeScreen)
self.HideMenu.menu().addAction(self.DesktopScreen)
if not self.isLive:
self.Toolbar.addToolbarSeparator(u'Close Separator')
self.Toolbar.addToolbarButton(
@ -252,19 +259,6 @@ class SlideController(QtGui.QWidget):
u'Media Stop', u':/slides/media_playback_stop.png',
translate('SlideController', 'Start playing media'),
self.onMediaStop)
if self.isLive:
self.blankButton = self.Mediabar.addToolbarButton(
u'Blank Screen', u':/slides/slide_blank.png',
translate('SlideController', 'Blank Screen'),
self.onBlankDisplay, True)
self.themeButton = self.Mediabar.addToolbarButton(
u'Display Theme', u':/slides/slide_theme.png',
translate('SlideController', 'Theme Screen'),
self.onThemeDisplay, True)
self.hideButton = self.Mediabar.addToolbarButton(
u'Hide screen', u':/slides/slide_desktop.png',
translate('SlideController', 'Hide Screen'),
self.onHideDisplay, True)
if not self.isLive:
self.seekSlider = Phonon.SeekSlider()
self.seekSlider.setGeometry(QtCore.QRect(90, 260, 221, 24))
@ -340,6 +334,7 @@ class SlideController(QtGui.QWidget):
self.receiveSpinDelay)
if isLive:
self.Toolbar.makeWidgetsInvisible(self.loopList)
self.Toolbar.actions[u'Stop Loop'].setVisible(False)
else:
self.Toolbar.makeWidgetsInvisible(self.songEditList)
self.Mediabar.setVisible(False)
@ -436,8 +431,8 @@ class SlideController(QtGui.QWidget):
self.Mediabar.setVisible(False)
self.Toolbar.makeWidgetsInvisible([u'Song Menu'])
self.Toolbar.makeWidgetsInvisible(self.loopList)
self.Toolbar.actions[u'Stop Loop'].setVisible(False)
if item.is_text():
self.Toolbar.makeWidgetsInvisible(self.loopList)
if QtCore.QSettings().value(
self.parent.songsSettingsSection + u'/show songbar',
QtCore.QVariant(True)).toBool() and len(self.slideList) > 0:
@ -519,21 +514,21 @@ class SlideController(QtGui.QWidget):
"""
log.debug(u'processManagerItem')
self.onStopLoop()
#If old item was a command tell it to stop
#If old item was a command tell it to stop
if self.serviceItem:
if self.serviceItem.is_command():
Receiver.send_message(u'%s_stop' %
Receiver.send_message(u'%s_stop' %
self.serviceItem.name.lower(), [serviceItem, self.isLive])
if self.serviceItem.is_media():
self.onMediaStop()
if serviceItem.is_media():
self.onMediaStart(serviceItem)
if self.isLive:
blanked = self.blankButton.isChecked()
else:
blanked = False
# if self.isLive:
# blanked = self.blankButton.isChecked()
# else:
# blanked = False
Receiver.send_message(u'%s_start' % serviceItem.name.lower(),
[serviceItem, self.isLive, blanked, slideno])
[serviceItem, self.isLive, True, slideno])
self.slideList = {}
width = self.parent.ControlSplitter.sizes()[self.split]
#Set pointing cursor when we have somthing to point at
@ -661,7 +656,7 @@ class SlideController(QtGui.QWidget):
"""
log.debug(u'mainDisplaySetBackground')
if not self.mainDisplay.primary:
self.blankButton.setChecked(True)
self.onBlankDisplay(True)
def onSlideBlank(self):
"""
@ -679,55 +674,55 @@ class SlideController(QtGui.QWidget):
"""
Handle the blank screen button actions
"""
log.debug(u'onBlankDisplay %d' % checked)
self.hideButton.setChecked(False)
self.themeButton.setChecked(False)
self.canDisplay = not checked
log.debug(u'onBlankDisplay %s' % checked)
self.HideMenu.setDefaultAction(self.BlankScreen)
self.BlankScreen.setChecked(checked)
self.ThemeScreen.setChecked(False)
self.DesktopScreen.setChecked(False)
QtCore.QSettings().setValue(
self.parent.generalSettingsSection + u'/screen blank',
QtCore.QVariant(checked))
if checked:
Receiver.send_message(u'maindisplay_hide', HideMode.Blank)
self.blankPlugin(True)
else:
Receiver.send_message(u'maindisplay_show')
self.blankPlugin(False)
self.blankPlugin(checked)
def onThemeDisplay(self, checked):
"""
Handle the Theme screen button
"""
log.debug(u'onThemeDisplay %d' % checked)
self.blankButton.setChecked(False)
self.hideButton.setChecked(False)
self.canDisplay = False
log.debug(u'onThemeDisplay %s' % checked)
self.HideMenu.setDefaultAction(self.ThemeScreen)
self.BlankScreen.setChecked(False)
self.ThemeScreen.setChecked(checked)
self.DesktopScreen.setChecked(False)
if checked:
Receiver.send_message(u'maindisplay_hide', HideMode.Theme)
self.blankPlugin(True)
else:
Receiver.send_message(u'maindisplay_show')
self.blankPlugin(False)
self.blankPlugin(checked)
def onHideDisplay(self, checked):
"""
Handle the Hide screen button
"""
log.debug(u'onHideDisplay %d' % checked)
self.blankButton.setChecked(False)
self.themeButton.setChecked(False)
self.canDisplay = False
log.debug(u'onHideDisplay %s' % checked)
self.HideMenu.setDefaultAction(self.DesktopScreen)
self.BlankScreen.setChecked(False)
self.ThemeScreen.setChecked(False)
self.DesktopScreen.setChecked(checked)
if checked:
Receiver.send_message(u'maindisplay_hide', HideMode.Screen)
self.hidePlugin(True)
else:
Receiver.send_message(u'maindisplay_show')
self.hidePlugin(False)
self.hidePlugin(checked)
def blankPlugin(self, blank):
"""
Blank the display screen within a plugin if required.
"""
log.debug(u'blankPlugin %d ', blank)
log.debug(u'blankPlugin %s ', blank)
if self.serviceItem is not None:
if blank:
Receiver.send_message(u'%s_blank'
@ -740,8 +735,9 @@ class SlideController(QtGui.QWidget):
def hidePlugin(self, hide):
"""
Blank the display screen.
Tell the plugin to hide the display screen.
"""
log.debug(u'hidePlugin %s ', hide)
if self.serviceItem is not None:
if hide:
Receiver.send_message(u'%s_hide'
@ -786,7 +782,10 @@ class SlideController(QtGui.QWidget):
log.log(
15, u'Slide Rendering took %4s' % (time.time() - before))
if self.isLive:
self.mainDisplay.frameView(frame, True, self.canDisplay)
if self.serviceItem.is_text():
self.mainDisplay.frameView(frame, True)
else:
self.displayManager.displayImage(frame[u'display'])
self.selectedRow = row
Receiver.send_message(u'slidecontroller_%s_changed' % self.typePrefix,
row)
@ -889,6 +888,8 @@ class SlideController(QtGui.QWidget):
if self.PreviewListWidget.rowCount() > 1:
self.timer_id = self.startTimer(
int(self.DelaySpinBox.value()) * 1000)
self.Toolbar.actions[u'Stop Loop'].setVisible(True)
self.Toolbar.actions[u'Start Loop'].setVisible(False)
def onStopLoop(self):
"""
@ -897,6 +898,8 @@ class SlideController(QtGui.QWidget):
if self.timer_id != 0:
self.killTimer(self.timer_id)
self.timer_id = 0
self.Toolbar.actions[u'Start Loop'].setVisible(True)
self.Toolbar.actions[u'Stop Loop'].setVisible(False)
def timerEvent(self, event):
"""
@ -928,8 +931,7 @@ class SlideController(QtGui.QWidget):
"""
log.debug(u'SlideController onMediaStart')
if self.isLive:
Receiver.send_message(u'videodisplay_start',
[item, self.blankButton.isChecked()])
Receiver.send_message(u'videodisplay_start', item)
else:
self.mediaObject.stop()
self.mediaObject.clearQueue()

View File

@ -150,9 +150,9 @@ class ThemesTab(SettingsTab):
settings.setValue(u'global theme',
QtCore.QVariant(self.global_theme))
settings.endGroup()
Receiver.send_message(u'theme_update_global', self.global_theme)
self.parent.RenderManager.set_global_theme(
self.global_theme, self.theme_level)
Receiver.send_message(u'theme_update_global', self.global_theme)
def postSetUp(self):
Receiver.send_message(u'theme_update_global', self.global_theme)

View File

@ -22,7 +22,10 @@
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
"""
The :mod:`languagemanager` module provides all the translation settings and
language file loading for OpenLP.
"""
import logging
import os
@ -42,50 +45,74 @@ class LanguageManager(object):
@staticmethod
def get_translator(language):
"""
Set up a translator to use in this instance of OpenLP
``language``
The language to load into the translator
"""
if LanguageManager.AutoLanguage:
language = QtCore.QLocale.system().name()
lang_Path = AppLocation.get_directory(AppLocation.AppDir)
lang_Path = os.path.join(lang_Path, u'resources', u'i18n')
appTranslator = QtCore.QTranslator()
if appTranslator.load("openlp_" + language, lang_Path):
return appTranslator
app_translator = QtCore.QTranslator()
if app_translator.load("openlp_" + language, lang_Path):
return app_translator
@staticmethod
def find_qm_files():
"""
Find all available language files in this OpenLP install
"""
trans_dir = AppLocation.get_directory(AppLocation.AppDir)
trans_dir = QtCore.QDir(os.path.join(trans_dir, u'resources', u'i18n'))
fileNames = trans_dir.entryList(QtCore.QStringList("*.qm"),
file_names = trans_dir.entryList(QtCore.QStringList("*.qm"),
QtCore.QDir.Files, QtCore.QDir.Name)
for name in fileNames:
fileNames.replaceInStrings(name, trans_dir.filePath(name))
return fileNames
for name in file_names:
file_names.replaceInStrings(name, trans_dir.filePath(name))
return file_names
@staticmethod
def language_name(qmFile):
def language_name(qm_file):
"""
Load the language name from a language file
``qm_file``
The file to obtain the name from
"""
translator = QtCore.QTranslator()
translator.load(qmFile)
translator.load(qm_file)
return translator.translate('MainWindow', 'English')
@staticmethod
def get_language():
"""
Retrieve a saved language to use from settings
"""
settings = QtCore.QSettings(u'OpenLP', u'OpenLP')
language = unicode(settings.value(
u'general/language', QtCore.QVariant(u'[en]')).toString())
log.info(u'Language file: \'%s\' Loaded from conf file' % language)
regEx = QtCore.QRegExp("^\[(.*)\]")
if regEx.exactMatch(language):
reg_ex = QtCore.QRegExp("^\[(.*)\]")
if reg_ex.exactMatch(language):
LanguageManager.AutoLanguage = True
language = regEx.cap(1)
language = reg_ex.cap(1)
return language
@staticmethod
def set_language(action):
actionName = u'%s' % action.objectName()
qmList = LanguageManager.get_qm_list()
"""
Set the language to translate OpenLP into
``action``
The language menu option
"""
action_name = u'%s' % action.objectName()
qm_list = LanguageManager.get_qm_list()
if LanguageManager.AutoLanguage:
language = u'[%s]' % qmList[actionName]
language = u'[%s]' % qm_list[action_name]
else:
language = u'%s' % qmList[actionName]
language = u'%s' % qm_list[action_name]
QtCore.QSettings().setValue(
u'general/language', QtCore.QVariant(language))
log.info(u'Language file: \'%s\' written to conf file' % language)
@ -96,17 +123,23 @@ class LanguageManager(object):
@staticmethod
def init_qm_list():
"""
Initialise the list of available translations
"""
LanguageManager.__qmList__ = {}
qmFiles = LanguageManager.find_qm_files()
for i, qmf in enumerate(qmFiles):
regEx = QtCore.QRegExp("^.*openlp_(.*).qm")
if regEx.exactMatch(qmf):
langName = regEx.cap(1)
qm_files = LanguageManager.find_qm_files()
for i, qmf in enumerate(qm_files):
reg_ex = QtCore.QRegExp("^.*openlp_(.*).qm")
if reg_ex.exactMatch(qmf):
lang_name = reg_ex.cap(1)
LanguageManager.__qmList__[u'%#2i %s' % (i+1,
LanguageManager.language_name(qmf))] = langName
LanguageManager.language_name(qmf))] = lang_name
@staticmethod
def get_qm_list():
"""
Return the list of available translations
"""
if LanguageManager.__qmList__ is None:
LanguageManager.init_qm_list()
return LanguageManager.__qmList__

View File

@ -24,5 +24,5 @@
###############################################################################
"""
The :mod:`alerts` module provides the Alerts plugin for producing impromptu
on-screen announcements during a service
on-screen announcements during a service.
"""

View File

@ -28,7 +28,9 @@ import logging
from PyQt4 import QtCore, QtGui
from openlp.core.lib import Plugin, build_icon, PluginStatus, translate
from openlp.plugins.alerts.lib import AlertsManager, AlertsTab, DBManager
from openlp.core.lib.db import Manager
from openlp.plugins.alerts.lib import AlertsManager, AlertsTab
from openlp.plugins.alerts.lib.db import init_schema
from openlp.plugins.alerts.forms import AlertForm
log = logging.getLogger(__name__)
@ -39,13 +41,16 @@ class alertsPlugin(Plugin):
def __init__(self, plugin_helpers):
Plugin.__init__(self, u'Alerts', u'1.9.2', plugin_helpers)
self.weight = -3
self.icon = build_icon(u':/media/media_image.png')
self.icon = build_icon(u':/plugins/plugin_alerts.png')
self.alertsmanager = AlertsManager(self)
self.manager = DBManager()
self.manager = Manager(u'alerts', init_schema)
self.alertForm = AlertForm(self.manager, self)
self.status = PluginStatus.Active
def get_settings_tab(self):
"""
Return the settings tab for the Alerts plugin
"""
self.alertsTab = AlertsTab(self)
return self.alertsTab
@ -60,7 +65,7 @@ class alertsPlugin(Plugin):
"""
log.info(u'add tools menu')
self.toolsAlertItem = QtGui.QAction(tools_menu)
AlertIcon = build_icon(u':/tools/tools_alert.png')
AlertIcon = build_icon(u':/plugins/plugin_alerts.png')
self.toolsAlertItem.setIcon(AlertIcon)
self.toolsAlertItem.setObjectName(u'toolsAlertItem')
self.toolsAlertItem.setText(
@ -80,8 +85,8 @@ class alertsPlugin(Plugin):
def finalise(self):
log.info(u'Plugin Finalise')
Plugin.finalise(self)
self.toolsAlertItem.setVisible(False)
#stop any events being processed
def togglealertsState(self):
self.alertsActive = not self.alertsActive
@ -97,4 +102,4 @@ class alertsPlugin(Plugin):
about_text = translate('AlertsPlugin',
'<b>Alerts Plugin</b><br>This plugin '
'controls the displaying of alerts on the presentations screen')
return about_text
return about_text

View File

@ -25,8 +25,8 @@
from PyQt4 import QtGui, QtCore
from openlp.plugins.alerts.lib.models import AlertItem
from openlp.core.lib import translate
from openlp.plugins.alerts.lib.db import AlertItem
from alertdialog import Ui_AlertDialog
@ -62,7 +62,7 @@ class AlertForm(QtGui.QDialog, Ui_AlertDialog):
def loadList(self):
self.AlertListWidget.clear()
alerts = self.manager.get_all_alerts()
alerts = self.manager.get_all_objects(AlertItem, AlertItem.text)
for alert in alerts:
item_name = QtGui.QListWidgetItem(alert.text)
item_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(alert.id))
@ -82,7 +82,7 @@ class AlertForm(QtGui.QDialog, Ui_AlertDialog):
item = self.AlertListWidget.currentItem()
if item:
item_id = (item.data(QtCore.Qt.UserRole)).toInt()[0]
self.parent.manager.delete_alert(item_id)
self.manager.delete_object(AlertItem, item_id)
row = self.AlertListWidget.row(item)
self.AlertListWidget.takeItem(row)
self.AlertTextEdit.setText(u'')
@ -98,7 +98,7 @@ class AlertForm(QtGui.QDialog, Ui_AlertDialog):
else:
alert = AlertItem()
alert.text = unicode(self.AlertTextEdit.text())
self.manager.save_alert(alert)
self.manager.save_object(alert)
self.AlertTextEdit.setText(u'')
self.loadList()
@ -107,9 +107,9 @@ class AlertForm(QtGui.QDialog, Ui_AlertDialog):
Save an alert
"""
if self.item_id:
alert = self.manager.get_alert(self.item_id)
alert = self.manager.get_object(AlertItem, self.item_id)
alert.text = unicode(self.AlertTextEdit.text())
self.manager.save_alert(alert)
self.manager.save_object(alert)
self.item_id = None
self.loadList()
else:

View File

@ -25,4 +25,3 @@
from alertsmanager import AlertsManager
from alertstab import AlertsTab
from manager import DBManager

View File

@ -25,12 +25,21 @@
import logging
from PyQt4 import QtCore, QtGui
from PyQt4 import QtCore
from openlp.core.lib import Receiver, translate
log = logging.getLogger(__name__)
HTMLCODE = u"""
<p style=\"color:%s;
background-color:%s;
font-family:%s;
font-size: %spt; \">
%s
</p>
"""
class AlertsManager(QtCore.QObject):
"""
AlertsTab is the Alerts settings tab in the settings dialog.
@ -47,28 +56,6 @@ class AlertsManager(QtCore.QObject):
QtCore.SIGNAL(u'maindisplay_active'), self.generateAlert)
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'alerts_text'), self.onAlertText)
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'config_screen_changed'), self.screenChanged)
def screenChanged(self):
log.debug(u'screen changed')
self.alertTab = self.parent.alertsTab
self.screen = self.parent.maindisplay.screens.current
self.font = QtGui.QFont()
self.font.setFamily(self.alertTab.font_face)
self.font.setBold(True)
self.font.setPointSize(self.alertTab.font_size)
self.metrics = QtGui.QFontMetrics(self.font)
self.alertHeight = self.metrics.height() + 4
if self.alertTab.location == 0:
self.alertScreenPosition = 0
else:
self.alertScreenPosition = self.screen[u'size'].height() \
- self.alertHeight
self.alertHeight = self.screen[u'size'].height() \
- self.alertScreenPosition
self.parent.maindisplay.setAlertSize(self.alertScreenPosition,
self.alertHeight)
def onAlertText(self, message):
"""
@ -88,8 +75,6 @@ class AlertsManager(QtCore.QObject):
display text
"""
log.debug(u'display alert called %s' % text)
if not self.screen:
self.screenChanged()
self.alertList.append(text)
if self.timer_id != 0:
Receiver.send_message(u'maindisplay_status_text',
@ -100,37 +85,35 @@ class AlertsManager(QtCore.QObject):
self.generateAlert()
def generateAlert(self):
"""
Format and request the Alert and start the timer
"""
log.debug(u'Generate Alert called')
if len(self.alertList) == 0:
return
text = self.alertList.pop(0)
alertTab = self.parent.alertsTab
alertframe = \
QtGui.QPixmap(self.screen[u'size'].width(), self.alertHeight)
alertframe.fill(QtCore.Qt.transparent)
painter = QtGui.QPainter(alertframe)
painter.fillRect(alertframe.rect(), QtCore.Qt.transparent)
painter.setRenderHint(QtGui.QPainter.Antialiasing)
painter.fillRect(
QtCore.QRect(
0, 0, alertframe.rect().width(),
alertframe.rect().height()),
QtGui.QColor(self.alertTab.bg_color))
painter.setFont(self.font)
painter.setPen(QtGui.QColor(self.alertTab.font_color))
x, y = (0, 2)
painter.drawText(
x, y + self.metrics.height() - self.metrics.descent() - 1, text)
painter.end()
self.parent.maindisplay.addAlertImage(alertframe)
text = HTMLCODE % (alertTab.font_color, alertTab.bg_color,
alertTab.font_face, alertTab.font_size, text)
self.parent.preview_controller.parent.displayManager.addAlert(text,
alertTab.location)
# check to see if we have a timer running
if self.timer_id == 0:
self.timer_id = self.startTimer(int(alertTab.timeout) * 1000)
def timerEvent(self, event):
"""
Time has finished so if our time then request the next Alert
if there is one and reset the timer.
``event``
the QT event that has been triggered.
"""
log.debug(u'timer event')
alertTab = self.parent.alertsTab
if event.timerId() == self.timer_id:
self.parent.maindisplay.addAlertImage(None, True)
self.parent.preview_controller.parent.displayManager.addAlert(u'',
alertTab.location)
self.killTimer(self.timer_id)
self.timer_id = 0
self.generateAlert()

View File

@ -128,6 +128,7 @@ class AlertsTab(SettingsTab):
self.LocationComboBox = QtGui.QComboBox(self.LocationWidget)
self.LocationComboBox.addItem(QtCore.QString())
self.LocationComboBox.addItem(QtCore.QString())
self.LocationComboBox.addItem(QtCore.QString())
self.LocationComboBox.setObjectName(u'LocationComboBox')
self.LocationLayout.addWidget(self.LocationComboBox)
self.LocationSpacer = QtGui.QSpacerItem(147, 20,
@ -208,9 +209,11 @@ class AlertsTab(SettingsTab):
translate('AlertsPlugin.AlertsTab', 'Preview'))
self.FontPreview.setText(
translate('AlertsPlugin.AlertsTab', 'openlp.org'))
self.LocationComboBox.setItemText(0,
self.LocationComboBox.setItemText(0,
translate('AlertsPlugin.AlertsTab', 'Top'))
self.LocationComboBox.setItemText(1,
self.LocationComboBox.setItemText(1,
translate('AlertsPlugin.AlertsTab', 'Middle'))
self.LocationComboBox.setItemText(2,
translate('AlertsPlugin.AlertsTab', 'Bottom'))
def onBackgroundColorButtonClicked(self):
@ -295,4 +298,4 @@ class AlertsTab(SettingsTab):
font.setPointSize(self.font_size)
self.FontPreview.setFont(font)
self.FontPreview.setStyleSheet(u'background-color: %s; color: %s' %
(self.bg_color, self.font_color))
(self.bg_color, self.font_color))

View File

@ -1,32 +0,0 @@
# -*- 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, Christian Richter, Maikel Stuivenberg, Martin #
# Thompson, Jon Tibble, Carsten Tinggaard #
# --------------------------------------------------------------------------- #
# This program is free software; you can redistribute it and/or modify it #
# under the terms of the GNU General Public License as published by the Free #
# Software Foundation; version 2 of the License. #
# #
# This program is distributed in the hope that it will be useful, but WITHOUT #
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
# more details. #
# #
# You should have received a copy of the GNU General Public License along #
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
from openlp.core.lib import BaseModel
class AlertItem(BaseModel):
"""
Custom Slide model
"""
pass

View File

@ -22,18 +22,36 @@
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
"""
The :mod:`db` module provides the database and schema that is the backend for
the Alerts plugin
"""
from sqlalchemy import create_engine
from sqlalchemy.orm import scoped_session, sessionmaker, mapper
from sqlalchemy import Column, Table, types
from sqlalchemy.orm import mapper
from openlp.plugins.alerts.lib.meta import metadata
from openlp.plugins.alerts.lib.tables import *
from openlp.plugins.alerts.lib.classes import *
from openlp.core.lib.db import BaseModel, init_db
class AlertItem(BaseModel):
"""
AlertItem model
"""
pass
def init_schema(url):
"""
Setup the alerts database connection and initialise the database schema
``url``
The database to setup
"""
session, metadata = init_db(url)
alerts_table = Table(u'alerts', metadata,
Column(u'id', types.Integer(), primary_key=True),
Column(u'text', types.UnicodeText, nullable=False))
def init_models(url):
engine = create_engine(url)
metadata.bind = engine
session = scoped_session(sessionmaker(autoflush=True, autocommit=False,
bind=engine))
mapper(AlertItem, alerts_table)
metadata.create_all(checkfirst=True)
return session

View File

@ -1,114 +0,0 @@
# -*- 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, Christian Richter, Maikel Stuivenberg, Martin #
# Thompson, Jon Tibble, Carsten Tinggaard #
# --------------------------------------------------------------------------- #
# 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 logging
from PyQt4 import QtCore
from sqlalchemy.exceptions import InvalidRequestError
from openlp.core.utils import AppLocation
from openlp.plugins.alerts.lib.models import init_models, metadata, AlertItem
log = logging.getLogger(__name__)
class DBManager(object):
"""
The Song Manager provides a central location for all database code. This
class takes care of connecting to the database and running all the queries.
"""
log.info(u'Alerts DB loaded')
def __init__(self):
"""
Creates the connection to the database, and creates the tables if they
don't exist.
"""
log.debug(u'Alerts Initialising')
settings = QtCore.QSettings()
settings.beginGroup(u'alerts')
self.db_url = u''
db_type = unicode(
settings.value(u'db type', QtCore.QVariant(u'sqlite')).toString())
if db_type == u'sqlite':
self.db_url = u'sqlite:///%s/alerts.sqlite' % \
AppLocation.get_section_data_path(u'alerts')
else:
self.db_url = u'%s://%s:%s@%s/%s' % (db_type,
unicode(settings.value(u'db username').toString()),
unicode(settings.value(u'db password').toString()),
unicode(settings.value(u'db hostname').toString()),
unicode(settings.value(u'db database').toString()))
settings.endGroup()
self.session = init_models(self.db_url)
metadata.create_all(checkfirst=True)
log.debug(u'Alerts Initialised')
def get_all_alerts(self):
"""
Returns the details of a Alert Show
"""
return self.session.query(AlertItem).order_by(AlertItem.text).all()
def save_alert(self, alert_item):
"""
Saves a Alert show to the database
"""
log.debug(u'Alert added')
try:
self.session.add(alert_item)
self.session.commit()
log.debug(u'Alert saved')
return True
except InvalidRequestError:
self.session.rollback()
log.exception(u'Alert save failed')
return False
def get_alert(self, id=None):
"""
Returns the details of a Alert
"""
if id is None:
return AlertItem()
else:
return self.session.query(AlertItem).get(id)
def delete_alert(self, id):
"""
Delete a Alert show
"""
if id != 0:
alert_item = self.get_alert(id)
try:
self.session.delete(alert_item)
self.session.commit()
return True
except InvalidRequestError:
self.session.rollback()
log.exception(u'Alert deleton failed')
return False
else:
return True

View File

@ -1,38 +0,0 @@
# -*- 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, Christian Richter, Maikel Stuivenberg, Martin #
# Thompson, Jon Tibble, Carsten Tinggaard #
# --------------------------------------------------------------------------- #
# This program is free software; you can redistribute it and/or modify it #
# under the terms of the GNU General Public License as published by the Free #
# Software Foundation; version 2 of the License. #
# #
# This program is distributed in the hope that it will be useful, but WITHOUT #
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
# more details. #
# #
# You should have received a copy of the GNU General Public License along #
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
from sqlalchemy import MetaData
__all__ = ['session', 'metadata', 'engine']
# SQLAlchemy database engine. Updated by model.init_model()
engine = None
# SQLAlchemy session manager. Updated by model.init_model()
session = None
# Global metadata. If you have multiple databases with overlapping table
# names, you'll need a metadata for each database
metadata = MetaData()

View File

@ -1,33 +0,0 @@
# -*- 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, Christian Richter, Maikel Stuivenberg, Martin #
# Thompson, Jon Tibble, Carsten Tinggaard #
# --------------------------------------------------------------------------- #
# This program is free software; you can redistribute it and/or modify it #
# under the terms of the GNU General Public License as published by the Free #
# Software Foundation; version 2 of the License. #
# #
# This program is distributed in the hope that it will be useful, but WITHOUT #
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
# more details. #
# #
# You should have received a copy of the GNU General Public License along #
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
from sqlalchemy import Column, Table, types
from openlp.plugins.alerts.lib.meta import metadata
# Definition of the "alerts" table
alerts_table = Table(u'alerts', metadata,
Column(u'id', types.Integer(), primary_key=True),
Column(u'text', types.UnicodeText, nullable=False))

View File

@ -23,6 +23,6 @@
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
"""
The :mod:`bibles' modules provides the Bible plugin to enable OpenLP to display
scripture
The :mod:`bibles' module provides the Bible plugin to enable OpenLP to display
scripture.
"""

View File

@ -38,7 +38,7 @@ class BiblePlugin(Plugin):
def __init__(self, plugin_helpers):
Plugin.__init__(self, u'Bibles', u'1.9.2', plugin_helpers)
self.weight = -9
self.icon = build_icon(u':/media/media_bible.png')
self.icon = build_icon(u':/plugins/plugin_bibles.png')
#Register the bible Manager
self.status = PluginStatus.Active
self.manager = None
@ -48,14 +48,12 @@ class BiblePlugin(Plugin):
if self.manager is None:
self.manager = BibleManager(self)
Plugin.initialise(self)
self.insert_toolbox_item()
self.ImportBibleItem.setVisible(True)
self.ExportBibleItem.setVisible(True)
def finalise(self):
log.info(u'Plugin Finalise')
Plugin.finalise(self)
self.remove_toolbox_item()
self.ImportBibleItem.setVisible(False)
self.ExportBibleItem.setVisible(False)
@ -99,4 +97,4 @@ class BiblePlugin(Plugin):
def can_delete_theme(self, theme):
if self.settings_tab.bible_theme == theme:
return False
return True
return True

View File

@ -32,6 +32,7 @@ from PyQt4 import QtCore, QtGui
from bibleimportwizard import Ui_BibleImportWizard
from openlp.core.lib import Receiver, SettingsManager, translate
from openlp.core.lib.db import delete_database
from openlp.core.utils import AppLocation
from openlp.plugins.bibles.lib.manager import BibleFormat
@ -224,7 +225,7 @@ class ImportWizardForm(QtGui.QWizard, Ui_BibleImportWizard):
Show the file open dialog for the OSIS file.
"""
self.getFileName(
translate('BiblesPlugin.ImportWizardForm', 'Open OSIS File'),
translate('BiblesPlugin.ImportWizardForm', 'Open OSIS File'),
self.OSISLocationEdit)
def onBooksFileButtonClicked(self):
@ -239,10 +240,8 @@ class ImportWizardForm(QtGui.QWizard, Ui_BibleImportWizard):
"""
Show the file open dialog for the verses CSV file.
"""
self.getFileName(
translate('BiblesPlugin.ImportWizardForm',
'Open Verses CSV File'),
self.CsvVerseLocationEdit)
self.getFileName(translate('BiblesPlugin.ImportWizardForm',
'Open Verses CSV File'), self.CsvVerseLocationEdit)
def onOpenSongBrowseButtonClicked(self):
"""
@ -451,7 +450,7 @@ class ImportWizardForm(QtGui.QWizard, Ui_BibleImportWizard):
self.ImportProgressLabel.setText(
translate('BiblesPlugin.ImportWizardForm',
'Your Bible import failed.'))
importer.delete()
delete_database(self.bibleplugin.settingsSection, importer.file)
def postImport(self):
self.ImportProgressBar.setValue(self.ImportProgressBar.maximum())

View File

@ -97,11 +97,11 @@ class CSVBible(BibleDB):
book_ptr = book.name
self.wizard.incrementProgressBar(
u'Importing %s %s' % (book.name, line[1]))
self.commit()
self.session.commit()
self.create_verse(book.id, line[1], line[2],
unicode(line[3], details['encoding']))
Receiver.send_message(u'openlp_process_events')
self.commit()
self.session.commit()
except IOError:
log.exception(u'Loading verses from file failed')
success = False
@ -113,5 +113,3 @@ class CSVBible(BibleDB):
return False
else:
return success

View File

@ -23,20 +23,99 @@
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
import os
import logging
import chardet
import re
from sqlalchemy import or_
from PyQt4 import QtCore, QtGui
from sqlalchemy import Column, ForeignKey, or_, Table, types
from sqlalchemy.orm import class_mapper, mapper, relation
from sqlalchemy.orm.exc import UnmappedClassError
from openlp.core.lib import translate
from openlp.plugins.bibles.lib.models import *
from openlp.core.lib.db import BaseModel, init_db, Manager
log = logging.getLogger(__name__)
class BibleDB(QtCore.QObject):
class BibleMeta(BaseModel):
"""
Bible Meta Data
"""
pass
class Testament(BaseModel):
"""
Bible Testaments
"""
pass
class Book(BaseModel):
"""
Song model
"""
pass
class Verse(BaseModel):
"""
Topic model
"""
pass
def init_schema(url):
"""
Setup a bible database connection and initialise the database schema
``url``
The database to setup
"""
session, metadata = init_db(url)
meta_table = Table(u'metadata', metadata,
Column(u'key', types.Unicode(255), primary_key=True, index=True),
Column(u'value', types.Unicode(255)),
)
testament_table = Table(u'testament', metadata,
Column(u'id', types.Integer, primary_key=True),
Column(u'name', types.Unicode(50)),
)
book_table = Table(u'book', metadata,
Column(u'id', types.Integer, primary_key=True),
Column(u'testament_id', types.Integer, ForeignKey(u'testament.id')),
Column(u'name', types.Unicode(50), index=True),
Column(u'abbreviation', types.Unicode(5), index=True),
)
verse_table = Table(u'verse', metadata,
Column(u'id', types.Integer, primary_key=True, index=True),
Column(u'book_id', types.Integer, ForeignKey(u'book.id'), index=True),
Column(u'chapter', types.Integer, index=True),
Column(u'verse', types.Integer, index=True),
Column(u'text', types.UnicodeText, index=True),
)
try:
class_mapper(BibleMeta)
except UnmappedClassError:
mapper(BibleMeta, meta_table)
try:
class_mapper(Testament)
except UnmappedClassError:
mapper(Testament, testament_table,
properties={'books': relation(Book, backref='testament')})
try:
class_mapper(Book)
except UnmappedClassError:
mapper(Book, book_table,
properties={'verses': relation(Verse, backref='book')})
try:
class_mapper(Verse)
except UnmappedClassError:
mapper(Verse, verse_table)
metadata.create_all(checkfirst=True)
return session
class BibleDB(QtCore.QObject, Manager):
"""
This class represents a database-bound Bible. It is used as a base class
for all the custom importers, so that the can implement their own import
@ -73,26 +152,10 @@ class BibleDB(QtCore.QObject):
self.file = self.clean_filename(self.name)
if u'file' in kwargs:
self.file = kwargs[u'file']
self.db_file = os.path.join(kwargs[u'path'], self.file)
log.debug(u'Load bible %s on path %s', self.file, self.db_file)
settings = QtCore.QSettings()
settings.beginGroup(u'bibles')
db_type = unicode(
settings.value(u'db type', QtCore.QVariant(u'sqlite')).toString())
db_url = u''
if db_type == u'sqlite':
db_url = u'sqlite:///' + self.db_file
else:
db_url = u'%s://%s:%s@%s/%s' % (db_type,
unicode(settings.value(u'db username').toString()),
unicode(settings.value(u'db password').toString()),
unicode(settings.value(u'db hostname').toString()),
unicode(settings.value(u'db database').toString()))
settings.endGroup()
self.session = init_models(db_url)
metadata.create_all(checkfirst=True)
Manager.__init__(self, u'bibles', init_schema, self.file)
if u'file' in kwargs:
self.get_name()
self.wizard = None
def stop_import(self):
"""
@ -105,7 +168,7 @@ class BibleDB(QtCore.QObject):
"""
Returns the version name of the Bible.
"""
version_name = self.get_meta(u'Version')
version_name = self.get_object(BibleMeta, u'Version')
if version_name:
self.name = version_name.value
else:
@ -125,16 +188,6 @@ class BibleDB(QtCore.QObject):
old_filename = re.sub(r'[^\w]+', u'_', old_filename).strip(u'_')
return old_filename + u'.sqlite'
def delete(self):
"""
Remove the Bible database file. Used when a Bible import fails.
"""
try:
os.remove(self.db_file)
return True
except OSError:
return False
def register(self, wizard):
"""
This method basically just initialialises the database. It is called
@ -146,36 +199,11 @@ class BibleDB(QtCore.QObject):
The actual Qt wizard form.
"""
self.wizard = wizard
self.create_tables()
return self.name
def commit(self):
"""
Perform a database commit.
"""
log.debug('Committing...')
self.session.commit()
def create_tables(self):
"""
Create some initial metadata.
"""
log.debug(u'createTables')
self.create_meta(u'dbversion', u'2')
self.create_testament(u'Old Testament')
self.create_testament(u'New Testament')
self.create_testament(u'Apocrypha')
def create_testament(self, testament):
"""
Add a testament to the database.
``testament``
The testament name.
"""
log.debug(u'BibleDB.create_testament("%s")', testament)
self.session.add(Testament.populate(name=testament))
self.commit()
self.save_object(Testament.populate(name=u'Old Testament'))
self.save_object(Testament.populate(name=u'New Testament'))
self.save_object(Testament.populate(name=u'Apocrypha'))
return self.name
def create_book(self, name, abbrev, testament=1):
"""
@ -193,8 +221,7 @@ class BibleDB(QtCore.QObject):
log.debug(u'create_book %s,%s', name, abbrev)
book = Book.populate(name=name, abbreviation=abbrev,
testament_id=testament)
self.session.add(book)
self.commit()
self.save_object(book)
return book
def create_chapter(self, book_id, chapter, textlist):
@ -221,7 +248,7 @@ class BibleDB(QtCore.QObject):
text = verse_text
)
self.session.add(verse)
self.commit()
self.session.commit()
def create_verse(self, book_id, chapter, verse, text):
"""
@ -252,31 +279,31 @@ class BibleDB(QtCore.QObject):
return verse
def create_meta(self, key, value):
log.debug(u'save_meta %s/%s', key, value)
self.session.add(BibleMeta.populate(key=key, value=value))
self.commit()
"""
Utility method to save BibleMeta objects in a Bible database
def get_books(self):
log.debug(u'BibleDB.get_books()')
return self.session.query(Book).order_by(Book.id).all()
``key``
The key for this instance
``value``
The value for this instance
"""
log.debug(u'save_meta %s/%s', key, value)
self.save_object(BibleMeta.populate(key=key, value=value))
def get_book(self, book):
log.debug(u'BibleDb.get_book("%s")', book)
db_book = self.session.query(Book)\
.filter(Book.name.like(book + u'%'))\
.first()
if db_book is None:
db_book = self.session.query(Book)\
.filter(Book.abbreviation.like(book + u'%'))\
.first()
return db_book
"""
Return a book object from the database
def get_chapter(self, id, chapter):
log.debug(u'BibleDB.get_chapter("%s", %s)', id, chapter)
return self.session.query(Verse)\
.filter_by(chapter=chapter)\
.filter_by(book_id=id)\
.first()
``book``
The name of the book to return
"""
log.debug(u'BibleDb.get_book("%s")', book)
db_book = self.get_object_filtered(Book, Book.name.like(book + u'%'))
if db_book is None:
db_book = self.get_object_filtered(Book,
Book.abbreviation.like(book + u'%'))
return db_book
def get_verses(self, reference_list):
"""
@ -351,6 +378,12 @@ class BibleDB(QtCore.QObject):
return verses
def get_chapter_count(self, book):
"""
Return the number of chapters in a book
``book``
The book to get the chapter count for
"""
log.debug(u'BibleDB.get_chapter_count("%s")', book)
count = self.session.query(Verse.chapter).join(Book)\
.filter(Book.name==book)\
@ -361,6 +394,15 @@ class BibleDB(QtCore.QObject):
return count
def get_verse_count(self, book, chapter):
"""
Return the number of verses in a chapter
``book``
The book containing the chapter
``chapter``
The chapter to get the verse count for
"""
log.debug(u'BibleDB.get_verse_count("%s", %s)', book, chapter)
count = self.session.query(Verse).join(Book)\
.filter(Book.name==book)\
@ -371,20 +413,10 @@ class BibleDB(QtCore.QObject):
else:
return count
def get_meta(self, key):
log.debug(u'get meta %s', key)
return self.session.query(BibleMeta).get(key)
def delete_meta(self, metakey):
biblemeta = self.get_meta(metakey)
try:
self.session.delete(biblemeta)
self.commit()
return True
except:
return False
def dump_bible(self):
"""
Utility debugging method to dump the contents of a bible
"""
log.debug(u'.........Dumping Bible Database')
log.debug('...............................Books ')
books = self.session.query(Book).all()

View File

@ -35,8 +35,7 @@ from openlp.core.lib import Receiver
from openlp.core.utils import AppLocation
from openlp.plugins.bibles.lib.common import BibleCommon, SearchResults, \
unescape
from openlp.plugins.bibles.lib.db import BibleDB
from openlp.plugins.bibles.lib.models import Book
from openlp.plugins.bibles.lib.db import BibleDB, Book
log = logging.getLogger(__name__)

View File

@ -29,12 +29,12 @@ from PyQt4 import QtCore
from openlp.core.lib import SettingsManager
from openlp.core.utils import AppLocation
from openlp.plugins.bibles.lib.db import BibleDB, Book, BibleMeta
from common import parse_reference
from opensong import OpenSongBible
from osis import OSISBible
from csvbible import CSVBible
from db import BibleDB
from http import HTTPBible
log = logging.getLogger(__name__)
@ -137,11 +137,13 @@ class BibleManager(object):
log.debug(u'Bible Name: "%s"', name)
self.db_cache[name] = bible
# look to see if lazy load bible exists and get create getter.
source = self.db_cache[name].get_meta(u'download source')
source = self.db_cache[name].get_object(BibleMeta,
u'download source')
if source:
download_name = \
self.db_cache[name].get_meta(u'download name').value
meta_proxy = self.db_cache[name].get_meta(u'proxy url')
download_name = self.db_cache[name].get_object(BibleMeta,
u'download name').value
meta_proxy = self.db_cache[name].get_object(BibleMeta,
u'proxy url')
web_bible = HTTPBible(self.parent, path=self.path,
file=filename, download_source=source.value,
download_name=download_name)
@ -196,7 +198,7 @@ class BibleManager(object):
u'name': book.name,
u'chapters': self.db_cache[bible].get_chapter_count(book.name)
}
for book in self.db_cache[bible].get_books()
for book in self.db_cache[bible].get_all_objects(Book, Book.id)
]
def get_chapter_count(self, bible, book):
@ -249,7 +251,7 @@ class BibleManager(object):
Returns the meta data for a given key
"""
log.debug(u'get_meta %s,%s', bible, key)
return self.db_cache[bible].get_meta(key)
return self.db_cache[bible].get_object(BibleMeta, key)
def exists(self, name):
"""

View File

@ -1,94 +0,0 @@
# -*- 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, Christian Richter, Maikel Stuivenberg, Martin #
# Thompson, Jon Tibble, Carsten Tinggaard #
# --------------------------------------------------------------------------- #
# This program is free software; you can redistribute it and/or modify it #
# under the terms of the GNU General Public License as published by the Free #
# Software Foundation; version 2 of the License. #
# #
# This program is distributed in the hope that it will be useful, but WITHOUT #
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
# more details. #
# #
# You should have received a copy of the GNU General Public License along #
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
from sqlalchemy import Column, Table, MetaData, ForeignKey, types, \
create_engine
from sqlalchemy.orm import mapper, relation, sessionmaker, scoped_session
from openlp.core.lib import BaseModel
class BibleMeta(BaseModel):
"""
Bible Meta Data
"""
pass
class Testament(BaseModel):
"""
Bible Testaments
"""
pass
class Book(BaseModel):
"""
Song model
"""
pass
class Verse(BaseModel):
"""
Topic model
"""
pass
def init_models(db_url):
engine = create_engine(db_url)
metadata.bind = engine
session = scoped_session(sessionmaker(autoflush=True, autocommit=False,
bind=engine))
return session
metadata = MetaData()
meta_table = Table(u'metadata', metadata,
Column(u'key', types.Unicode(255), primary_key=True, index=True),
Column(u'value', types.Unicode(255)),
)
testament_table = Table(u'testament', metadata,
Column(u'id', types.Integer, primary_key=True),
Column(u'name', types.Unicode(50)),
)
book_table = Table(u'book', metadata,
Column(u'id', types.Integer, primary_key=True),
Column(u'testament_id', types.Integer, ForeignKey(u'testament.id')),
Column(u'name', types.Unicode(50), index=True),
Column(u'abbreviation', types.Unicode(5), index=True),
)
verse_table = Table(u'verse', metadata,
Column(u'id', types.Integer, primary_key=True, index=True),
Column(u'book_id', types.Integer, ForeignKey(u'book.id'), index=True),
Column(u'chapter', types.Integer, index=True),
Column(u'verse', types.Integer, index=True),
Column(u'text', types.UnicodeText, index=True),
)
mapper(BibleMeta, meta_table)
mapper(Testament, testament_table,
properties={'books': relation(Book, backref='testament')})
mapper(Book, book_table,
properties={'verses': relation(Verse, backref='book')})
mapper(Verse, verse_table)

View File

@ -90,7 +90,7 @@ class OpenSongBible(BibleDB):
QtCore.QString('%s %s %s' % (
translate('BiblesPlugin.Opensong', 'Importing'), \
db_book.name, chapter.attrib[u'n'])))
self.commit()
self.session.commit()
except IOError:
log.exception(u'Loading bible from OpenSong file failed')
success = False

View File

@ -140,7 +140,7 @@ class OSISBible(BibleDB):
self.wizard.ImportProgressBar.setMaximum(260)
if last_chapter != chapter:
if last_chapter != 0:
self.commit()
self.session.commit()
self.wizard.incrementProgressBar(
u'Importing %s %s...' % \
(self.books[match.group(1)][0], chapter))
@ -169,7 +169,7 @@ class OSISBible(BibleDB):
verse_text = self.spaces_regex.sub(u' ', verse_text)
self.create_verse(db_book.id, chapter, verse, verse_text)
Receiver.send_message(u'openlp_process_events')
self.commit()
self.session.commit()
self.wizard.incrementProgressBar(u'Finishing import...')
if match_count == 0:
success = False

View File

@ -22,3 +22,8 @@
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
"""
The :mod:`custom` module provides the Custom plugin which allows custom,
themed, text based items to be displayed without having to misuse another item
type.
"""

View File

@ -26,8 +26,11 @@
import logging
from forms import EditCustomForm
from openlp.core.lib import Plugin, build_icon, PluginStatus, translate
from openlp.plugins.custom.lib import CustomManager, CustomMediaItem, CustomTab
from openlp.core.lib.db import Manager
from openlp.plugins.custom.lib import CustomMediaItem, CustomTab
from openlp.plugins.custom.lib.db import CustomSlide, init_schema
log = logging.getLogger(__name__)
@ -45,9 +48,9 @@ class CustomPlugin(Plugin):
def __init__(self, plugin_helpers):
Plugin.__init__(self, u'Custom', u'1.9.2', plugin_helpers)
self.weight = -5
self.custommanager = CustomManager()
self.custommanager = Manager(u'custom', init_schema)
self.edit_custom_form = EditCustomForm(self.custommanager)
self.icon = build_icon(u':/media/media_custom.png')
self.icon = build_icon(u':/plugins/plugin_custom.png')
self.status = PluginStatus.Active
def get_settings_tab(self):
@ -57,15 +60,6 @@ class CustomPlugin(Plugin):
# Create the CustomManagerItem object
return CustomMediaItem(self, self.icon, self.name)
def initialise(self):
log.info(u'Plugin Initialising')
Plugin.initialise(self)
self.insert_toolbox_item()
def finalise(self):
log.info(u'Plugin Finalise')
self.remove_toolbox_item()
def about(self):
about_text = translate('CustomPlugin',
'<b>Custom Plugin</b><br>This plugin '
@ -75,6 +69,7 @@ class CustomPlugin(Plugin):
return about_text
def can_delete_theme(self, theme):
if len(self.custommanager.get_customs_for_theme(theme)) == 0:
if not self.custommanager.get_all_objects_filtered(CustomSlide,
CustomSlide.theme_name == theme):
return True
return False
return False

View File

@ -29,7 +29,7 @@ from PyQt4 import QtCore, QtGui
from editcustomdialog import Ui_customEditDialog
from openlp.core.lib import SongXMLBuilder, SongXMLParser, Receiver, translate
from openlp.plugins.custom.lib.models import CustomSlide
from openlp.plugins.custom.lib.db import CustomSlide
log = logging.getLogger(__name__)
@ -116,7 +116,7 @@ class EditCustomForm(QtGui.QDialog, Ui_customEditDialog):
self.customSlide = CustomSlide()
self.initialise()
if id != 0:
self.customSlide = self.custommanager.get_custom(id)
self.customSlide = self.custommanager.get_object(CustomSlide, id)
self.TitleEdit.setText(self.customSlide.title)
self.CreditEdit.setText(self.customSlide.credits)
songXML = SongXMLParser(self.customSlide.text)
@ -166,8 +166,7 @@ class EditCustomForm(QtGui.QDialog, Ui_customEditDialog):
u'utf-8')
self.customSlide.theme_name = unicode(self.ThemeComboBox.currentText(),
u'utf-8')
self.custommanager.save_slide(self.customSlide)
return True
return self.custommanager.save_object(self.customSlide)
def onUpButtonPressed(self):
selectedRow = self.VerseListView.currentRow()

View File

@ -23,6 +23,5 @@
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
from manager import CustomManager
from mediaitem import CustomMediaItem
from customtab import CustomTab

View File

@ -1,32 +0,0 @@
# -*- 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, Christian Richter, Maikel Stuivenberg, Martin #
# Thompson, Jon Tibble, Carsten Tinggaard #
# --------------------------------------------------------------------------- #
# This program is free software; you can redistribute it and/or modify it #
# under the terms of the GNU General Public License as published by the Free #
# Software Foundation; version 2 of the License. #
# #
# This program is distributed in the hope that it will be useful, but WITHOUT #
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
# more details. #
# #
# You should have received a copy of the GNU General Public License along #
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
from openlp.core.lib import BaseModel
class CustomSlide(BaseModel):
"""
Custom Slide model
"""
pass

View File

@ -22,18 +22,40 @@
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
"""
The :mod:`db` module provides the database and schema that is the backend for
the Custom plugin
"""
from sqlalchemy import create_engine
from sqlalchemy.orm import scoped_session, sessionmaker, mapper
from sqlalchemy import Column, Table, types
from sqlalchemy.orm import mapper
from openlp.plugins.custom.lib.meta import metadata
from openlp.plugins.custom.lib.tables import *
from openlp.plugins.custom.lib.classes import *
from openlp.core.lib.db import BaseModel, init_db
class CustomSlide(BaseModel):
"""
CustomSlide model
"""
pass
def init_schema(url):
"""
Setup the custom database connection and initialise the database schema
``url``
The database to setup
"""
session, metadata = init_db(url)
custom_slide_table = Table(u'custom_slide', metadata,
Column(u'id', types.Integer(), primary_key=True),
Column(u'title', types.Unicode(255), nullable=False),
Column(u'text', types.UnicodeText, nullable=False),
Column(u'credits', types.UnicodeText),
Column(u'theme_name', types.Unicode(128))
)
def init_models(url):
engine = create_engine(url)
metadata.bind = engine
session = scoped_session(sessionmaker(autoflush=True, autocommit=False,
bind=engine))
mapper(CustomSlide, custom_slide_table)
metadata.create_all(checkfirst=True)
return session

View File

@ -1,117 +0,0 @@
# -*- 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, Christian Richter, Maikel Stuivenberg, Martin #
# Thompson, Jon Tibble, Carsten Tinggaard #
# --------------------------------------------------------------------------- #
# 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 logging
from PyQt4 import QtCore
from sqlalchemy.exceptions import InvalidRequestError
from openlp.core.utils import AppLocation
from openlp.plugins.custom.lib.models import init_models, metadata, CustomSlide
log = logging.getLogger(__name__)
class CustomManager(object):
"""
The Song Manager provides a central location for all database code. This
class takes care of connecting to the database and running all the queries.
"""
log.info(u'Custom manager loaded')
def __init__(self):
"""
Creates the connection to the database, and creates the tables if they
don't exist.
"""
log.debug(u'Custom Initialising')
settings = QtCore.QSettings()
settings.beginGroup(u'custom')
self.db_url = u''
db_type = unicode(
settings.value(u'db type', QtCore.QVariant(u'sqlite')).toString())
if db_type == u'sqlite':
self.db_url = u'sqlite:///%s/custom.sqlite' % \
AppLocation.get_section_data_path(u'custom')
else:
self.db_url = u'%s://%s:%s@%s/%s' % (db_type,
unicode(settings.value(u'db username').toString()),
unicode(settings.value(u'db password').toString()),
unicode(settings.value(u'db hostname').toString()),
unicode(settings.value(u'db database').toString()))
self.session = init_models(self.db_url)
metadata.create_all(checkfirst=True)
settings.endGroup()
log.debug(u'Custom Initialised')
def get_all_slides(self):
"""
Returns the details of a Custom Slide Show
"""
return self.session.query(CustomSlide).order_by(CustomSlide.title).all()
def save_slide(self, customslide):
"""
Saves a Custom slide show to the database
"""
log.debug(u'Custom Slide added')
try:
self.session.add(customslide)
self.session.commit()
log.debug(u'Custom Slide saved')
return True
except InvalidRequestError:
self.session.rollback()
log.exception(u'Custom Slide save failed')
return False
def get_custom(self, id=None):
"""
Returns the details of a Custom Slide
"""
if id is None:
return CustomSlide()
else:
return self.session.query(CustomSlide).get(id)
def delete_custom(self, id):
"""
Delete a Custom slide show
"""
if id != 0:
customslide = self.get_custom(id)
try:
self.session.delete(customslide)
self.session.commit()
return True
except InvalidRequestError:
self.session.rollback()
log.exception(u'Custom Slide deleton failed')
return False
else:
return True
def get_customs_for_theme(self, theme):
return self.session.query(
CustomSlide).filter(CustomSlide.theme_name == theme).all()

View File

@ -29,6 +29,7 @@ from PyQt4 import QtCore, QtGui
from openlp.core.lib import MediaManagerItem, SongXMLParser, BaseListWithDnD, \
Receiver, ItemCapabilities, translate, check_item_selected
from openlp.plugins.custom.lib.db import CustomSlide
log = logging.getLogger(__name__)
@ -72,7 +73,8 @@ class CustomMediaItem(MediaManagerItem):
MediaManagerItem.requiredIcons(self)
def initialise(self):
self.loadCustomListView(self.parent.custommanager.get_all_slides())
self.loadCustomListView(self.parent.custommanager.get_all_objects(
CustomSlide, CustomSlide.title))
#Called to redisplay the song list screen edith from a search
#or from the exit of the Song edit dialog. If remote editing is active
#Trigger it and clean up so it will not update again.
@ -84,10 +86,10 @@ class CustomMediaItem(MediaManagerItem):
def loadCustomListView(self, list):
self.ListView.clear()
for CustomSlide in list:
custom_name = QtGui.QListWidgetItem(CustomSlide.title)
for customSlide in list:
custom_name = QtGui.QListWidgetItem(customSlide.title)
custom_name.setData(
QtCore.Qt.UserRole, QtCore.QVariant(CustomSlide.id))
QtCore.Qt.UserRole, QtCore.QVariant(customSlide.id))
self.ListView.addItem(custom_name)
def onNewClick(self):
@ -106,7 +108,7 @@ class CustomMediaItem(MediaManagerItem):
type of display is required.
"""
fields = customid.split(u':')
valid = self.parent.custommanager.get_custom(fields[1])
valid = self.parent.custommanager.get_object(CustomSlide, fields[1])
if valid:
self.remoteCustom = fields[1]
self.remoteTriggered = fields[0]
@ -134,11 +136,14 @@ class CustomMediaItem(MediaManagerItem):
if check_item_selected(self.ListView,
translate('CustomPlugin.MediaItem',
'You must select an item to delete.')):
item = self.ListView.currentItem()
item_id = (item.data(QtCore.Qt.UserRole)).toInt()[0]
self.parent.custommanager.delete_custom(item_id)
row = self.ListView.row(item)
self.ListView.takeItem(row)
row_list = [item.row() for item in self.ListView.selectedIndexes()]
row_list.sort(reverse=True)
id_list = [(item.data(QtCore.Qt.UserRole)).toInt()[0]
for item in self.ListView.selectedIndexes()]
for id in id_list:
self.parent.custommanager.delete_custom(id)
for row in row_list:
self.ListView.takeItem(row)
def generateSlideData(self, service_item, item=None):
raw_slides = []
@ -158,7 +163,7 @@ class CustomMediaItem(MediaManagerItem):
service_item.add_capability(ItemCapabilities.AllowsEdit)
service_item.add_capability(ItemCapabilities.AllowsPreview)
service_item.add_capability(ItemCapabilities.AllowsLoop)
customSlide = self.parent.custommanager.get_custom(item_id)
customSlide = self.parent.custommanager.get_object(CustomSlide, item_id)
title = customSlide.title
credit = customSlide.credits
service_item.editId = item_id

View File

@ -1,38 +0,0 @@
# -*- 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, Christian Richter, Maikel Stuivenberg, Martin #
# Thompson, Jon Tibble, Carsten Tinggaard #
# --------------------------------------------------------------------------- #
# This program is free software; you can redistribute it and/or modify it #
# under the terms of the GNU General Public License as published by the Free #
# Software Foundation; version 2 of the License. #
# #
# This program is distributed in the hope that it will be useful, but WITHOUT #
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
# more details. #
# #
# You should have received a copy of the GNU General Public License along #
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
from sqlalchemy import MetaData
__all__ = ['session', 'metadata', 'engine']
# SQLAlchemy database engine. Updated by model.init_model()
engine = None
# SQLAlchemy session manager. Updated by model.init_model()
session = None
# Global metadata. If you have multiple databases with overlapping table
# names, you'll need a metadata for each database
metadata = MetaData()

View File

@ -1,37 +0,0 @@
# -*- 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, Christian Richter, Maikel Stuivenberg, Martin #
# Thompson, Jon Tibble, Carsten Tinggaard #
# --------------------------------------------------------------------------- #
# This program is free software; you can redistribute it and/or modify it #
# under the terms of the GNU General Public License as published by the Free #
# Software Foundation; version 2 of the License. #
# #
# This program is distributed in the hope that it will be useful, but WITHOUT #
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
# more details. #
# #
# You should have received a copy of the GNU General Public License along #
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
from sqlalchemy import Column, Table, types
from openlp.plugins.custom.lib.meta import metadata
# Definition of the "custom slide" table
custom_slide_table = Table(u'custom_slide', metadata,
Column(u'id', types.Integer(), primary_key=True),
Column(u'title', types.Unicode(255), nullable=False),
Column(u'text', types.UnicodeText, nullable=False),
Column(u'credits', types.UnicodeText),
Column(u'theme_name', types.Unicode(128))
)

View File

@ -22,3 +22,7 @@
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
"""
The :mod:`images` module provides the Images plugin. The Images plugin
provides the facility to display images from OpenLP.
"""

View File

@ -36,18 +36,9 @@ class ImagePlugin(Plugin):
def __init__(self, plugin_helpers):
Plugin.__init__(self, u'Images', u'1.9.2', plugin_helpers)
self.weight = -7
self.icon = build_icon(u':/media/media_image.png')
self.icon = build_icon(u':/plugins/plugin_images.png')
self.status = PluginStatus.Active
def initialise(self):
log.info(u'Plugin Initialising')
Plugin.initialise(self)
self.insert_toolbox_item()
def finalise(self):
log.info(u'Plugin Finalise')
self.remove_toolbox_item()
def get_settings_tab(self):
return ImageTab(self.name)
@ -64,4 +55,4 @@ class ImagePlugin(Plugin):
'an image is selected any songs which are rendered will use the '
'selected image from the background instead of the one provied by '
'the theme.<br>')
return about_text
return about_text

View File

@ -119,9 +119,10 @@ class ImageMediaItem(MediaManagerItem):
"""
if check_item_selected(self.ListView, translate('ImagePlugin.MediaItem',
'You must select an item to delete.')):
items = self.ListView.selectedIndexes()
for item in items:
text = self.ListView.item(item.row())
row_list = [item.row() for item in self.ListView.selectedIndexes()]
row_list.sort(reverse=True)
for row in row_list:
text = self.ListView.item(row)
if text:
try:
os.remove(os.path.join(self.servicePath,
@ -129,9 +130,9 @@ class ImageMediaItem(MediaManagerItem):
except OSError:
#if not present do not worry
pass
self.ListView.takeItem(item.row())
SettingsManager.set_list(self.settingsSection,
self.settingsSection, self.getFileList())
self.ListView.takeItem(row)
SettingsManager.set_list(self.settingsSection,
self.settingsSection, self.getFileList())
def loadList(self, list):
for file in list:
@ -169,17 +170,14 @@ class ImageMediaItem(MediaManagerItem):
return False
def onReplaceClick(self):
if not self.ListView.selectedIndexes():
QtGui.QMessageBox.information(self,
translate('ImagePlugin.MediaItem', 'No item selected'),
translate('ImagePlugin.MediaItem',
'You must select one item'))
items = self.ListView.selectedIndexes()
for item in items:
bitem = self.ListView.item(item.row())
filename = unicode(bitem.data(QtCore.Qt.UserRole).toString())
frame = QtGui.QImage(unicode(filename))
self.parent.maindisplay.addImageWithText(frame)
if check_item_selected(self.ListView,
translate('ImagePlugin.MediaItem',
'You must select an item to process.')):
item = self.buildServiceItem()
item.render()
self.parent.live_controller.displayManager. \
displayImage(item.get_rendered_frame(0)[u'display'])
def onPreviewClick(self):
MediaManagerItem.onPreviewClick(self)

View File

@ -22,3 +22,9 @@
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
"""
The :mod:`media` module provides the Media plugin which allows OpenLP to
display videos. The media supported depends not only on the Python support
but also extensively on the codecs installed on the underlying operating system
being picked up and usable by Python.
"""

View File

@ -29,7 +29,8 @@ import os
from PyQt4 import QtCore, QtGui
from openlp.core.lib import MediaManagerItem, BaseListWithDnD, build_icon, \
ItemCapabilities, SettingsManager, translate, check_item_selected
ItemCapabilities, SettingsManager, translate, check_item_selected, \
context_menu_action
log = logging.getLogger(__name__)
@ -73,13 +74,13 @@ class MediaMediaItem(MediaManagerItem):
self.hasNewIcon = False
self.hasEditIcon = False
# def addListViewToToolBar(self):
# MediaManagerItem.addListViewToToolBar(self)
# self.ListView.setContextMenuPolicy(QtCore.Qt.ActionsContextMenu)
# self.ListView.addAction(
# context_menu_action(self.ListView, u':/slides/slide_blank.png',
# translate('MediaPlugin.MediaItem', 'Replace Live Background'),
# self.onReplaceClick))
def addListViewToToolBar(self):
MediaManagerItem.addListViewToToolBar(self)
self.ListView.setContextMenuPolicy(QtCore.Qt.ActionsContextMenu)
self.ListView.addAction(
context_menu_action(self.ListView, u':/slides/slide_blank.png',
translate('MediaPlugin.MediaItem', 'Replace Live Background'),
self.onReplaceClick))
def addEndHeaderBar(self):
self.ImageWidget = QtGui.QWidget(self)
@ -92,24 +93,25 @@ class MediaMediaItem(MediaManagerItem):
self.ImageWidget.setSizePolicy(sizePolicy)
self.ImageWidget.setObjectName(u'ImageWidget')
#Replace backgrounds do not work at present so remove functionality.
# self.blankButton = self.Toolbar.addToolbarButton(
# u'Replace Background', u':/slides/slide_blank.png',
# translate('MediaPlugin.MediaItem', 'Replace Live Background'),
# self.onReplaceClick, False)
self.blankButton = self.Toolbar.addToolbarButton(
u'Replace Background', u':/slides/slide_blank.png',
translate('MediaPlugin.MediaItem', 'Replace Live Background'),
self.onReplaceClick, False)
# Add the song widget to the page layout
self.PageLayout.addWidget(self.ImageWidget)
# def onReplaceClick(self):
def onReplaceClick(self):
# if self.background:
# self.background = False
# Receiver.send_message(u'videodisplay_stop')
# else:
# self.background = True
# if not self.ListView.selectedIndexes():
# QtGui.QMessageBox.information(self,
# translate('MediaPlugin.MediaItem', 'No item selected'),
# translate('MediaPlugin.MediaItem',
# 'You must select one item'))
if check_item_selected(self.ListView,
translate('ImagePlugin.MediaItem',
'You must select an item to process.')):
item = self.ListView.currentItem()
filename = unicode(item.data(QtCore.Qt.UserRole).toString())
self.parent.live_controller.displayManager.displayVideo(filename)
# items = self.ListView.selectedIndexes()
# for item in items:
# bitem = self.ListView.item(item.row())
@ -143,9 +145,10 @@ class MediaMediaItem(MediaManagerItem):
"""
if check_item_selected(self.ListView, translate('MediaPlugin.MediaItem',
'You must select an item to delete.')):
item = self.ListView.currentItem()
row = self.ListView.row(item)
self.ListView.takeItem(row)
row_list = [item.row() for item in self.ListView.selectedIndexes()]
row_list.sort(reverse=True)
for row in row_list:
self.ListView.takeItem(row)
SettingsManager.set_list(self.settingsSection,
self.settingsSection, self.getFileList())

View File

@ -38,7 +38,7 @@ class MediaPlugin(Plugin):
def __init__(self, plugin_helpers):
Plugin.__init__(self, u'Media', u'1.9.2', plugin_helpers)
self.weight = -6
self.icon = build_icon(u':/media/media_video.png')
self.icon = build_icon(u':/plugins/plugin_media.png')
# passed with drag and drop messages
self.dnd_id = u'Media'
self.status = PluginStatus.Active
@ -67,15 +67,6 @@ class MediaPlugin(Plugin):
type = u''
return list, type
def initialise(self):
log.info(u'Plugin Initialising')
Plugin.initialise(self)
self.insert_toolbox_item()
def finalise(self):
log.info(u'Plugin Finalise')
self.remove_toolbox_item()
def get_media_manager_item(self):
# Create the MediaManagerItem object
return MediaMediaItem(self, self.icon, self.name)

View File

@ -22,3 +22,7 @@
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
"""
The :mod:`presentations` module provides the Presentations plugin which allows
OpenLP to show presentations from most popular presentation packages.
"""

View File

@ -41,10 +41,15 @@ from openlp.core.lib import resize_image
if os.name == u'nt':
from win32com.client import Dispatch
import pywintypes
else:
import uno
from com.sun.star.beans import PropertyValue
try:
import uno
from com.sun.star.beans import PropertyValue
uno_available = True
except ImportError:
uno_available = False
from PyQt4 import QtCore
from presentationcontroller import PresentationController, PresentationDocument
@ -78,9 +83,7 @@ class ImpressController(PresentationController):
if os.name == u'nt':
return self.get_com_servicemanager() is not None
else:
# If not windows, and we've got this far then probably
# installed else the import uno would likely have failed
return True
return uno_available
def start_process(self):
"""
@ -322,7 +325,10 @@ class ImpressDocument(PresentationDocument):
Returns true if screen is blank
"""
log.debug(u'is blank OpenOffice')
return self.control.isPaused()
if self.control:
return self.control.isPaused()
else:
return False
def stop_presentation(self):
log.debug(u'stop presentation OpenOffice')

View File

@ -180,18 +180,22 @@ class PresentationMediaItem(MediaManagerItem):
if check_item_selected(self.ListView,
translate('PresentationPlugin.MediaItem',
'You must select an item to delete.')):
item = self.ListView.currentItem()
row = self.ListView.row(item)
self.ListView.takeItem(row)
items = self.ListView.selectedIndexes()
row_list = [item.row() for item in items]
row_list.sort(reverse=True)
for item in items:
filepath = unicode(item.data(
QtCore.Qt.UserRole).toString())
#not sure of this has errors
#John please can you look at .
for cidx in self.controllers:
doc = self.controllers[cidx].add_doc(filepath)
doc.presentation_deleted()
doc.close_presentation()
for row in row_list:
self.ListView.takeItem(row)
SettingsManager.set_list(self.settingsSection,
self.settingsSection, self.getFileList())
filepath = unicode(item.data(QtCore.Qt.UserRole).toString())
#not sure of this has errors
#John please can you look at .
for cidx in self.controllers:
doc = self.controllers[cidx].add_doc(filepath)
doc.presentation_deleted()
doc.close_presentation()
def generateSlideData(self, service_item, item=None):
items = self.ListView.selectedIndexes()

View File

@ -27,7 +27,7 @@ import os
import logging
if os.name == u'nt':
from ctypes import *
from ctypes import cdll
from ctypes.wintypes import RECT
from presentationcontroller import PresentationController, PresentationDocument

View File

@ -40,7 +40,7 @@ class PresentationPlugin(Plugin):
self.controllers = {}
Plugin.__init__(self, u'Presentations', u'1.9.2', plugin_helpers)
self.weight = -8
self.icon = build_icon(u':/media/media_presentation.png')
self.icon = build_icon(u':/plugins/plugin_presentations.png')
self.status = PluginStatus.Active
def get_settings_tab(self):
@ -64,7 +64,7 @@ class PresentationPlugin(Plugin):
controller = self.controllers[key]
if controller.enabled:
controller.kill()
self.remove_toolbox_item()
Plugin.finalise(self)
def get_media_manager_item(self):
"""

View File

@ -22,3 +22,7 @@
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
"""
The :mod:`remotes` plugin allows OpenLP to be controlled from another machine
over a network connection.
"""

View File

@ -25,7 +25,7 @@
import logging
from openlp.core.lib import Plugin, translate
from openlp.core.lib import Plugin, translate, build_icon
from openlp.plugins.remotes.lib import RemoteTab, HttpServer
log = logging.getLogger(__name__)
@ -38,6 +38,7 @@ class RemotesPlugin(Plugin):
remotes constructor
"""
Plugin.__init__(self, u'Remotes', u'1.9.2', plugin_helpers)
self.icon = build_icon(u':/plugins/plugin_remote.png')
self.weight = -1
self.server = None
@ -55,7 +56,7 @@ class RemotesPlugin(Plugin):
Tidy up and close down the http server
"""
log.debug(u'finalise')
self.remove_toolbox_item()
Plugin.finalise(self)
if self.server:
self.server.close()
@ -74,4 +75,4 @@ class RemotesPlugin(Plugin):
'provides the ability to send messages to a running version of '
'openlp on a different computer via a web browser or other app<br>'
'The Primary use for this would be to send alerts from a creche')
return about_text
return about_text

View File

@ -22,3 +22,7 @@
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
"""
The :mod:`songs` module provides the Songs plugin. The Songs plugin provides
the main lyric projection function of OpenLP.
"""

View File

@ -24,6 +24,7 @@
###############################################################################
from PyQt4 import QtCore, QtGui
from openlp.core.lib import translate
class Ui_AuthorsDialog(object):

View File

@ -28,7 +28,6 @@ from PyQt4 import QtGui, QtCore
from openlp.core.lib import translate
from openlp.plugins.songs.forms.authorsdialog import Ui_AuthorsDialog
class AuthorsForm(QtGui.QDialog, Ui_AuthorsDialog):
"""
Class to control the Maintenance of Authors Dialog

View File

@ -24,9 +24,8 @@
###############################################################################
from PyQt4 import QtCore, QtGui
from openlp.core.lib import translate
from openlp.core.lib import build_icon
from openlp.core.lib import build_icon, translate
class Ui_EditSongDialog(object):
def setupUi(self, EditSongDialog):

View File

@ -31,7 +31,7 @@ from PyQt4 import QtCore, QtGui
from openlp.core.lib import SongXMLBuilder, SongXMLParser, Receiver, translate
from openlp.plugins.songs.forms import EditVerseForm
from openlp.plugins.songs.lib import VerseType
from openlp.plugins.songs.lib.models import Song, Author, Topic, Book
from openlp.plugins.songs.lib.db import Book, Song, Author, Topic
from editsongdialog import Ui_EditSongDialog
log = logging.getLogger(__name__)
@ -118,7 +118,7 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
self.TopicRemoveButton.setEnabled(False)
def loadAuthors(self):
authors = self.songmanager.get_authors()
authors = self.songmanager.get_all_objects(Author, Author.display_name)
self.AuthorsSelectionComboItem.clear()
self.AuthorsSelectionComboItem.addItem(u'')
for author in authors:
@ -128,7 +128,7 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
row, QtCore.QVariant(author.id))
def loadTopics(self):
topics = self.songmanager.get_topics()
topics = self.songmanager.get_all_objects(Topic, Topic.name)
self.SongTopicCombo.clear()
self.SongTopicCombo.addItem(u'')
for topic in topics:
@ -137,7 +137,7 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
self.SongTopicCombo.setItemData(row, QtCore.QVariant(topic.id))
def loadBooks(self):
books = self.songmanager.get_books()
books = self.songmanager.get_all_objects(Book, Book.name)
self.SongbookCombo.clear()
self.SongbookCombo.addItem(u'')
for book in books:
@ -178,11 +178,12 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
self.loadAuthors()
self.loadTopics()
self.loadBooks()
self.song = self.songmanager.get_song(id)
self.song = self.songmanager.get_object(Song, id)
self.TitleEditItem.setText(self.song.title)
title = self.song.search_title.split(u'@')
if self.song.song_book_id != 0:
book_name = self.songmanager.get_book(self.song.song_book_id)
book_name = self.songmanager.get_object(Book,
self.song.song_book_id)
id = self.SongbookCombo.findText(
unicode(book_name.name), QtCore.Qt.MatchExactly)
if id == -1:
@ -289,7 +290,7 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
QtGui.QMessageBox.Yes) == QtGui.QMessageBox.Yes:
author = Author.populate(first_name=text.rsplit(u' ', 1)[0],
last_name=text.rsplit(u' ', 1)[1], display_name=text)
self.songmanager.save_author(author)
self.songmanager.save_object(author)
self.song.authors.append(author)
author_item = QtGui.QListWidgetItem(
unicode(author.display_name))
@ -302,7 +303,7 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
return
elif item > 0:
item_id = (self.AuthorsSelectionComboItem.itemData(item)).toInt()[0]
author = self.songmanager.get_author(item_id)
author = self.songmanager.get_object(Author, item_id)
self.song.authors.append(author)
author_item = QtGui.QListWidgetItem(unicode(author.display_name))
author_item.setData(QtCore.Qt.UserRole, QtCore.QVariant(author.id))
@ -325,7 +326,7 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
self.AuthorRemoveButton.setEnabled(False)
item = self.AuthorsListView.currentItem()
author_id = (item.data(QtCore.Qt.UserRole)).toInt()[0]
author = self.songmanager.get_author(author_id)
author = self.songmanager.get_object(Author, author_id)
self.song.authors.remove(author)
row = self.AuthorsListView.row(item)
self.AuthorsListView.takeItem(row)
@ -341,7 +342,7 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
QtGui.QMessageBox.Yes | QtGui.QMessageBox.No,
QtGui.QMessageBox.Yes) == QtGui.QMessageBox.Yes:
topic = Topic.populate(name=text)
self.songmanager.save_topic(topic)
self.songmanager.save_object(topic)
self.song.topics.append(topic)
topic_item = QtGui.QListWidgetItem(unicode(topic.name))
topic_item.setData(QtCore.Qt.UserRole,
@ -353,7 +354,7 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
return
elif item > 0:
item_id = (self.SongTopicCombo.itemData(item)).toInt()[0]
topic = self.songmanager.get_topic(item_id)
topic = self.songmanager.get_object(Topic, item_id)
self.song.topics.append(topic)
topic_item = QtGui.QListWidgetItem(unicode(topic.name))
topic_item.setData(QtCore.Qt.UserRole, QtCore.QVariant(topic.id))
@ -375,7 +376,7 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
self.TopicRemoveButton.setEnabled(False)
item = self.TopicsListView.currentItem()
topic_id = (item.data(QtCore.Qt.UserRole)).toInt()[0]
topic = self.songmanager.get_topic(topic_id)
topic = self.songmanager.get_object(Topic, topic_id)
self.song.topics.remove(topic)
row = self.TopicsListView.row(item)
self.TopicsListView.takeItem(row)
@ -391,12 +392,12 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
QtGui.QMessageBox.Yes | QtGui.QMessageBox.No,
QtGui.QMessageBox.Yes) == QtGui.QMessageBox.Yes:
book = Book.populate(name=text)
self.songmanager.save_book(book)
self.songmanager.save_object(book)
self.song.book = book
self.loadBooks()
else:
return
elif item > 1:
elif item >= 1:
item = int(self.SongbookCombo.currentIndex())
self.song.song_book_id = \
(self.SongbookCombo.itemData(item)).toInt()[0]
@ -630,7 +631,7 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
if self._validate_song():
self.processLyrics()
self.processTitle()
self.songmanager.save_song(self.song)
self.songmanager.save_object(self.song)
return True
return False

View File

@ -24,6 +24,7 @@
###############################################################################
from PyQt4 import QtCore, QtGui
from openlp.core.lib import translate
class Ui_SongBookDialog(object):

View File

@ -28,7 +28,6 @@ from PyQt4 import QtGui
from openlp.core.lib import translate
from openlp.plugins.songs.forms.songbookdialog import Ui_SongBookDialog
class SongBookForm(QtGui.QDialog, Ui_SongBookDialog):
"""
Class documentation goes here.

View File

@ -30,7 +30,7 @@ from PyQt4 import QtCore, QtGui
from songimportwizard import Ui_SongImportWizard
from openlp.core.lib import Receiver, SettingsManager, translate
#from openlp.core.utils import AppLocation
from openlp.plugins.songs.lib.manager import SongFormat
from openlp.plugins.songs.lib import SongFormat
log = logging.getLogger(__name__)

View File

@ -25,12 +25,10 @@
from PyQt4 import QtGui, QtCore
from openlp.plugins.songs.lib.classes import Author, Book, Topic
from songmaintenancedialog import Ui_SongMaintenanceDialog
from authorsform import AuthorsForm
from topicsform import TopicsForm
from songbookform import SongBookForm
from openlp.core.lib import translate
from openlp.plugins.songs.forms import AuthorsForm, TopicsForm, SongBookForm
from openlp.plugins.songs.lib.db import Author, Book, Topic
from songmaintenancedialog import Ui_SongMaintenanceDialog
class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog):
"""
@ -81,17 +79,17 @@ class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog):
else:
return -1
def _deleteItem(self, list_widget, get_func, del_func, reset_func,
dlg_title, del_text, err_text, sel_text):
def _deleteItem(self, item_class, list_widget, reset_func, dlg_title,
del_text, err_text, sel_text):
item_id = self._getCurrentItemId(list_widget)
if item_id != -1:
item = get_func(item_id)
item = self.songmanager.get_object(item_class, item_id)
if item and len(item.songs) == 0:
if QtGui.QMessageBox.warning(self, dlg_title, del_text,
QtGui.QMessageBox.StandardButtons(
QtGui.QMessageBox.No | QtGui.QMessageBox.Yes)
) == QtGui.QMessageBox.Yes:
del_func(item.id)
self.songmanager.delete_object(item_class, item.id)
reset_func()
else:
QtGui.QMessageBox.critical(self, dlg_title, err_text)
@ -100,7 +98,7 @@ class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog):
def resetAuthors(self):
self.AuthorsListWidget.clear()
authors = self.songmanager.get_authors()
authors = self.songmanager.get_all_objects(Author, Author.display_name)
for author in authors:
if author.display_name:
author_name = QtGui.QListWidgetItem(author.display_name)
@ -112,7 +110,7 @@ class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog):
def resetTopics(self):
self.TopicsListWidget.clear()
topics = self.songmanager.get_topics()
topics = self.songmanager.get_all_objects(Topic, Topic.name)
for topic in topics:
topic_name = QtGui.QListWidgetItem(topic.name)
topic_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(topic.id))
@ -120,7 +118,7 @@ class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog):
def resetBooks(self):
self.BooksListWidget.clear()
books = self.songmanager.get_books()
books = self.songmanager.get_all_objects(Book, Book.name)
for book in books:
book_name = QtGui.QListWidgetItem(book.name)
book_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(book.id))
@ -133,7 +131,7 @@ class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog):
first_name=unicode(self.authorform.FirstNameEdit.text()),
last_name=unicode(self.authorform.LastNameEdit.text()),
display_name=unicode(self.authorform.DisplayEdit.text()))
if self.songmanager.save_author(author):
if self.songmanager.save_object(author):
self.resetAuthors()
else:
QtGui.QMessageBox.critical(
@ -145,7 +143,7 @@ class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog):
def onTopicAddButtonClick(self):
if self.topicform.exec_():
topic = Topic.populate(name=unicode(self.topicform.NameEdit.text()))
if self.songmanager.save_topic(topic):
if self.songmanager.save_object(topic):
self.resetTopics()
else:
QtGui.QMessageBox.critical(
@ -159,7 +157,7 @@ class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog):
book = Book.populate(
name=unicode(self.bookform.NameEdit.text()),
publisher=unicode(self.bookform.PublisherEdit.text()))
if self.songmanager.save_book(book):
if self.songmanager.save_object(book):
self.resetBooks()
else:
QtGui.QMessageBox.critical(
@ -171,7 +169,7 @@ class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog):
def onAuthorEditButtonClick(self):
author_id = self._getCurrentItemId(self.AuthorsListWidget)
if author_id != -1:
author = self.songmanager.get_author(author_id)
author = self.songmanager.get_object(Author, author_id)
# Just make sure none of the fields is None
if author.first_name is None:
author.first_name = u''
@ -189,7 +187,7 @@ class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog):
author.last_name = unicode(self.authorform.LastNameEdit.text())
author.display_name = unicode(
self.authorform.DisplayEdit.text())
if self.songmanager.save_author(author):
if self.songmanager.save_object(author):
self.resetAuthors()
else:
QtGui.QMessageBox.critical(
@ -201,11 +199,11 @@ class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog):
def onTopicEditButtonClick(self):
topic_id = self._getCurrentItemId(self.TopicsListWidget)
if topic_id != -1:
topic = self.songmanager.get_topic(topic_id)
topic = self.songmanager.get_object(Topic, topic_id)
self.topicform.NameEdit.setText(topic.name)
if self.topicform.exec_(False):
topic.name = unicode(self.topicform.NameEdit.text())
if self.songmanager.save_topic(topic):
if self.songmanager.save_object(topic):
self.resetTopics()
else:
QtGui.QMessageBox.critical(
@ -217,13 +215,13 @@ class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog):
def onBookEditButtonClick(self):
book_id = self._getCurrentItemId(self.BooksListWidget)
if book_id != -1:
book = self.songmanager.get_book(book_id)
book = self.songmanager.get_object(Book, book_id)
self.bookform.NameEdit.setText(book.name)
self.bookform.PublisherEdit.setText(book.publisher)
if self.bookform.exec_(False):
book.name = unicode(self.bookform.NameEdit.text())
book.publisher = unicode(self.bookform.PublisherEdit.text())
if self.songmanager.save_book(book):
if self.songmanager.save_object(book):
self.resetBooks()
else:
QtGui.QMessageBox.critical(
@ -236,11 +234,9 @@ class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog):
"""
Delete the author if the author is not attached to any songs
"""
self._deleteItem(
self.AuthorsListWidget, self.songmanager.get_author,
self.songmanager.delete_author, self.resetAuthors,
self._deleteItem(Author, self.AuthorsListWidget, self.resetAuthors,
translate('SongsPlugin.SongMaintenanceForm', 'Delete Author'),
translate('SongsPlugin.SongMaintenanceForm',
translate('SongsPlugin.SongMaintenanceForm',
'Are you sure you want to delete the selected author?'),
translate('SongsPlugin.SongMaintenanceForm',
'This author can\'t be deleted, they are currently '
@ -252,13 +248,11 @@ class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog):
"""
Delete the Book is the Book is not attached to any songs
"""
self._deleteItem(
self.TopicsListWidget, self.songmanager.get_topic,
self.songmanager.delete_topic, self.resetTopics,
self._deleteItem(Topic, self.TopicsListWidget, self.resetTopics,
translate('SongsPlugin.SongMaintenanceForm', 'Delete Topic'),
translate('SongsPlugin.SongMaintenanceForm',
translate('SongsPlugin.SongMaintenanceForm',
'Are you sure you want to delete the selected topic?'),
translate('SongsPlugin.SongMaintenanceForm',
translate('SongsPlugin.SongMaintenanceForm',
'This topic can\'t be deleted, it is currently '
'assigned to at least one song.'),
translate('SongsPlugin.SongMaintenanceForm',
@ -268,13 +262,11 @@ class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog):
"""
Delete the Book is the Book is not attached to any songs
"""
self._deleteItem(
self.BooksListWidget, self.songmanager.get_book,
self.songmanager.delete_book, self.resetBooks,
self._deleteItem(Book, self.BooksListWidget, self.resetBooks,
translate('SongsPlugin.SongMaintenanceForm', 'Delete Book'),
translate('SongsPlugin.SongMaintenanceForm',
'Are you sure you want to delete the selected book?'),
translate('SongsPlugin.SongMaintenanceForm',
translate('SongsPlugin.SongMaintenanceForm',
'This book can\'t be deleted, it is currently '
'assigned to at least one song.'),
translate('SongsPlugin.SongMaintenanceForm', 'No book selected!'))
translate('SongsPlugin.SongMaintenanceForm', u'No book selected!'))

View File

@ -24,6 +24,7 @@
###############################################################################
from PyQt4 import QtCore, QtGui
from openlp.core.lib import translate
class Ui_TopicsDialog(object):

View File

@ -28,7 +28,6 @@ from PyQt4 import QtGui
from openlp.core.lib import translate
from openlp.plugins.songs.forms.topicsdialog import Ui_TopicsDialog
class TopicsForm(QtGui.QDialog, Ui_TopicsDialog):
"""
Class documentation goes here.

View File

@ -25,6 +25,52 @@
from openlp.core.lib import translate
#from openlp.plugins.songs.lib import OpenLyricsSong, OpenSongSong, CCLISong, \
# CSVSong
class SongFormat(object):
"""
This is a special enumeration class that holds the various types of songs,
plus a few helper functions to facilitate generic handling of song types
for importing.
"""
Unknown = -1
OpenLyrics = 0
OpenSong = 1
CCLI = 2
CSV = 3
@staticmethod
def get_class(id):
"""
Return the appropriate imeplementation class.
``id``
The song format.
"""
# if id == SongFormat.OpenLyrics:
# return OpenLyricsSong
# elif id == SongFormat.OpenSong:
# return OpenSongSong
# elif id == SongFormat.CCLI:
# return CCLISong
# elif id == SongFormat.CSV:
# return CSVSong
# else:
return None
@staticmethod
def list():
"""
Return a list of the supported song formats.
"""
return [
SongFormat.OpenLyrics,
SongFormat.OpenSong,
SongFormat.CCLI,
SongFormat.CSV
]
class VerseType(object):
"""
VerseType provides an enumeration for the tags that may be associated
@ -91,7 +137,6 @@ class VerseType(object):
unicode(VerseType.to_string(VerseType.Other)).lower():
return VerseType.Other
from manager import SongManager
from songstab import SongsTab
from mediaitem import SongMediaItem
from songimport import SongImport

View File

@ -1,52 +0,0 @@
# -*- 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, Christian Richter, Maikel Stuivenberg, Martin #
# Thompson, Jon Tibble, Carsten Tinggaard #
# --------------------------------------------------------------------------- #
# This program is free software; you can redistribute it and/or modify it #
# under the terms of the GNU General Public License as published by the Free #
# Software Foundation; version 2 of the License. #
# #
# This program is distributed in the hope that it will be useful, but WITHOUT #
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
# more details. #
# #
# You should have received a copy of the GNU General Public License along #
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
from openlp.core.lib import BaseModel
class Author(BaseModel):
"""
Author model
"""
pass
class Book(BaseModel):
"""
Book model
"""
def __repr__(self):
return u'<Book id="%s" name="%s" publisher="%s" />' % (
str(self.id), self.name, self.publisher)
class Song(BaseModel):
"""
Song model
"""
pass
class Topic(BaseModel):
"""
Topic model
"""
pass

View File

@ -0,0 +1,151 @@
# -*- 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, Christian Richter, Maikel Stuivenberg, Martin #
# Thompson, Jon Tibble, Carsten Tinggaard #
# --------------------------------------------------------------------------- #
# This program is free software; you can redistribute it and/or modify it #
# under the terms of the GNU General Public License as published by the Free #
# Software Foundation; version 2 of the License. #
# #
# This program is distributed in the hope that it will be useful, but WITHOUT #
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
# more details. #
# #
# You should have received a copy of the GNU General Public License along #
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
"""
The :mod:`db` module provides the database and schema that is the backend for
the Songs plugin
"""
from sqlalchemy import Column, ForeignKey, Index, Table, types
from sqlalchemy.orm import mapper, relation
from openlp.core.lib.db import BaseModel, init_db
class Author(BaseModel):
"""
Author model
"""
pass
class Book(BaseModel):
"""
Book model
"""
def __repr__(self):
return u'<Book id="%s" name="%s" publisher="%s" />' % (
str(self.id), self.name, self.publisher)
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
``url``
The database to setup
"""
session, metadata = init_db(url, auto_flush=False)
# Definition of the "authors" table
authors_table = Table(u'authors', metadata,
Column(u'id', types.Integer, primary_key=True),
Column(u'first_name', types.Unicode(128)),
Column(u'last_name', types.Unicode(128)),
Column(u'display_name', types.Unicode(255), nullable=False)
)
# Definition of the "song_books" table
song_books_table = Table(u'song_books', metadata,
Column(u'id', types.Integer, primary_key=True),
Column(u'name', types.Unicode(128), nullable=False),
Column(u'publisher', types.Unicode(128))
)
# Definition of the "songs" table
songs_table = Table(u'songs', metadata,
Column(u'id', types.Integer, primary_key=True),
Column(u'song_book_id', types.Integer,
ForeignKey(u'song_books.id'), default=0),
Column(u'title', types.Unicode(255), nullable=False),
Column(u'lyrics', types.UnicodeText, nullable=False),
Column(u'verse_order', types.Unicode(128)),
Column(u'copyright', types.Unicode(255)),
Column(u'comments', types.UnicodeText),
Column(u'ccli_number', types.Unicode(64)),
Column(u'song_number', types.Unicode(64)),
Column(u'theme_name', types.Unicode(128)),
Column(u'search_title', types.Unicode(255), index=True, nullable=False),
Column(u'search_lyrics', types.UnicodeText, index=True, nullable=False)
)
# Definition of the "topics" table
topics_table = Table(u'topics', metadata,
Column(u'id', types.Integer, primary_key=True),
Column(u'name', types.Unicode(128), nullable=False)
)
# Definition of the "authors_songs" table
authors_songs_table = Table(u'authors_songs', metadata,
Column(u'author_id', types.Integer,
ForeignKey(u'authors.id'), primary_key=True),
Column(u'song_id', types.Integer,
ForeignKey(u'songs.id'), primary_key=True)
)
# Definition of the "songs_topics" table
songs_topics_table = Table(u'songs_topics', metadata,
Column(u'song_id', types.Integer,
ForeignKey(u'songs.id'), primary_key=True),
Column(u'topic_id', types.Integer,
ForeignKey(u'topics.id'), primary_key=True)
)
# Define table indexes
Index(u'authors_id', authors_table.c.id)
Index(u'authors_display_name_id', authors_table.c.display_name,
authors_table.c.id)
Index(u'song_books_id', song_books_table.c.id)
Index(u'songs_id', songs_table.c.id)
Index(u'topics_id', topics_table.c.id)
Index(u'authors_songs_author', authors_songs_table.c.author_id,
authors_songs_table.c.song_id)
Index(u'authors_songs_song', authors_songs_table.c.song_id,
authors_songs_table.c.author_id)
Index(u'topics_song_topic', songs_topics_table.c.topic_id,
songs_topics_table.c.song_id)
Index(u'topics_song_song', songs_topics_table.c.song_id,
songs_topics_table.c.topic_id)
mapper(Author, authors_table)
mapper(Book, song_books_table)
mapper(Song, songs_table,
properties={'authors': relation(Author, backref='songs',
secondary=authors_songs_table),
'book': relation(Book, backref='songs'),
'topics': relation(Topic, backref='songs',
secondary=songs_topics_table)})
mapper(Topic, topics_table)
metadata.create_all(checkfirst=True)
return session

View File

@ -1,318 +0,0 @@
# -*- 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, Christian Richter, Maikel Stuivenberg, Martin #
# Thompson, Jon Tibble, Carsten Tinggaard #
# --------------------------------------------------------------------------- #
# 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 logging
from PyQt4 import QtCore
from sqlalchemy.exceptions import InvalidRequestError
from openlp.core.utils import AppLocation
from openlp.plugins.songs.lib.models import init_models, metadata, Song, \
Author, Topic, Book
#from openlp.plugins.songs.lib import OpenLyricsSong, OpenSongSong, CCLISong, \
# CSVSong
log = logging.getLogger(__name__)
class SongFormat(object):
"""
This is a special enumeration class that holds the various types of songs,
plus a few helper functions to facilitate generic handling of song types
for importing.
"""
Unknown = -1
OpenLyrics = 0
OpenSong = 1
CCLI = 2
CSV = 3
@staticmethod
def get_class(id):
"""
Return the appropriate imeplementation class.
``id``
The song format.
"""
# if id == SongFormat.OpenLyrics:
# return OpenLyricsSong
# elif id == SongFormat.OpenSong:
# return OpenSongSong
# elif id == SongFormat.CCLI:
# return CCLISong
# elif id == SongFormat.CSV:
# return CSVSong
# else:
return None
@staticmethod
def list():
"""
Return a list of the supported song formats.
"""
return [
SongFormat.OpenLyrics,
SongFormat.OpenSong,
SongFormat.CCLI,
SongFormat.CSV
]
class SongManager(object):
"""
The Song Manager provides a central location for all database code. This
class takes care of connecting to the database and running all the queries.
"""
log.info(u'Song manager loaded')
def __init__(self):
"""
Creates the connection to the database, and creates the tables if they
don't exist.
"""
log.debug(u'Song Initialising')
settings = QtCore.QSettings()
settings.beginGroup(u'songs')
self.db_url = u''
db_type = unicode(settings.value(u'db type',
QtCore.QVariant(u'sqlite')).toString())
if db_type == u'sqlite':
self.db_url = u'sqlite:///%s/songs.sqlite' % \
AppLocation.get_section_data_path(u'songs')
else:
self.db_url = u'%s://%s:%s@%s/%s' % (db_type,
unicode(settings.value(
u'db username', QtCore.QVariant(u'')).toString()),
unicode(settings.value(
u'db password', QtCore.QVariant(u'')).toString()),
unicode(settings.value(
u'db hostname', QtCore.QVariant(u'')).toString()),
unicode(settings.value(
u'db database', QtCore.QVariant(u'')).toString()))
self.session = init_models(self.db_url)
metadata.create_all(checkfirst=True)
settings.endGroup()
log.debug(u'Song Initialised')
def get_songs(self):
"""
Returns the details of a song
"""
return self.session.query(Song).order_by(Song.title).all()
def search_song_title(self, keywords):
"""
Searches the song title for keywords.
"""
return self.session.query(Song).filter(
Song.search_title.like(u'%' + keywords + u'%')).order_by(
Song.search_title.asc()).all()
def search_song_lyrics(self, keywords):
"""
Searches the song lyrics for keywords.
"""
return self.session.query(Song).filter(
Song.search_lyrics.like(u'%' + keywords + u'%')).order_by(
Song.search_lyrics.asc()).all()
def get_song_from_author(self, keywords):
"""
Searches the song authors for keywords.
"""
return self.session.query(Author).filter(Author.display_name.like(
u'%' + keywords + u'%')).order_by(Author.display_name.asc()).all()
def get_song(self, id=None):
"""
Returns the details of a song
"""
if id is None:
return Song()
else:
return self.session.query(Song).get(id)
def save_song(self, song):
"""
Saves a song to the database
"""
try:
self.session.add(song)
self.session.commit()
return True
except InvalidRequestError:
log.exception(u'Could not save song to song database')
self.session.rollback()
return False
def delete_song(self, songid):
song = self.get_song(songid)
try:
self.session.delete(song)
self.session.commit()
return True
except InvalidRequestError:
self.session.rollback()
log.exception(u'Could not delete song from song database')
return False
def get_authors(self):
"""
Returns a list of all the authors
"""
return self.session.query(Author).order_by(Author.display_name).all()
def get_author(self, id):
"""
Details of the Author
"""
return self.session.query(Author).get(id)
def get_author_by_name(self, name):
"""
Get author by display name
"""
return self.session.query(Author).filter_by(display_name=name).first()
def save_author(self, author):
"""
Save the Author and refresh the cache
"""
try:
self.session.add(author)
self.session.commit()
return True
except InvalidRequestError:
self.session.rollback()
log.exception(u'Could not save author to song database')
return False
def delete_author(self, authorid):
"""
Delete the author
"""
author = self.get_author(authorid)
try:
self.session.delete(author)
self.session.commit()
return True
except InvalidRequestError:
self.session.rollback()
log.exception(u'Could not delete author from song database')
return False
def get_topics(self):
"""
Returns a list of all the topics
"""
return self.session.query(Topic).order_by(Topic.name).all()
def get_topic(self, id):
"""
Details of the Topic
"""
return self.session.query(Topic).get(id)
def get_topic_by_name(self, name):
"""
Get topic by name
"""
return self.session.query(Topic).filter_by(name=name).first()
def save_topic(self, topic):
"""
Save the Topic
"""
try:
self.session.add(topic)
self.session.commit()
return True
except InvalidRequestError:
self.session.rollback()
log.exception(u'Could not save topic to song database')
return False
def delete_topic(self, topicid):
"""
Delete the topic
"""
topic = self.get_topic(topicid)
try:
self.session.delete(topic)
self.session.commit()
return True
except InvalidRequestError:
self.session.rollback()
log.exception(u'Could not delete topic from song database')
return False
def get_books(self):
"""
Returns a list of all the Books
"""
return self.session.query(Book).order_by(Book.name).all()
def get_book(self, id):
"""
Details of the Books
"""
return self.session.query(Book).get(id)
def get_book_by_name(self, name):
"""
Get book by name
"""
return self.session.query(Book).filter_by(name=name).first()
def save_book(self, book):
"""
Save the Book
"""
try:
self.session.add(book)
self.session.commit()
return True
except InvalidRequestError:
self.session.rollback()
log.exception(u'Could not save book to song database')
return False
def delete_book(self, bookid):
"""
Delete the Book
"""
book = self.get_book(bookid)
try:
self.session.delete(book)
self.session.commit()
return True
except InvalidRequestError:
self.session.rollback()
log.exception(u'Could not delete book from song database')
return False
def get_songs_for_theme(self, theme):
return self.session.query(Song).filter(Song.theme_name == theme).all()

View File

@ -31,6 +31,7 @@ from openlp.core.lib import MediaManagerItem, SongXMLParser, \
BaseListWithDnD, Receiver, ItemCapabilities, translate, check_item_selected
from openlp.plugins.songs.forms import EditSongForm, SongMaintenanceForm, \
ImportWizardForm
from openlp.plugins.songs.lib.db import Song
log = logging.getLogger(__name__)
@ -164,18 +165,21 @@ class SongMediaItem(MediaManagerItem):
search_type = self.SearchTypeComboBox.currentIndex()
if search_type == 0:
log.debug(u'Titles Search')
search_results = self.parent.manager.search_song_title(
search_keywords)
search_results = self.parent.manager.get_all_objects_filtered(Song,
Song.search_title.like(u'%' + search_keywords + u'%'),
Song.search_title.asc())
self.displayResultsSong(search_results)
elif search_type == 1:
log.debug(u'Lyrics Search')
search_results = self.parent.manager.search_song_lyrics(
search_keywords)
search_results = self.parent.manager.get_all_objects_filtered(Song,
Song.search_lyrics.like(u'%' + search_keywords + u'%'),
Song.search_lyrics.asc())
self.displayResultsSong(search_results)
elif search_type == 2:
log.debug(u'Authors Search')
search_results = self.parent.manager.get_song_from_author(
search_keywords)
search_results = self.parent.manager.get_all_objects_filtered(
Author, Author.display_name.like(u'%' + search_keywords + u'%'),
Author.display_name.asc())
self.displayResultsAuthor(search_results)
#Called to redisplay the song list screen edith from a search
#or from the exit of the Song edit dialog. If remote editing is active
@ -268,7 +272,7 @@ class SongMediaItem(MediaManagerItem):
type of display is required.
"""
fields = songid.split(u':')
valid = self.parent.manager.get_song(fields[1])
valid = self.parent.manager.get_object(Song, fields[1])
if valid:
self.remoteSong = fields[1]
self.remoteTriggered = fields[0]
@ -310,7 +314,7 @@ class SongMediaItem(MediaManagerItem):
return
for item in items:
item_id = (item.data(QtCore.Qt.UserRole)).toInt()[0]
self.parent.manager.delete_song(item_id)
self.parent.manager.delete_object(Song, item_id)
self.onSearchTextButtonClick()
def generateSlideData(self, service_item, item=None):
@ -331,7 +335,7 @@ class SongMediaItem(MediaManagerItem):
service_item.add_capability(ItemCapabilities.AllowsEdit)
service_item.add_capability(ItemCapabilities.AllowsPreview)
service_item.add_capability(ItemCapabilities.AllowsLoop)
song = self.parent.manager.get_song(item_id)
song = self.parent.manager.get_object(Song, item_id)
service_item.theme = song.theme_name
service_item.editId = item_id
if song.lyrics.startswith(u'<?xml version='):
@ -367,7 +371,8 @@ class SongMediaItem(MediaManagerItem):
author_list = author_list + unicode(author.display_name)
author_audit.append(unicode(author.display_name))
if song.ccli_number is None or len(song.ccli_number) == 0:
ccli = self.parent.settings_form.GeneralTab.CCLINumber
ccli = QtCore.QSettings().value(u'general/ccli number',
QtCore.QVariant(u'')).toString()
else:
ccli = unicode(song.ccli_number)
raw_footer.append(song.title)

View File

@ -1,38 +0,0 @@
# -*- 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, Christian Richter, Maikel Stuivenberg, Martin #
# Thompson, Jon Tibble, Carsten Tinggaard #
# --------------------------------------------------------------------------- #
# This program is free software; you can redistribute it and/or modify it #
# under the terms of the GNU General Public License as published by the Free #
# Software Foundation; version 2 of the License. #
# #
# This program is distributed in the hope that it will be useful, but WITHOUT #
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
# more details. #
# #
# You should have received a copy of the GNU General Public License along #
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
from sqlalchemy import MetaData
__all__ = ['session', 'metadata', 'engine']
# SQLAlchemy database engine. Updated by model.init_model()
engine = None
# SQLAlchemy session manager. Updated by model.init_model()
session = None
# Global metadata. If you have multiple databases with overlapping table
# names, you'll need a metadata for each database
metadata = MetaData()

View File

@ -1,48 +0,0 @@
# -*- 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, Christian Richter, Maikel Stuivenberg, Martin #
# Thompson, Jon Tibble, Carsten Tinggaard #
# --------------------------------------------------------------------------- #
# This program is free software; you can redistribute it and/or modify it #
# under the terms of the GNU General Public License as published by the Free #
# Software Foundation; version 2 of the License. #
# #
# This program is distributed in the hope that it will be useful, but WITHOUT #
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
# more details. #
# #
# You should have received a copy of the GNU General Public License along #
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
from sqlalchemy import create_engine
from sqlalchemy.orm import scoped_session, sessionmaker, mapper, relation
from openlp.plugins.songs.lib.meta import metadata
from openlp.plugins.songs.lib.tables import *
from openlp.plugins.songs.lib.classes import *
def init_models(url):
engine = create_engine(url)
metadata.bind = engine
session = scoped_session(sessionmaker(autoflush=False, autocommit=False,
bind=engine))
mapper(Author, authors_table)
mapper(Book, song_books_table)
mapper(Song, songs_table,
properties={'authors': relation(Author, backref='songs',
secondary=authors_songs_table),
'book': relation(Book, backref='songs'),
'topics': relation(Topic, backref='songs',
secondary=songs_topics_table)})
mapper(Topic, topics_table)
return session

View File

@ -27,7 +27,7 @@ import re
from openlp.core.lib import SongXMLBuilder, translate
from openlp.plugins.songs.lib import VerseType
from openlp.plugins.songs.lib.models import Song, Author, Topic, Book
from openlp.plugins.songs.lib.db import Song, Author, Topic, Book
class SongImport(object):
"""
@ -264,7 +264,6 @@ class SongImport(object):
if len(self.authors) == 0:
self.authors.append(u'Author unknown')
self.commit_song()
#self.print_song()
def commit_song(self):
"""
@ -303,30 +302,33 @@ class SongImport(object):
song.theme_name = self.theme_name
song.ccli_number = self.ccli_number
for authortext in self.authors:
author = self.manager.get_author_by_name(authortext)
author = self.manager.get_object_filtered(Author,
Author.display_name == authortext)
if author is None:
author = Author()
author.display_name = authortext
author.last_name = authortext.split(u' ')[-1]
author.first_name = u' '.join(authortext.split(u' ')[:-1])
self.manager.save_author(author)
self.manager.save_object(author)
song.authors.append(author)
if self.song_book_name:
song_book = self.manager.get_book_by_name(self.song_book_name)
song_book = self.manager.get_object_filtered(Book,
Book.name == self.song_book_name)
if song_book is None:
song_book = Book()
song_book.name = self.song_book_name
song_book.publisher = self.song_book_pub
self.manager.save_book(song_book)
self.manager.save_object(song_book)
song.song_book_id = song_book.id
for topictext in self.topics:
topic = self.manager.get_topic_by_name(topictext)
topic = self.manager.get_object_filtered(Topic,
Topic.name == topictext)
if topic is None:
topic = Topic()
topic.name = topictext
self.manager.save_topic(topic)
self.manager.save_object(topic)
song.topics.append(topictext)
self.manager.save_song(song)
self.manager.save_object(song)
def print_song(self):
"""
@ -357,5 +359,3 @@ class SongImport(object):
print u'THEME: ' + self.theme_name
if self.ccli_number:
print u'CCLI: ' + self.ccli_number

View File

@ -1,99 +0,0 @@
# -*- 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, Christian Richter, Maikel Stuivenberg, Martin #
# Thompson, Jon Tibble, Carsten Tinggaard #
# --------------------------------------------------------------------------- #
# This program is free software; you can redistribute it and/or modify it #
# under the terms of the GNU General Public License as published by the Free #
# Software Foundation; version 2 of the License. #
# #
# This program is distributed in the hope that it will be useful, but WITHOUT #
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
# more details. #
# #
# You should have received a copy of the GNU General Public License along #
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
from sqlalchemy import *
from sqlalchemy import Column, Table, ForeignKey, types
from openlp.plugins.songs.lib.meta import metadata
# Definition of the "authors" table
authors_table = Table(u'authors', metadata,
Column(u'id', types.Integer, primary_key=True),
Column(u'first_name', types.Unicode(128)),
Column(u'last_name', types.Unicode(128)),
Column(u'display_name', types.Unicode(255), nullable=False)
)
# Definition of the "song_books" table
song_books_table = Table(u'song_books', metadata,
Column(u'id', types.Integer, primary_key=True),
Column(u'name', types.Unicode(128), nullable=False),
Column(u'publisher', types.Unicode(128))
)
# Definition of the "songs" table
songs_table = Table(u'songs', metadata,
Column(u'id', types.Integer, primary_key=True),
Column(u'song_book_id', types.Integer,
ForeignKey(u'song_books.id'), default=0),
Column(u'title', types.Unicode(255), nullable=False),
Column(u'lyrics', types.UnicodeText, nullable=False),
Column(u'verse_order', types.Unicode(128)),
Column(u'copyright', types.Unicode(255)),
Column(u'comments', types.UnicodeText),
Column(u'ccli_number', types.Unicode(64)),
Column(u'song_number', types.Unicode(64)),
Column(u'theme_name', types.Unicode(128)),
Column(u'search_title', types.Unicode(255), index=True, nullable=False),
Column(u'search_lyrics', types.UnicodeText, index=True, nullable=False)
)
# Definition of the "topics" table
topics_table = Table(u'topics', metadata,
Column(u'id', types.Integer, primary_key=True),
Column(u'name', types.Unicode(128), nullable=False)
)
# Definition of the "authors_songs" table
authors_songs_table = Table(u'authors_songs', metadata,
Column(u'author_id', types.Integer,
ForeignKey(u'authors.id'), primary_key=True),
Column(u'song_id', types.Integer,
ForeignKey(u'songs.id'), primary_key=True)
)
# Definition of the "songs_topics" table
songs_topics_table = Table(u'songs_topics', metadata,
Column(u'song_id', types.Integer,
ForeignKey(u'songs.id'), primary_key=True),
Column(u'topic_id', types.Integer,
ForeignKey(u'topics.id'), primary_key=True)
)
# Define table indexes
Index(u'authors_id', authors_table.c.id)
Index(u'authors_display_name_id', authors_table.c.display_name,
authors_table.c.id)
Index(u'song_books_id', song_books_table.c.id)
Index(u'songs_id', songs_table.c.id)
Index(u'topics_id', topics_table.c.id)
Index(u'authors_songs_author', authors_songs_table.c.author_id,
authors_songs_table.c.song_id)
Index(u'authors_songs_song', authors_songs_table.c.song_id,
authors_songs_table.c.author_id)
Index(u'topics_song_topic', songs_topics_table.c.topic_id,
songs_topics_table.c.song_id)
Index(u'topics_song_song', songs_topics_table.c.song_id,
songs_topics_table.c.topic_id)

View File

@ -29,7 +29,9 @@ from PyQt4 import QtCore, QtGui
from openlp.core.lib import Plugin, build_icon, PluginStatus, Receiver, \
translate
from openlp.plugins.songs.lib import SongManager, SongMediaItem, SongsTab
from openlp.core.lib.db import Manager
from openlp.plugins.songs.lib import SongMediaItem, SongsTab
from openlp.plugins.songs.lib.db import init_schema, Song
try:
from openlp.plugins.songs.lib import SofImport, OooImport
@ -39,7 +41,6 @@ except ImportError:
log = logging.getLogger(__name__)
class SongsPlugin(Plugin):
"""
This is the number 1 plugin, if importance were placed on any
@ -56,8 +57,8 @@ class SongsPlugin(Plugin):
"""
Plugin.__init__(self, u'Songs', u'1.9.2', plugin_helpers)
self.weight = -10
self.manager = SongManager()
self.icon = build_icon(u':/media/media_song.png')
self.manager = Manager(u'songs', init_schema)
self.icon = build_icon(u':/plugins/plugin_songs.png')
self.status = PluginStatus.Active
def get_settings_tab(self):
@ -65,16 +66,9 @@ class SongsPlugin(Plugin):
def initialise(self):
log.info(u'Songs Initialising')
#if self.songmanager is None:
# self.songmanager = SongManager()
Plugin.initialise(self)
self.insert_toolbox_item()
self.media_item.displayResultsSong(self.manager.get_songs())
def finalise(self):
log.info(u'Plugin Finalise')
Plugin.finalise(self)
self.remove_toolbox_item()
self.media_item.displayResultsSong(
self.manager.get_all_objects(Song, Song.title))
def get_media_manager_item(self):
"""
@ -198,6 +192,7 @@ class SongsPlugin(Plugin):
return about_text
def can_delete_theme(self, theme):
if len(self.manager.get_songs_for_theme(theme)) == 0:
if not self.manager.get_all_objects_filtered(Song,
Song.theme_name == theme):
return True
return False

View File

@ -22,3 +22,8 @@
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
"""
The :mod:`songusage` module contains the Song Usage plugin. The Song Usage
plugin provides auditing capabilities for reporting the songs you are using to
copyright license organisations.
"""

View File

@ -42,7 +42,7 @@ class SongUsageDetailForm(QtGui.QDialog, Ui_SongUsageDetailDialog):
def __init__(self, parent=None):
"""
Constructor
Initialise the form
"""
QtGui.QDialog.__init__(self, None)
self.parent = parent
@ -74,16 +74,16 @@ class SongUsageDetailForm(QtGui.QDialog, Ui_SongUsageDetailDialog):
filename = u'usage_detail_%s_%s.txt' % (
self.FromDate.selectedDate().toString(u'ddMMyyyy'),
self.ToDate.selectedDate().toString(u'ddMMyyyy'))
usage = self.parent.songusagemanager.get_all_songusage(
usage = self.parent.songusagemanager.get_songusage_for_period(
self.FromDate.selectedDate(), self.ToDate.selectedDate())
outname = os.path.join(unicode(self.FileLineEdit.text()), filename)
file = None
try:
file = open(outname, u'w')
for instance in usage:
record = u'\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\"\n' % \
(instance.usagedate,instance.usagetime, instance.title,
instance.copyright, instance.ccl_number , instance.authors)
record = u'\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\"\n' % (
instance.usagedate, instance.usagetime, instance.title,
instance.copyright, instance.ccl_number, instance.authors)
file.write(record)
except IOError:
log.exception(u'Failed to write out song usage records')

View File

@ -22,5 +22,7 @@
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
from manager import SongUsageManager
"""
The :mod:`lib` module contains the library functions for the songusage plugin.
"""
from openlp.plugins.songusage.lib.manager import SongUsageManager

View File

@ -1,32 +0,0 @@
# -*- 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, Christian Richter, Maikel Stuivenberg, Martin #
# Thompson, Jon Tibble, Carsten Tinggaard #
# --------------------------------------------------------------------------- #
# This program is free software; you can redistribute it and/or modify it #
# under the terms of the GNU General Public License as published by the Free #
# Software Foundation; version 2 of the License. #
# #
# This program is distributed in the hope that it will be useful, but WITHOUT #
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
# more details. #
# #
# You should have received a copy of the GNU General Public License along #
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
from openlp.core.lib import BaseModel
class SongUsageItem(BaseModel):
"""
Audit model
"""
pass

View File

@ -22,18 +22,42 @@
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
"""
The :mod:`db` module provides the database and schema that is the backend for
the SongUsage plugin
"""
from sqlalchemy import create_engine
from sqlalchemy.orm import scoped_session, sessionmaker, mapper
from sqlalchemy import Column, Table, types
from sqlalchemy.orm import mapper
from openlp.plugins.songusage.lib.meta import metadata
from openlp.plugins.songusage.lib.tables import *
from openlp.plugins.songusage.lib.classes import *
from openlp.core.lib.db import BaseModel, init_db
class SongUsageItem(BaseModel):
"""
SongUsageItem model
"""
pass
def init_schema(url):
"""
Setup the songusage database connection and initialise the database schema
``url``
The database to setup
"""
session, metadata = init_db(url)
songusage_table = Table(u'songusage_data', metadata,
Column(u'id', types.Integer(), primary_key=True),
Column(u'usagedate', types.Date, index=True, nullable=False),
Column(u'usagetime', types.Time, index=True, nullable=False),
Column(u'title', types.Unicode(255), nullable=False),
Column(u'authors', types.Unicode(255), nullable=False),
Column(u'copyright', types.Unicode(255)),
Column(u'ccl_number', types.Unicode(65))
)
def init_models(url):
engine = create_engine(url)
metadata.bind = engine
session = scoped_session(sessionmaker(autoflush=True, autocommit=False,
bind=engine))
mapper(SongUsageItem, songusage_table)
metadata.create_all(checkfirst=True)
return session

View File

@ -22,19 +22,19 @@
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
"""
The :mod:`manager` module provides song usage specific database query code
"""
import logging
from PyQt4 import QtCore
from sqlalchemy.exceptions import InvalidRequestError
from openlp.core.utils import AppLocation
from openlp.plugins.songusage.lib.models import init_models, metadata, \
SongUsageItem
from openlp.core.lib.db import Manager
from openlp.plugins.songusage.lib.db import init_schema, SongUsageItem
log = logging.getLogger(__name__)
class SongUsageManager(object):
class SongUsageManager(Manager):
"""
The Song Manager provides a central location for all database code. This
class takes care of connecting to the database and running all the queries.
@ -47,98 +47,31 @@ class SongUsageManager(object):
don't exist.
"""
log.debug(u'SongUsage Initialising')
settings = QtCore.QSettings()
settings.beginGroup(u'songusage')
self.db_url = u''
db_type = unicode(
settings.value(u'db type', QtCore.QVariant(u'sqlite')).toString())
if db_type == u'sqlite':
self.db_url = u'sqlite:///%s/songusage.sqlite' % \
AppLocation.get_section_data_path(u'songusage')
else:
self.db_url = u'%s://%s:%s@%s/%s' % (db_type,
unicode(settings.value(u'db username',
QtCore.QVariant(u'')).toString()),
unicode(settings.value(u'db password',
QtCore.QVariant(u'')).toString()),
unicode(settings.value(u'db hostname',
QtCore.QVariant(u'')).toString()),
unicode(settings.value(u'db database',
QtCore.QVariant(u'')).toString()))
self.session = init_models(self.db_url)
metadata.create_all(checkfirst=True)
settings.endGroup()
Manager.__init__(self, u'songusage', init_schema)
log.debug(u'SongUsage Initialised')
def get_all_songusage(self, start_date, end_date):
def get_songusage_for_period(self, start_date, end_date):
"""
Returns the details of SongUsage
Returns the details of SongUsage for a designated time period
``start_date``
The start of the period to return
``end_date``
The end of the period to return
"""
return self.session.query(SongUsageItem) \
.filter(SongUsageItem.usagedate >= start_date.toPyDate()) \
.filter(SongUsageItem.usagedate < end_date.toPyDate()) \
.order_by(SongUsageItem.usagedate, SongUsageItem.usagetime ).all()
def insert_songusage(self, songusageitem):
"""
Saves an SongUsage to the database
"""
log.debug(u'SongUsage added')
try:
self.session.add(songusageitem)
self.session.commit()
return True
except InvalidRequestError:
self.session.rollback()
log.exception(u'SongUsage item failed to save')
return False
def get_songusage(self, id=None):
"""
Returns the details of a SongUsage
"""
if id is None:
return SongUsageItem()
else:
return self.session.query(SongUsageItem).get(id)
def delete_songusage(self, id):
"""
Delete a SongUsage record
"""
if id != 0:
songusageitem = self.get_songusage(id)
try:
self.session.delete(songusageitem)
self.session.commit()
return True
except InvalidRequestError:
self.session.rollback()
log.exception(u'SongUsage Item failed to delete')
return False
else:
return True
def delete_all(self):
"""
Delete all Song Usage records
"""
try:
self.session.query(SongUsageItem).delete(synchronize_session=False)
self.session.commit()
return True
except InvalidRequestError:
self.session.rollback()
log.exception(u'Failed to delete all Song Usage items')
return False
.order_by(SongUsageItem.usagedate, SongUsageItem.usagetime).all()
def delete_to_date(self, date):
"""
Delete SongUsage records before given date
"""
try:
self.session.query(SongUsageItem)\
.filter(SongUsageItem.usagedate <= date)\
self.session.query(SongUsageItem) \
.filter(SongUsageItem.usagedate <= date) \
.delete(synchronize_session=False)
self.session.commit()
return True
@ -146,4 +79,3 @@ class SongUsageManager(object):
self.session.rollback()
log.exception(u'Failed to delete all Song Usage items to %s' % date)
return False

View File

@ -1,38 +0,0 @@
# -*- 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, Christian Richter, Maikel Stuivenberg, Martin #
# Thompson, Jon Tibble, Carsten Tinggaard #
# --------------------------------------------------------------------------- #
# This program is free software; you can redistribute it and/or modify it #
# under the terms of the GNU General Public License as published by the Free #
# Software Foundation; version 2 of the License. #
# #
# This program is distributed in the hope that it will be useful, but WITHOUT #
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
# more details. #
# #
# You should have received a copy of the GNU General Public License along #
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
from sqlalchemy import MetaData
__all__ = ['session', 'metadata', 'engine']
# SQLAlchemy database engine. Updated by model.init_model()
engine = None
# SQLAlchemy session manager. Updated by model.init_model()
session = None
# Global metadata. If you have multiple databases with overlapping table
# names, you'll need a metadata for each database
metadata = MetaData()

View File

@ -1,39 +0,0 @@
# -*- 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, Christian Richter, Maikel Stuivenberg, Martin #
# Thompson, Jon Tibble, Carsten Tinggaard #
# --------------------------------------------------------------------------- #
# This program is free software; you can redistribute it and/or modify it #
# under the terms of the GNU General Public License as published by the Free #
# Software Foundation; version 2 of the License. #
# #
# This program is distributed in the hope that it will be useful, but WITHOUT #
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
# more details. #
# #
# You should have received a copy of the GNU General Public License along #
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
from sqlalchemy import Column, Table, types
from openlp.plugins.songusage.lib.meta import metadata
# Definition of the "songusage" table
songusage_table = Table(u'songusage_data', metadata,
Column(u'id', types.Integer(), primary_key=True),
Column(u'usagedate', types.Date, index=True, nullable=False),
Column(u'usagetime', types.Time, index=True, nullable=False),
Column(u'title', types.Unicode(255), nullable=False),
Column(u'authors', types.Unicode(255), nullable=False),
Column(u'copyright', types.Unicode(255)),
Column(u'ccl_number', types.Unicode(65))
)

View File

@ -23,16 +23,16 @@
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
from datetime import datetime
import logging
from datetime import datetime
from PyQt4 import QtCore, QtGui
from openlp.core.lib import Plugin, Receiver, build_icon, translate
from openlp.plugins.songusage.lib import SongUsageManager
from openlp.plugins.songusage.forms import SongUsageDetailForm, \
SongUsageDeleteForm
from openlp.plugins.songusage.lib.models import SongUsageItem
from openlp.plugins.songusage.lib.db import SongUsageItem
log = logging.getLogger(__name__)
@ -42,7 +42,7 @@ class SongUsagePlugin(Plugin):
def __init__(self, plugin_helpers):
Plugin.__init__(self, u'SongUsage', u'1.9.2', plugin_helpers)
self.weight = -4
self.icon = build_icon(u':/media/media_image.png')
self.icon = build_icon(u':/plugins/plugin_songusage.png')
self.songusagemanager = None
self.songusageActive = False
@ -76,7 +76,7 @@ class SongUsagePlugin(Plugin):
translate('SongUsagePlugin', 'Generate report on Song Usage'))
self.SongUsageReport.setObjectName(u'SongUsageReport')
#SongUsage activation
SongUsageIcon = build_icon(u':/tools/tools_alert.png')
SongUsageIcon = build_icon(u':/plugins/plugin_songusage.png')
self.SongUsageStatus = QtGui.QAction(tools_menu)
self.SongUsageStatus.setIcon(SongUsageIcon)
self.SongUsageStatus.setCheckable(True)
@ -148,7 +148,7 @@ class SongUsagePlugin(Plugin):
song_usage_item.authors = u''
for author in audit[1]:
song_usage_item.authors += author + u' '
self.songusagemanager.insert_songusage(song_usage_item)
self.songusagemanager.save_object(song_usage_item)
def onSongUsageDelete(self):
self.SongUsagedeleteform.exec_()
@ -162,4 +162,4 @@ class SongUsagePlugin(Plugin):
'<b>SongUsage Plugin</b><br>This plugin '
'records the use of songs and when they have been used during '
'a live service')
return about_text
return about_text

View File

@ -1,5 +1,5 @@
<RCC>
<qresource prefix="songs" >
<qresource prefix="songs">
<file>topic_edit.png</file>
<file>author_add.png</file>
<file>author_delete.png</file>
@ -17,7 +17,18 @@
<file>song_topic_edit.png</file>
<file>song_book_edit.png</file>
</qresource>
<qresource prefix="general" >
<qresource prefix="plugins">
<file>plugin_alerts.png</file>
<file>plugin_bibles.png</file>
<file>plugin_custom.png</file>
<file>plugin_images.png</file>
<file>plugin_media.png</file>
<file>plugin_presentations.png</file>
<file>plugin_songs.png</file>
<file>plugin_remote.png</file>
<file>plugin_songusage.png</file>
</qresource>
<qresource prefix="general">
<file>general_preview.png</file>
<file>general_live.png</file>
<file>general_add.png</file>
@ -29,7 +40,7 @@
<file>general_open.png</file>
<file>general_save.png</file>
</qresource>
<qresource prefix="slides" >
<qresource prefix="slides">
<file>slide_close.png</file>
<file>slide_first.png</file>
<file>slide_last.png</file>
@ -42,7 +53,7 @@
<file>media_playback_stop.png</file>
<file>media_playback_pause.png</file>
</qresource>
<qresource prefix="icon" >
<qresource prefix="icon">
<file>openlp-logo-16x16.png</file>
<file>openlp-logo-32x32.png</file>
<file>openlp-logo-48x48.png</file>
@ -50,27 +61,27 @@
<file>openlp-logo-128x128.png</file>
<file>openlp-logo-256x256.png</file>
</qresource>
<qresource prefix="graphics" >
<qresource prefix="graphics">
<file>openlp-about-logo.png</file>
<file>openlp-splash-screen.png</file>
</qresource>
<qresource prefix="imports" >
<qresource prefix="imports">
<file>import_selectall.png</file>
<file>import_move_to_list.png</file>
<file>import_remove.png</file>
<file>import_load.png</file>
</qresource>
<qresource prefix="exports" >
<qresource prefix="exports">
<file>export_selectall.png</file>
<file>export_remove.png</file>
<file>export_load.png</file>
<file>export_move_to_list.png</file>
</qresource>
<qresource prefix="wizards" >
<qresource prefix="wizards">
<file>wizard_importsong.bmp</file>
<file>wizard_importbible.bmp</file>
</qresource>
<qresource prefix="services" >
<qresource prefix="services">
<file>service_notes.png</file>
<file>service_item_notes.png</file>
<file>service_bottom.png</file>
@ -78,7 +89,7 @@
<file>service_top.png</file>
<file>service_up.png</file>
</qresource>
<qresource prefix="system" >
<qresource prefix="system">
<file>system_close.png</file>
<file>system_about.png</file>
<file>system_help_contents.png</file>
@ -89,27 +100,21 @@
<file>system_exit.png</file>
<file>system_settings.png</file>
</qresource>
<qresource prefix="media" >
<file>media_custom.png</file>
<file>media_presentation.png</file>
<file>media_image.png</file>
<file>media_song.png</file>
<file>media_bible.png</file>
<file>media_video.png</file>
<qresource prefix="media">
<file>media_time.png</file>
<file>media_stop.png</file>
<file>image_clapperboard.png</file>
</qresource>
<qresource prefix="messagebox" >
<qresource prefix="messagebox">
<file>messagebox_critical.png</file>
<file>messagebox_info.png</file>
<file>messagebox_warning.png</file>
</qresource>
<qresource prefix="tools" >
<qresource prefix="tools">
<file>tools_add.png</file>
<file>tools_alert.png</file>
</qresource>
<qresource prefix="themes" >
<qresource prefix="themes">
<file>theme_delete.png</file>
<file>theme_new.png</file>
<file>theme_edit.png</file>

Binary file not shown.

After

Width:  |  Height:  |  Size: 762 B

View File

Before

Width:  |  Height:  |  Size: 590 B

After

Width:  |  Height:  |  Size: 590 B

View File

Before

Width:  |  Height:  |  Size: 514 B

After

Width:  |  Height:  |  Size: 514 B

View File

Before

Width:  |  Height:  |  Size: 534 B

After

Width:  |  Height:  |  Size: 534 B

View File

Before

Width:  |  Height:  |  Size: 915 B

After

Width:  |  Height:  |  Size: 915 B

View File

Before

Width:  |  Height:  |  Size: 551 B

After

Width:  |  Height:  |  Size: 551 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 830 B

Some files were not shown because too many files have changed in this diff Show More