This commit is contained in:
Andreas Preikschat 2010-12-13 15:23:40 +01:00
commit 78a752b77c
15 changed files with 629 additions and 68 deletions

View File

@ -0,0 +1,38 @@
PSF LICENSE AGREEMENT FOR PYTHON 2.7.1
1. This LICENSE AGREEMENT is between the Python Software Foundation ("PSF"),
and the Individual or Organization ("Licensee") accessing and otherwise
using Python 2.7.1 software in source or binary form and its associated
documentation.
2. Subject to the terms and conditions of this License Agreement, PSF hereby
grants Licensee a nonexclusive, royalty-free, world-wide license to
reproduce, analyze, test, perform and/or display publicly, prepare
derivative works, distribute, and otherwise use Python 2.7.1 alone or in any
derivative version, provided, however, that PSF's License Agreement and
PSF's notice of copyright, i.e., "Copyright (c) 2001-2010 Python Software
Foundation; All Rights Reserved" are retained in Python 2.7.1 alone or in
any derivative version prepared by Licensee.
3. In the event Licensee prepares a derivative work that is based on or
incorporates Python 2.7.1 or any part thereof, and wants to make the
derivative work available to others as provided herein, then Licensee hereby
agrees to include in any such work a brief summary of the changes made to
Python 2.7.1.
4. PSF is making Python 2.7.1 available to Licensee on an "AS IS" basis. PSF
MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF
EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND DISCLAIMS ANY REPRESENTATION
OR WARRANTY OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT
THE USE OF PYTHON 2.7.1 WILL NOT INFRINGE ANY THIRD PARTY RIGHTS.
5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON 2.7.1 FOR
ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS A RESULT OF
MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 2.7.1, OR ANY DERIVATIVE
THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
6. This License Agreement will automatically terminate upon a material breach
of its terms and conditions.
7. Nothing in this License Agreement shall be deemed to create any relationship
of agency, partnership, or joint venture between PSF and Licensee. This
License Agreement does not grant permission to use PSF trademarks or trade
name in a trademark sense to endorse or promote products or services of
Licensee, or any third party.
8. By copying, installing or otherwise using Python 2.7.1, Licensee agrees to
be bound by the terms and conditions of this License Agreement.

View File

@ -0,0 +1,321 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
###############################################################################
# Utilities for opening files or URLs in the registered default application #
# and for sending e-mail using the user's preferred composer. #
# --------------------------------------------------------------------------- #
# Copyright (c) 2007 Antonio Valentino #
# All rights reserved. #
# --------------------------------------------------------------------------- #
# This program offered under the PSF License as published by the Python #
# Software Foundation. #
# #
# The license text can be found at http://docs.python.org/license.html #
# #
# This code is taken from: http://code.activestate.com/recipes/511443 #
# Modified for use in OpenLP #
###############################################################################
__version__ = u'1.1'
__all__ = [u'open', u'mailto']
import os
import sys
import webbrowser
import subprocess
from email.Utils import encode_rfc2231
_controllers = {}
_open = None
class BaseController(object):
"""
Base class for open program controllers.
"""
def __init__(self, name):
self.name = name
def open(self, filename):
raise NotImplementedError
class Controller(BaseController):
"""
Controller for a generic open program.
"""
def __init__(self, *args):
super(Controller, self).__init__(os.path.basename(args[0]))
self.args = list(args)
def _invoke(self, cmdline):
if sys.platform[:3] == u'win':
closefds = False
startupinfo = subprocess.STARTUPINFO()
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
else:
closefds = True
startupinfo = None
if (os.environ.get(u'DISPLAY') or sys.platform[:3] == u'win' or \
sys.platform == u'darwin'):
inout = file(os.devnull, u'r+')
else:
# for TTY programs, we need stdin/out
inout = None
# if possible, put the child precess in separate process group,
# so keyboard interrupts don't affect child precess as well as
# Python
setsid = getattr(os, u'setsid', None)
if not setsid:
setsid = getattr(os, u'setpgrp', None)
pipe = subprocess.Popen(cmdline, stdin=inout, stdout=inout,
stderr=inout, close_fds=closefds, preexec_fn=setsid,
startupinfo=startupinfo)
# It is assumed that this kind of tools (gnome-open, kfmclient,
# exo-open, xdg-open and open for OSX) immediately exit after lauching
# the specific application
returncode = pipe.wait()
if hasattr(self, u'fixreturncode'):
returncode = self.fixreturncode(returncode)
return not returncode
def open(self, filename):
if isinstance(filename, basestring):
cmdline = self.args + [filename]
else:
# assume it is a sequence
cmdline = self.args + filename
try:
return self._invoke(cmdline)
except OSError:
return False
# Platform support for Windows
if sys.platform[:3] == u'win':
class Start(BaseController):
"""
Controller for the win32 start progam through os.startfile.
"""
def open(self, filename):
try:
os.startfile(filename)
except WindowsError:
# [Error 22] No application is associated with the specified
# file for this operation: '<URL>'
return False
else:
return True
_controllers[u'windows-default'] = Start(u'start')
_open = _controllers[u'windows-default'].open
# Platform support for MacOS
elif sys.platform == u'darwin':
_controllers[u'open']= Controller(u'open')
_open = _controllers[u'open'].open
# Platform support for Unix
else:
import commands
# @WARNING: use the private API of the webbrowser module
from webbrowser import _iscommand
class KfmClient(Controller):
"""
Controller for the KDE kfmclient program.
"""
def __init__(self, kfmclient=u'kfmclient'):
super(KfmClient, self).__init__(kfmclient, u'exec')
self.kde_version = self.detect_kde_version()
def detect_kde_version(self):
kde_version = None
try:
info = commands.getoutput(u'kfmclient --version')
for line in info.splitlines():
if line.startswith(u'KDE'):
kde_version = line.split(u':')[-1].strip()
break
except (OSError, RuntimeError):
pass
return kde_version
def fixreturncode(self, returncode):
if returncode is not None and self.kde_version > u'3.5.4':
return returncode
else:
return os.EX_OK
def detect_desktop_environment():
"""
Checks for known desktop environments
Return the desktop environments name, lowercase (kde, gnome, xfce)
or "generic"
"""
desktop_environment = u'generic'
if os.environ.get(u'KDE_FULL_SESSION') == u'true':
desktop_environment = u'kde'
elif os.environ.get(u'GNOME_DESKTOP_SESSION_ID'):
desktop_environment = u'gnome'
else:
try:
info = commands.getoutput(u'xprop -root _DT_SAVE_MODE')
if u' = "xfce4"' in info:
desktop_environment = u'xfce'
except (OSError, RuntimeError):
pass
return desktop_environment
def register_X_controllers():
if _iscommand(u'kfmclient'):
_controllers[u'kde-open'] = KfmClient()
for command in (u'gnome-open', u'exo-open', u'xdg-open'):
if _iscommand(command):
_controllers[command] = Controller(command)
def get():
controllers_map = {
u'gnome': u'gnome-open',
u'kde': u'kde-open',
u'xfce': u'exo-open',
}
desktop_environment = detect_desktop_environment()
try:
controller_name = controllers_map[desktop_environment]
return _controllers[controller_name].open
except KeyError:
if _controllers.has_key(u'xdg-open'):
return _controllers[u'xdg-open'].open
else:
return webbrowser.open
if os.environ.get(u'DISPLAY'):
register_X_controllers()
_open = get()
def open(filename):
"""
Open a file or an URL in the registered default application.
"""
return _open(filename)
def _fix_addersses(**kwargs):
for headername in (u'address', u'to', u'cc', u'bcc'):
try:
headervalue = kwargs[headername]
if not headervalue:
del kwargs[headername]
continue
elif not isinstance(headervalue, basestring):
# assume it is a sequence
headervalue = u','.join(headervalue)
except KeyError:
pass
except TypeError:
raise TypeError(u'string or sequence expected for "%s", %s '
u'found' % (headername, type(headervalue).__name__))
else:
translation_map = {u'%': u'%25', u'&': u'%26', u'?': u'%3F'}
for char, replacement in translation_map.items():
headervalue = headervalue.replace(char, replacement)
kwargs[headername] = headervalue
return kwargs
def mailto_format(**kwargs):
"""
Compile mailto string from call parameters
"""
# @TODO: implement utf8 option
kwargs = _fix_addersses(**kwargs)
parts = []
for headername in (u'to', u'cc', u'bcc', u'subject', u'body', u'attach'):
if kwargs.has_key(headername):
headervalue = kwargs[headername]
if not headervalue:
continue
if headername in (u'address', u'to', u'cc', u'bcc'):
parts.append(u'%s=%s' % (headername, headervalue))
else:
headervalue = encode_rfc2231(headervalue) # @TODO: check
parts.append(u'%s=%s' % (headername, headervalue))
mailto_string = u'mailto:%s' % kwargs.get(u'address', '')
if parts:
mailto_string = u'%s?%s' % (mailto_string, u'&'.join(parts))
return mailto_string
def mailto(address, to=None, cc=None, bcc=None, subject=None, body=None,
attach=None):
"""
Send an e-mail using the user's preferred composer.
Open the user's preferred e-mail composer in order to send a mail to
address(es) that must follow the syntax of RFC822. Multiple addresses
may be provided (for address, cc and bcc parameters) as separate
arguments.
All parameters provided are used to prefill corresponding fields in
the user's e-mail composer. The user will have the opportunity to
change any of this information before actually sending the e-mail.
``address``
specify the destination recipient
``cc``
specify a recipient to be copied on the e-mail
``bcc``
specify a recipient to be blindly copied on the e-mail
``subject``
specify a subject for the e-mail
``body``
specify a body for the e-mail. Since the user will be able to make
changes before actually sending the e-mail, this can be used to provide
the user with a template for the e-mail text may contain linebreaks
``attach``
specify an attachment for the e-mail. file must point to an existing
file
"""
mailto_string = mailto_format(**locals())
return open(mailto_string)

View File

@ -108,7 +108,7 @@ class Plugin(QtCore.QObject):
""" """
log.info(u'loaded') log.info(u'loaded')
def __init__(self, name, version=None, plugin_helpers=None): def __init__(self, name, version=None, pluginHelpers=None):
""" """
This is the constructor for the plugin object. This provides an easy This is the constructor for the plugin object. This provides an easy
way for descendent plugins to populate common data. This method *must* way for descendent plugins to populate common data. This method *must*
@ -124,7 +124,7 @@ class Plugin(QtCore.QObject):
``version`` ``version``
Defaults to *None*. The version of the plugin. Defaults to *None*. The version of the plugin.
``plugin_helpers`` ``pluginHelpers``
Defaults to *None*. A list of helper objects. Defaults to *None*. A list of helper objects.
""" """
QtCore.QObject.__init__(self) QtCore.QObject.__init__(self)
@ -139,14 +139,14 @@ class Plugin(QtCore.QObject):
self.status = PluginStatus.Inactive self.status = PluginStatus.Inactive
# Set up logging # Set up logging
self.log = logging.getLogger(self.name) self.log = logging.getLogger(self.name)
self.previewController = plugin_helpers[u'preview'] self.previewController = pluginHelpers[u'preview']
self.liveController = plugin_helpers[u'live'] self.liveController = pluginHelpers[u'live']
self.renderManager = plugin_helpers[u'render'] self.renderManager = pluginHelpers[u'render']
self.serviceManager = plugin_helpers[u'service'] self.serviceManager = pluginHelpers[u'service']
self.settingsForm = plugin_helpers[u'settings form'] self.settingsForm = pluginHelpers[u'settings form']
self.mediadock = plugin_helpers[u'toolbox'] self.mediadock = pluginHelpers[u'toolbox']
self.pluginManager = plugin_helpers[u'pluginmanager'] self.pluginManager = pluginHelpers[u'pluginmanager']
self.formparent = plugin_helpers[u'formparent'] self.formparent = pluginHelpers[u'formparent']
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'%s_add_service_item' % self.name), QtCore.SIGNAL(u'%s_add_service_item' % self.name),
self.processAddServiceEvent) self.processAddServiceEvent)

View File

@ -26,7 +26,7 @@
from PyQt4 import QtCore, QtGui from PyQt4 import QtCore, QtGui
from openlp.core.lib import translate from openlp.core.lib import translate, build_icon
class Ui_ExceptionDialog(object): class Ui_ExceptionDialog(object):
def setupUi(self, exceptionDialog): def setupUi(self, exceptionDialog):
@ -63,12 +63,27 @@ class Ui_ExceptionDialog(object):
self.exceptionButtonBox.setStandardButtons(QtGui.QDialogButtonBox.Close) self.exceptionButtonBox.setStandardButtons(QtGui.QDialogButtonBox.Close)
self.exceptionButtonBox.setObjectName(u'exceptionButtonBox') self.exceptionButtonBox.setObjectName(u'exceptionButtonBox')
self.exceptionLayout.addWidget(self.exceptionButtonBox) self.exceptionLayout.addWidget(self.exceptionButtonBox)
self.sendReportButton = QtGui.QPushButton(exceptionDialog)
self.sendReportButton.setIcon(build_icon(
u':/general/general_email.png'))
self.sendReportButton.setObjectName(u'sendReportButton')
self.exceptionButtonBox.addButton(self.sendReportButton,
QtGui.QDialogButtonBox.ActionRole)
self.saveReportButton = QtGui.QPushButton(exceptionDialog)
self.saveReportButton.setIcon(build_icon(u':/general/general_save.png'))
self.saveReportButton.setObjectName(u'saveReportButton')
self.exceptionButtonBox.addButton(self.saveReportButton,
QtGui.QDialogButtonBox.ActionRole)
self.retranslateUi(exceptionDialog) self.retranslateUi(exceptionDialog)
QtCore.QObject.connect(self.exceptionButtonBox, QtCore.QObject.connect(self.exceptionButtonBox,
QtCore.SIGNAL(u'accepted()'), exceptionDialog.accept) QtCore.SIGNAL(u'accepted()'), exceptionDialog.accept)
QtCore.QObject.connect(self.exceptionButtonBox, QtCore.QObject.connect(self.exceptionButtonBox,
QtCore.SIGNAL(u'rejected()'), exceptionDialog.reject) QtCore.SIGNAL(u'rejected()'), exceptionDialog.reject)
QtCore.QObject.connect(self.sendReportButton,
QtCore.SIGNAL(u'pressed()'), self.onSendReportButtonPressed)
QtCore.QObject.connect(self.saveReportButton,
QtCore.SIGNAL(u'pressed()'), self.onSaveReportButtonPressed)
QtCore.QMetaObject.connectSlotsByName(exceptionDialog) QtCore.QMetaObject.connectSlotsByName(exceptionDialog)
def retranslateUi(self, exceptionDialog): def retranslateUi(self, exceptionDialog):
@ -80,3 +95,7 @@ class Ui_ExceptionDialog(object):
'developers, so please e-mail it to bugs@openlp.org, along with a ' 'developers, so please e-mail it to bugs@openlp.org, along with a '
'detailed description of what you were doing when the problem ' 'detailed description of what you were doing when the problem '
'occurred.')) 'occurred.'))
self.sendReportButton.setText(translate('OpenLP.ExceptionDialog',
'Send E-Mail'))
self.saveReportButton.setText(translate('OpenLP.ExceptionDialog',
'Save to File'))

View File

@ -24,7 +24,38 @@
# Temple Place, Suite 330, Boston, MA 02111-1307 USA # # Temple Place, Suite 330, Boston, MA 02111-1307 USA #
############################################################################### ###############################################################################
from PyQt4 import QtGui import re
import os
import platform
import sqlalchemy
import BeautifulSoup
from lxml import etree
from PyQt4 import Qt, QtCore, QtGui
try:
from PyQt4.phonon import Phonon
phonon_version = Phonon.phononVersion()
except ImportError:
phonon_version = u'-'
try:
import chardet
chardet_version = chardet.__version__
except ImportError:
chardet_version = u'-'
try:
import enchant
enchant_version = enchant.__version__
except ImportError:
enchant_version = u'-'
try:
import sqlite
sqlite_version = sqlite.version
except ImportError:
sqlite_version = u'-'
from openlp.core.lib import translate, SettingsManager
from openlp.core.lib.mailto import mailto
from exceptiondialog import Ui_ExceptionDialog from exceptiondialog import Ui_ExceptionDialog
@ -35,3 +66,78 @@ class ExceptionForm(QtGui.QDialog, Ui_ExceptionDialog):
def __init__(self, parent): def __init__(self, parent):
QtGui.QDialog.__init__(self, parent) QtGui.QDialog.__init__(self, parent)
self.setupUi(self) self.setupUi(self)
self.settingsSection = u'crashreport'
def _createReport(self):
openlp_version = self.parent().applicationVersion[u'full']
traceback = unicode(self.exceptionTextEdit.toPlainText())
system = unicode(translate('OpenLP.ExceptionForm',
'Platform: %s\n')) % platform.platform()
libraries = u'Python: %s\n' % platform.python_version() + \
u'Qt4: %s\n' % Qt.qVersion() + \
u'Phonon: %s\n' % phonon_version + \
u'PyQt4: %s\n' % Qt.PYQT_VERSION_STR + \
u'SQLAlchemy: %s\n' % sqlalchemy.__version__ + \
u'BeautifulSoup: %s\n' % BeautifulSoup.__version__ + \
u'lxml: %s\n' % etree.__version__ + \
u'Chardet: %s\n' % chardet_version + \
u'PyEnchant: %s\n' % enchant_version + \
u'PySQLite: %s\n' % sqlite_version
if platform.system() == u'Linux':
if os.environ.get(u'KDE_FULL_SESSION') == u'true':
system = system + u'Desktop: KDE SC\n'
elif os.environ.get(u'GNOME_DESKTOP_SESSION_ID'):
system = system + u'Desktop: GNOME\n'
return (openlp_version, traceback, system, libraries)
def onSaveReportButtonPressed(self):
"""
Saving exception log and system informations to a file.
"""
report = unicode(translate('OpenLP.ExceptionForm',
'**OpenLP Bug Report**\n'
'Version: %s\n\n'
'--- Exception Traceback ---\n%s\n'
'--- System information ---\n%s\n'
'--- Library Versions ---\n%s\n'))
filename = QtGui.QFileDialog.getSaveFileName(self,
translate('OpenLP.ExceptionForm', 'Save Crash Report'),
SettingsManager.get_last_dir(self.settingsSection),
translate('OpenLP.ExceptionForm', 'Text files (*.txt *.log *.text)'))
if filename:
filename = unicode(QtCore.QDir.toNativeSeparators(filename))
SettingsManager.set_last_dir(self.settingsSection, os.path.dirname(
filename))
report = report % self._createReport()
try:
file = open(filename, u'w')
try:
file.write(report)
except UnicodeError:
file.close()
file = open(filename, u'wb')
file.write(report.encode(u'utf-8'))
file.close()
except IOError:
log.exception(u'Failed to write crash report')
def onSendReportButtonPressed(self):
"""
Opening systems default email client and inserting exception log and
system informations.
"""
body = unicode(translate('OpenLP.ExceptionForm',
'*OpenLP Bug Report*\n'
'Version: %s\n\n'
'--- Please enter the report below this line. ---\n\n\n'
'--- Exception Traceback ---\n%s\n'
'--- System information ---\n%s\n'
'--- Library Versions ---\n%s\n'))
content = self._createReport()
for line in content[1].split(u'\n'):
if re.search(r'[/\\]openlp[/\\]', line):
source = re.sub(r'.*[/\\]openlp[/\\](.*)".*', r'\1', line)
if u':' in line:
exception = line.split(u'\n')[-1].split(u':')[0]
subject = u'Bug report: %s in %s' % (exception, source)
mailto(address=u'bugs@openlp.org', subject=subject, body=body % content)

View File

@ -97,16 +97,16 @@ class Ui_MainWindow(object):
self.ControlSplitter.setObjectName(u'ControlSplitter') self.ControlSplitter.setObjectName(u'ControlSplitter')
self.MainContentLayout.addWidget(self.ControlSplitter) self.MainContentLayout.addWidget(self.ControlSplitter)
# Create slide controllers # Create slide controllers
self.PreviewController = SlideController(self, self.settingsmanager, self.previewController = SlideController(self, self.settingsmanager,
self.screens) self.screens)
self.LiveController = SlideController(self, self.settingsmanager, self.liveController = SlideController(self, self.settingsmanager,
self.screens, True) self.screens, True)
previewVisible = QtCore.QSettings().value( previewVisible = QtCore.QSettings().value(
u'user interface/preview panel', QtCore.QVariant(True)).toBool() u'user interface/preview panel', QtCore.QVariant(True)).toBool()
self.PreviewController.Panel.setVisible(previewVisible) self.previewController.Panel.setVisible(previewVisible)
liveVisible = QtCore.QSettings().value(u'user interface/live panel', liveVisible = QtCore.QSettings().value(u'user interface/live panel',
QtCore.QVariant(True)).toBool() QtCore.QVariant(True)).toBool()
self.LiveController.Panel.setVisible(liveVisible) self.liveController.Panel.setVisible(liveVisible)
# Create menu # Create menu
self.MenuBar = QtGui.QMenuBar(MainWindow) self.MenuBar = QtGui.QMenuBar(MainWindow)
self.MenuBar.setGeometry(QtCore.QRect(0, 0, 1087, 27)) self.MenuBar.setGeometry(QtCore.QRect(0, 0, 1087, 27))
@ -362,8 +362,8 @@ class Ui_MainWindow(object):
""" """
Splitter between the Preview and Live Controllers. Splitter between the Preview and Live Controllers.
""" """
self.LiveController.widthChanged() self.liveController.widthChanged()
self.PreviewController.widthChanged() self.previewController.widthChanged()
def retranslateUi(self, MainWindow): def retranslateUi(self, MainWindow):
""" """
@ -548,8 +548,8 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
self.recentFiles = QtCore.QStringList() self.recentFiles = QtCore.QStringList()
# Set up the path with plugins # Set up the path with plugins
pluginpath = AppLocation.get_directory(AppLocation.PluginsDir) pluginpath = AppLocation.get_directory(AppLocation.PluginsDir)
self.plugin_manager = PluginManager(pluginpath) self.pluginManager = PluginManager(pluginpath)
self.plugin_helpers = {} self.pluginHelpers = {}
# Set up the interface # Set up the interface
self.setupUi(self) self.setupUi(self)
# Load settings after setupUi so default UI sizes are overwritten # Load settings after setupUi so default UI sizes are overwritten
@ -633,33 +633,33 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
self.mediaDockManager = MediaDockManager(self.MediaToolBox) self.mediaDockManager = MediaDockManager(self.MediaToolBox)
log.info(u'Load Plugins') log.info(u'Load Plugins')
# make the controllers available to the plugins # make the controllers available to the plugins
self.plugin_helpers[u'preview'] = self.PreviewController self.pluginHelpers[u'preview'] = self.previewController
self.plugin_helpers[u'live'] = self.LiveController self.pluginHelpers[u'live'] = self.liveController
self.plugin_helpers[u'render'] = self.renderManager self.pluginHelpers[u'render'] = self.renderManager
self.plugin_helpers[u'service'] = self.ServiceManagerContents self.pluginHelpers[u'service'] = self.ServiceManagerContents
self.plugin_helpers[u'settings form'] = self.settingsForm self.pluginHelpers[u'settings form'] = self.settingsForm
self.plugin_helpers[u'toolbox'] = self.mediaDockManager self.pluginHelpers[u'toolbox'] = self.mediaDockManager
self.plugin_helpers[u'pluginmanager'] = self.plugin_manager self.pluginHelpers[u'pluginmanager'] = self.pluginManager
self.plugin_helpers[u'formparent'] = self self.pluginHelpers[u'formparent'] = self
self.plugin_manager.find_plugins(pluginpath, self.plugin_helpers) self.pluginManager.find_plugins(pluginpath, self.pluginHelpers)
# hook methods have to happen after find_plugins. Find plugins needs # hook methods have to happen after find_plugins. Find plugins needs
# the controllers hence the hooks have moved from setupUI() to here # the controllers hence the hooks have moved from setupUI() to here
# Find and insert settings tabs # Find and insert settings tabs
log.info(u'hook settings') log.info(u'hook settings')
self.plugin_manager.hook_settings_tabs(self.settingsForm) self.pluginManager.hook_settings_tabs(self.settingsForm)
# Find and insert media manager items # Find and insert media manager items
log.info(u'hook media') log.info(u'hook media')
self.plugin_manager.hook_media_manager(self.mediaDockManager) self.pluginManager.hook_media_manager(self.mediaDockManager)
# Call the hook method to pull in import menus. # Call the hook method to pull in import menus.
log.info(u'hook menus') log.info(u'hook menus')
self.plugin_manager.hook_import_menu(self.FileImportMenu) self.pluginManager.hook_import_menu(self.FileImportMenu)
# Call the hook method to pull in export menus. # Call the hook method to pull in export menus.
self.plugin_manager.hook_export_menu(self.FileExportMenu) self.pluginManager.hook_export_menu(self.FileExportMenu)
# Call the hook method to pull in tools menus. # Call the hook method to pull in tools menus.
self.plugin_manager.hook_tools_menu(self.ToolsMenu) self.pluginManager.hook_tools_menu(self.ToolsMenu)
# Call the initialise method to setup plugins. # Call the initialise method to setup plugins.
log.info(u'initialise plugins') log.info(u'initialise plugins')
self.plugin_manager.initialise_plugins() self.pluginManager.initialise_plugins()
# Once all components are initialised load the Themes # Once all components are initialised load the Themes
log.info(u'Load Themes') log.info(u'Load Themes')
self.ThemeManagerContents.loadThemes() self.ThemeManagerContents.loadThemes()
@ -695,10 +695,10 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
Show the main form, as well as the display form Show the main form, as well as the display form
""" """
QtGui.QWidget.show(self) QtGui.QWidget.show(self)
self.LiveController.display.setup() self.liveController.display.setup()
self.PreviewController.display.setup() self.previewController.display.setup()
if self.LiveController.display.isVisible(): if self.liveController.display.isVisible():
self.LiveController.display.setFocus() self.liveController.display.setFocus()
self.activateWindow() self.activateWindow()
if QtCore.QSettings().value( if QtCore.QSettings().value(
self.generalSettingsSection + u'/auto open', self.generalSettingsSection + u'/auto open',
@ -723,7 +723,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
settings = QtCore.QSettings() settings = QtCore.QSettings()
if settings.value(u'%s/screen blank' % self.generalSettingsSection, if settings.value(u'%s/screen blank' % self.generalSettingsSection,
QtCore.QVariant(False)).toBool(): QtCore.QVariant(False)).toBool():
self.LiveController.mainDisplaySetBackground() self.liveController.mainDisplaySetBackground()
if settings.value(u'blank warning', if settings.value(u'blank warning',
QtCore.QVariant(False)).toBool(): QtCore.QVariant(False)).toBool():
QtGui.QMessageBox.question(self, QtGui.QMessageBox.question(self,
@ -852,11 +852,11 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
QtCore.QVariant(self.MediaToolBox.currentIndex())) QtCore.QVariant(self.MediaToolBox.currentIndex()))
# Call the cleanup method to shutdown plugins. # Call the cleanup method to shutdown plugins.
log.info(u'cleanup plugins') log.info(u'cleanup plugins')
self.plugin_manager.finalise_plugins() self.pluginManager.finalise_plugins()
# Save settings # Save settings
self.saveSettings() self.saveSettings()
# Close down the display # Close down the display
self.LiveController.display.close() self.liveController.display.close()
def serviceChanged(self, reset=False, serviceName=None): def serviceChanged(self, reset=False, serviceName=None):
""" """
@ -910,7 +910,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
True - Visible True - Visible
False - Hidden False - Hidden
""" """
self.PreviewController.Panel.setVisible(visible) self.previewController.Panel.setVisible(visible)
QtCore.QSettings().setValue(u'user interface/preview panel', QtCore.QSettings().setValue(u'user interface/preview panel',
QtCore.QVariant(visible)) QtCore.QVariant(visible))
self.ViewPreviewPanel.setChecked(visible) self.ViewPreviewPanel.setChecked(visible)
@ -925,7 +925,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
True - Visible True - Visible
False - Hidden False - Hidden
""" """
self.LiveController.Panel.setVisible(visible) self.liveController.Panel.setVisible(visible)
QtCore.QSettings().setValue(u'user interface/live panel', QtCore.QSettings().setValue(u'user interface/live panel',
QtCore.QVariant(visible)) QtCore.QVariant(visible))
self.ViewLivePanel.setChecked(visible) self.ViewLivePanel.setChecked(visible)

View File

@ -61,7 +61,7 @@ class PluginForm(QtGui.QDialog, Ui_PluginViewDialog):
self.programaticChange = True self.programaticChange = True
self._clearDetails() self._clearDetails()
self.programaticChange = True self.programaticChange = True
for plugin in self.parent.plugin_manager.plugins: for plugin in self.parent.pluginManager.plugins:
item = QtGui.QListWidgetItem(self.pluginListWidget) item = QtGui.QListWidgetItem(self.pluginListWidget)
# We do this just to make 100% sure the status is an integer as # We do this just to make 100% sure the status is an integer as
# sometimes when it's loaded from the config, it isn't cast to int. # sometimes when it's loaded from the config, it isn't cast to int.
@ -110,7 +110,7 @@ class PluginForm(QtGui.QDialog, Ui_PluginViewDialog):
plugin_name_plural = \ plugin_name_plural = \
self.pluginListWidget.currentItem().text().split(u' ')[0] self.pluginListWidget.currentItem().text().split(u' ')[0]
self.activePlugin = None self.activePlugin = None
for plugin in self.parent.plugin_manager.plugins: for plugin in self.parent.pluginManager.plugins:
name_string = plugin.getString(StringContent.Name) name_string = plugin.getString(StringContent.Name)
if name_string[u'plural'] == plugin_name_plural: if name_string[u'plural'] == plugin_name_plural:
self.activePlugin = plugin self.activePlugin = plugin

View File

@ -880,7 +880,7 @@ class ServiceManager(QtGui.QWidget):
newItem.merge(item[u'service_item']) newItem.merge(item[u'service_item'])
item[u'service_item'] = newItem item[u'service_item'] = newItem
self.repaintServiceList(itemcount + 1, 0) self.repaintServiceList(itemcount + 1, 0)
self.parent.LiveController.replaceServiceManagerItem(newItem) self.parent.liveController.replaceServiceManagerItem(newItem)
self.parent.serviceChanged(False, self.serviceName) self.parent.serviceChanged(False, self.serviceName)
def addServiceItem(self, item, rebuild=False, expand=None, replace=False): def addServiceItem(self, item, rebuild=False, expand=None, replace=False):
@ -902,7 +902,7 @@ class ServiceManager(QtGui.QWidget):
item.merge(self.serviceItems[sitem][u'service_item']) item.merge(self.serviceItems[sitem][u'service_item'])
self.serviceItems[sitem][u'service_item'] = item self.serviceItems[sitem][u'service_item'] = item
self.repaintServiceList(sitem + 1, 0) self.repaintServiceList(sitem + 1, 0)
self.parent.LiveController.replaceServiceManagerItem(item) self.parent.liveController.replaceServiceManagerItem(item)
else: else:
# nothing selected for dnd # nothing selected for dnd
if self.droppos == 0: if self.droppos == 0:
@ -923,7 +923,7 @@ class ServiceManager(QtGui.QWidget):
self.repaintServiceList(self.droppos, 0) self.repaintServiceList(self.droppos, 0)
# if rebuilding list make sure live is fixed. # if rebuilding list make sure live is fixed.
if rebuild: if rebuild:
self.parent.LiveController.replaceServiceManagerItem(item) self.parent.liveController.replaceServiceManagerItem(item)
self.droppos = 0 self.droppos = 0
self.parent.serviceChanged(False, self.serviceName) self.parent.serviceChanged(False, self.serviceName)
@ -933,7 +933,7 @@ class ServiceManager(QtGui.QWidget):
""" """
item, count = self.findServiceItem() item, count = self.findServiceItem()
if self.serviceItems[item][u'service_item'].is_valid: if self.serviceItems[item][u'service_item'].is_valid:
self.parent.PreviewController.addServiceManagerItem( self.parent.previewController.addServiceManagerItem(
self.serviceItems[item][u'service_item'], count) self.serviceItems[item][u'service_item'], count)
else: else:
QtGui.QMessageBox.critical(self, QtGui.QMessageBox.critical(self,
@ -957,7 +957,7 @@ class ServiceManager(QtGui.QWidget):
""" """
item, count = self.findServiceItem() item, count = self.findServiceItem()
if self.serviceItems[item][u'service_item'].is_valid: if self.serviceItems[item][u'service_item'].is_valid:
self.parent.LiveController.addServiceManagerItem( self.parent.liveController.addServiceManagerItem(
self.serviceItems[item][u'service_item'], count) self.serviceItems[item][u'service_item'], count)
if QtCore.QSettings().value( if QtCore.QSettings().value(
self.parent.generalSettingsSection + u'/auto preview', self.parent.generalSettingsSection + u'/auto preview',
@ -966,9 +966,9 @@ class ServiceManager(QtGui.QWidget):
if self.serviceItems and item < len(self.serviceItems) and \ if self.serviceItems and item < len(self.serviceItems) and \
self.serviceItems[item][u'service_item'].is_capable( self.serviceItems[item][u'service_item'].is_capable(
ItemCapabilities.AllowsPreview): ItemCapabilities.AllowsPreview):
self.parent.PreviewController.addServiceManagerItem( self.parent.previewController.addServiceManagerItem(
self.serviceItems[item][u'service_item'], 0) self.serviceItems[item][u'service_item'], 0)
self.parent.LiveController.PreviewListWidget.setFocus() self.parent.liveController.PreviewListWidget.setFocus()
else: else:
QtGui.QMessageBox.critical(self, QtGui.QMessageBox.critical(self,
translate('OpenLP.ServiceManager', 'Missing Display Handler'), translate('OpenLP.ServiceManager', 'Missing Display Handler'),

View File

@ -957,7 +957,7 @@ class SlideController(QtGui.QWidget):
""" """
row = self.PreviewListWidget.currentRow() row = self.PreviewListWidget.currentRow()
if row > -1 and row < self.PreviewListWidget.rowCount(): if row > -1 and row < self.PreviewListWidget.rowCount():
self.parent.LiveController.addServiceManagerItem( self.parent.liveController.addServiceManagerItem(
self.serviceItem, row) self.serviceItem, row)
def onMediaStart(self, item): def onMediaStart(self, item):

View File

@ -310,7 +310,7 @@ class ThemeManager(QtGui.QWidget):
translate('OpenLP.ThemeManager', translate('OpenLP.ThemeManager',
'You are unable to delete the default theme.')) 'You are unable to delete the default theme.'))
else: else:
for plugin in self.parent.plugin_manager.plugins: for plugin in self.parent.pluginManager.plugins:
if plugin.usesTheme(theme): if plugin.usesTheme(theme):
QtGui.QMessageBox.critical(self, QtGui.QMessageBox.critical(self,
translate('OpenLP.ThemeManager', 'Error'), translate('OpenLP.ThemeManager', 'Error'),
@ -663,7 +663,7 @@ class ThemeManager(QtGui.QWidget):
(QtGui.QMessageBox.Yes | QtGui.QMessageBox.No), (QtGui.QMessageBox.Yes | QtGui.QMessageBox.No),
QtGui.QMessageBox.No) QtGui.QMessageBox.No)
if self.saveThemeName != u'': if self.saveThemeName != u'':
for plugin in self.parent.plugin_manager.plugins: for plugin in self.parent.pluginManager.plugins:
if plugin.usesTheme(self.saveThemeName): if plugin.usesTheme(self.saveThemeName):
plugin.renameTheme(self.saveThemeName, name) plugin.renameTheme(self.saveThemeName, name)
if unicode(self.serviceComboBox.currentText()) == name: if unicode(self.serviceComboBox.currentText()) == name:

View File

@ -62,6 +62,9 @@ class AlertForm(QtGui.QDialog, Ui_AlertDialog):
QtCore.SIGNAL(u'clicked(QModelIndex)'), self.onSingleClick) QtCore.SIGNAL(u'clicked(QModelIndex)'), self.onSingleClick)
def loadList(self): def loadList(self):
"""
Loads the list with alerts.
"""
self.AlertListWidget.clear() self.AlertListWidget.clear()
alerts = self.manager.get_all_objects(AlertItem, alerts = self.manager.get_all_objects(AlertItem,
order_by_ref=AlertItem.text) order_by_ref=AlertItem.text)
@ -81,12 +84,16 @@ class AlertForm(QtGui.QDialog, Ui_AlertDialog):
self.close() self.close()
def onDeleteClick(self): def onDeleteClick(self):
"""
Deletes the selected item.
"""
item = self.AlertListWidget.currentItem() item = self.AlertListWidget.currentItem()
if item: if item:
item_id = (item.data(QtCore.Qt.UserRole)).toInt()[0] item_id = (item.data(QtCore.Qt.UserRole)).toInt()[0]
self.manager.delete_object(AlertItem, item_id) self.manager.delete_object(AlertItem, item_id)
row = self.AlertListWidget.row(item) row = self.AlertListWidget.row(item)
self.AlertListWidget.takeItem(row) self.AlertListWidget.takeItem(row)
self.item_id = None
self.AlertTextEdit.setText(u'') self.AlertTextEdit.setText(u'')
self.SaveButton.setEnabled(False) self.SaveButton.setEnabled(False)
self.DeleteButton.setEnabled(False) self.DeleteButton.setEnabled(False)
@ -96,8 +103,8 @@ class AlertForm(QtGui.QDialog, Ui_AlertDialog):
QtGui.QMessageBox.information(self, QtGui.QMessageBox.information(self,
translate('AlertsPlugin.AlertForm', 'New Alert'), translate('AlertsPlugin.AlertForm', 'New Alert'),
translate('AlertsPlugin.AlertForm', 'You haven\'t specified ' translate('AlertsPlugin.AlertForm', 'You haven\'t specified '
'any text for your alert. Please type in some text before ' 'any text for your alert. Please type in some text before '
'clicking New.')) 'clicking New.'))
else: else:
alert = AlertItem() alert = AlertItem()
alert.text = unicode(self.AlertTextEdit.text()) alert.text = unicode(self.AlertTextEdit.text())
@ -107,7 +114,7 @@ class AlertForm(QtGui.QDialog, Ui_AlertDialog):
def onSaveClick(self): def onSaveClick(self):
""" """
Save an alert Save the alert, we are editing.
""" """
if self.item_id: if self.item_id:
alert = self.manager.get_object(AlertItem, self.item_id) alert = self.manager.get_object(AlertItem, self.item_id)
@ -115,14 +122,14 @@ class AlertForm(QtGui.QDialog, Ui_AlertDialog):
self.manager.save_object(alert) self.manager.save_object(alert)
self.item_id = None self.item_id = None
self.loadList() self.loadList()
else:
self.onNewClick()
def onTextChanged(self): def onTextChanged(self):
""" """
Enable save button when data has been changed by editing the form Enable save button when data has been changed by editing the form
""" """
self.SaveButton.setEnabled(True) # Only enable the button, if we are editing an item.
if self.item_id:
self.SaveButton.setEnabled(True)
def onDoubleClick(self): def onDoubleClick(self):
""" """
@ -131,8 +138,8 @@ class AlertForm(QtGui.QDialog, Ui_AlertDialog):
items = self.AlertListWidget.selectedIndexes() items = self.AlertListWidget.selectedIndexes()
for item in items: for item in items:
bitem = self.AlertListWidget.item(item.row()) bitem = self.AlertListWidget.item(item.row())
self.triggerAlert(bitem.text()) self.triggerAlert(unicode(bitem.text()))
self.AlertTextEdit.setText(bitem.text()) self.AlertTextEdit.setText(unicode(bitem.text()))
self.item_id = (bitem.data(QtCore.Qt.UserRole)).toInt()[0] self.item_id = (bitem.data(QtCore.Qt.UserRole)).toInt()[0]
self.SaveButton.setEnabled(False) self.SaveButton.setEnabled(False)
self.DeleteButton.setEnabled(True) self.DeleteButton.setEnabled(True)
@ -145,13 +152,45 @@ class AlertForm(QtGui.QDialog, Ui_AlertDialog):
items = self.AlertListWidget.selectedIndexes() items = self.AlertListWidget.selectedIndexes()
for item in items: for item in items:
bitem = self.AlertListWidget.item(item.row()) bitem = self.AlertListWidget.item(item.row())
self.AlertTextEdit.setText(bitem.text()) self.AlertTextEdit.setText(unicode(bitem.text()))
self.item_id = (bitem.data(QtCore.Qt.UserRole)).toInt()[0] self.item_id = (bitem.data(QtCore.Qt.UserRole)).toInt()[0]
# If the alert does not contain '<>' we clear the ParameterEdit field.
if unicode(self.AlertTextEdit.text()).find(u'<>') == -1:
self.ParameterEdit.setText(u'')
self.SaveButton.setEnabled(False) self.SaveButton.setEnabled(False)
self.DeleteButton.setEnabled(True) self.DeleteButton.setEnabled(True)
def triggerAlert(self, text): def triggerAlert(self, text):
"""
Prepares the alert text for displaying.
``text``
The alert text (unicode).
"""
if text: if text:
# We found '<>' in the alert text, but the ParameterEdit field is
# empty.
if text.find(u'<>') != -1 and not self.ParameterEdit.text() and \
QtGui.QMessageBox.question(self, translate(
'AlertPlugin.AlertForm', 'No Parameter found'),
translate('AlertPlugin.AlertForm', 'You have not entered a '
'parameter to be replaced.\nDo you want to continue '
'anyway?'),
QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.No |
QtGui.QMessageBox.Yes)) == QtGui.QMessageBox.No:
self.ParameterEdit.setFocus()
return False
# The ParameterEdit field is not empty, but we have not found '<>'
# in the alert text.
elif text.find(u'<>') == -1 and self.ParameterEdit.text() and \
QtGui.QMessageBox.question(self, translate(
'AlertPlugin.AlertForm', 'No Placeholder found'),
translate('AlertPlugin.AlertForm', 'The alert text does not'
' contain \'<>\'.\nDo want to continue anyway?'),
QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.No |
QtGui.QMessageBox.Yes)) == QtGui.QMessageBox.No:
self.ParameterEdit.setFocus()
return False
text = text.replace(u'<>', unicode(self.ParameterEdit.text())) text = text.replace(u'<>', unicode(self.ParameterEdit.text()))
self.parent.alertsmanager.displayAlert(text) self.parent.alertsmanager.displayAlert(text)
return True return True

View File

@ -86,7 +86,7 @@ class AlertsManager(QtCore.QObject):
text = self.alertList.pop(0) text = self.alertList.pop(0)
alertTab = self.parent.alertsTab alertTab = self.parent.alertsTab
self.parent.liveController.display.alert(text) self.parent.liveController.display.alert(text)
# check to see if we have a timer running # Check to see if we have a timer running.
if self.timer_id == 0: if self.timer_id == 0:
self.timer_id = self.startTimer(int(alertTab.timeout) * 1000) self.timer_id = self.startTimer(int(alertTab.timeout) * 1000)
@ -94,9 +94,9 @@ class AlertsManager(QtCore.QObject):
""" """
Time has finished so if our time then request the next Alert Time has finished so if our time then request the next Alert
if there is one and reset the timer. if there is one and reset the timer.
``event`` ``event``
the QT event that has been triggered. the QT event that has been triggered.
""" """
log.debug(u'timer event') log.debug(u'timer event')
if event.timerId() == self.timer_id: if event.timerId() == self.timer_id:

View File

@ -120,35 +120,55 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
order_by_ref=Author.display_name) order_by_ref=Author.display_name)
self.AuthorsSelectionComboItem.clear() self.AuthorsSelectionComboItem.clear()
self.AuthorsSelectionComboItem.addItem(u'') self.AuthorsSelectionComboItem.addItem(u'')
self.authors = []
for author in authors: for author in authors:
row = self.AuthorsSelectionComboItem.count() row = self.AuthorsSelectionComboItem.count()
self.AuthorsSelectionComboItem.addItem(author.display_name) self.AuthorsSelectionComboItem.addItem(author.display_name)
self.AuthorsSelectionComboItem.setItemData( self.AuthorsSelectionComboItem.setItemData(
row, QtCore.QVariant(author.id)) row, QtCore.QVariant(author.id))
self.authors.append(author.display_name)
completer = QtGui.QCompleter(self.authors)
completer.setCaseSensitivity(QtCore.Qt.CaseInsensitive)
self.AuthorsSelectionComboItem.setCompleter(completer)
def loadTopics(self): def loadTopics(self):
topics = self.manager.get_all_objects(Topic, order_by_ref=Topic.name) topics = self.manager.get_all_objects(Topic, order_by_ref=Topic.name)
self.SongTopicCombo.clear() self.SongTopicCombo.clear()
self.SongTopicCombo.addItem(u'') self.SongTopicCombo.addItem(u'')
self.topics = []
for topic in topics: for topic in topics:
row = self.SongTopicCombo.count() row = self.SongTopicCombo.count()
self.SongTopicCombo.addItem(topic.name) self.SongTopicCombo.addItem(topic.name)
self.topics.append(topic.name)
self.SongTopicCombo.setItemData(row, QtCore.QVariant(topic.id)) self.SongTopicCombo.setItemData(row, QtCore.QVariant(topic.id))
completer = QtGui.QCompleter(self.topics)
completer.setCaseSensitivity(QtCore.Qt.CaseInsensitive)
self.SongTopicCombo.setCompleter(completer)
def loadBooks(self): def loadBooks(self):
books = self.manager.get_all_objects(Book, order_by_ref=Book.name) books = self.manager.get_all_objects(Book, order_by_ref=Book.name)
self.SongbookCombo.clear() self.SongbookCombo.clear()
self.SongbookCombo.addItem(u'') self.SongbookCombo.addItem(u'')
self.books = []
for book in books: for book in books:
row = self.SongbookCombo.count() row = self.SongbookCombo.count()
self.SongbookCombo.addItem(book.name) self.SongbookCombo.addItem(book.name)
self.books.append(book.name)
self.SongbookCombo.setItemData(row, QtCore.QVariant(book.id)) self.SongbookCombo.setItemData(row, QtCore.QVariant(book.id))
completer = QtGui.QCompleter(self.books)
completer.setCaseSensitivity(QtCore.Qt.CaseInsensitive)
self.SongbookCombo.setCompleter(completer)
def loadThemes(self, theme_list): def loadThemes(self, theme_list):
self.ThemeSelectionComboItem.clear() self.ThemeSelectionComboItem.clear()
self.ThemeSelectionComboItem.addItem(u'') self.ThemeSelectionComboItem.addItem(u'')
self.themes = []
for theme in theme_list: for theme in theme_list:
self.ThemeSelectionComboItem.addItem(theme) self.ThemeSelectionComboItem.addItem(theme)
self.themes.append(theme)
completer = QtGui.QCompleter(self.themes)
completer.setCaseSensitivity(QtCore.Qt.CaseInsensitive)
self.ThemeSelectionComboItem.setCompleter(completer)
def newSong(self): def newSong(self):
log.debug(u'New Song') log.debug(u'New Song')
@ -614,12 +634,29 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
self.saveSong(True): self.saveSong(True):
Receiver.send_message(u'songs_preview') Receiver.send_message(u'songs_preview')
def clearCaches(self):
"""
Free up autocompletion memory on dialog exit
"""
self.authors = []
self.themes = []
self.books = []
self.topics = []
def closePressed(self): def closePressed(self):
"""
Exit Dialog and do not save
"""
Receiver.send_message(u'songs_edit_clear') Receiver.send_message(u'songs_edit_clear')
self.clearCaches()
self.close() self.close()
def accept(self): def accept(self):
"""
Exit Dialog and save soong if valid
"""
log.debug(u'accept') log.debug(u'accept')
self.clearCaches()
if not self.song: if not self.song:
self.song = Song() self.song = Song()
item = int(self.SongbookCombo.currentIndex()) item = int(self.SongbookCombo.currentIndex())
@ -644,7 +681,7 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
Get all the data from the widgets on the form, and then save it to the Get all the data from the widgets on the form, and then save it to the
database. database.
``preview`` ``preview``
Should be ``True`` if the song is also previewed (boolean). Should be ``True`` if the song is also previewed (boolean).
""" """
self.song.title = unicode(self.TitleEditItem.text()) self.song.title = unicode(self.TitleEditItem.text())

Binary file not shown.

After

Width:  |  Height:  |  Size: 833 B

View File

@ -39,6 +39,7 @@
<file>general_new.png</file> <file>general_new.png</file>
<file>general_open.png</file> <file>general_open.png</file>
<file>general_save.png</file> <file>general_save.png</file>
<file>general_email.png</file>
</qresource> </qresource>
<qresource prefix="slides"> <qresource prefix="slides">
<file>slide_close.png</file> <file>slide_close.png</file>