forked from openlp/openlp
Merge master.
This commit is contained in:
commit
9bcdb79e7b
|
@ -393,7 +393,6 @@ from settings import Settings
|
|||
from listwidgetwithdnd import ListWidgetWithDnD
|
||||
from formattingtags import FormattingTags
|
||||
from spelltextedit import SpellTextEdit
|
||||
from settingsmanager import SettingsManager
|
||||
from plugin import PluginStatus, StringContent, Plugin
|
||||
from pluginmanager import PluginManager
|
||||
from settingstab import SettingsTab
|
||||
|
|
|
@ -229,25 +229,28 @@ class MediaManagerItem(QtGui.QWidget):
|
|||
create_widget_action(self.listView, separator=True)
|
||||
if self.hasDeleteIcon:
|
||||
create_widget_action(self.listView,
|
||||
u'listView%s%sItem' % (self.plugin.name.title(), StringContent.Delete.title()),
|
||||
text=self.plugin.getString(StringContent.Delete)[u'title'],
|
||||
icon=u':/general/general_delete.png',
|
||||
shortcuts=[QtCore.Qt.Key_Delete], triggers=self.onDeleteClick)
|
||||
can_shortcuts=True, triggers=self.onDeleteClick)
|
||||
create_widget_action(self.listView, separator=True)
|
||||
create_widget_action(self.listView,
|
||||
u'listView%s%sItem' % (self.plugin.name.title(), StringContent.Preview.title()),
|
||||
text=self.plugin.getString(StringContent.Preview)[u'title'],
|
||||
icon=u':/general/general_preview.png',
|
||||
shortcuts=[QtCore.Qt.Key_Enter, QtCore.Qt.Key_Return],
|
||||
can_shortcuts=True,
|
||||
triggers=self.onPreviewClick)
|
||||
create_widget_action(self.listView,
|
||||
u'listView%s%sItem' % (self.plugin.name.title(), StringContent.Live.title()),
|
||||
text=self.plugin.getString(StringContent.Live)[u'title'],
|
||||
icon=u':/general/general_live.png',
|
||||
shortcuts=[QtCore.Qt.ShiftModifier | QtCore.Qt.Key_Enter,
|
||||
QtCore.Qt.ShiftModifier | QtCore.Qt.Key_Return],
|
||||
can_shortcuts=True,
|
||||
triggers=self.onLiveClick)
|
||||
create_widget_action(self.listView,
|
||||
u'listView%s%sItem' % (self.plugin.name.title(), StringContent.Service.title()),
|
||||
can_shortcuts=True,
|
||||
text=self.plugin.getString(StringContent.Service)[u'title'],
|
||||
icon=u':/general/general_add.png',
|
||||
shortcuts=[QtCore.Qt.Key_Plus, QtCore.Qt.Key_Equal],
|
||||
triggers=self.onAddClick)
|
||||
if self.addToServiceItem:
|
||||
create_widget_action(self.listView, separator=True)
|
||||
|
|
|
@ -36,9 +36,8 @@ import sys
|
|||
|
||||
from PyQt4 import QtCore, QtGui
|
||||
|
||||
from openlp.core.lib import SlideLimits
|
||||
from openlp.core.lib import SlideLimits, UiStrings
|
||||
from openlp.core.lib.theme import ThemeLevel
|
||||
from openlp.core.lib import UiStrings
|
||||
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
@ -70,7 +69,8 @@ class Settings(QtCore.QSettings):
|
|||
``__obsolete_settings__``
|
||||
Each entry is structured in the following way::
|
||||
|
||||
(u'general/enable slide loop', u'advanced/slide limits', [(SlideLimits.Wrap, True), (SlideLimits.End, False)])
|
||||
(u'general/enable slide loop', u'advanced/slide limits',
|
||||
[(SlideLimits.Wrap, True), (SlideLimits.End, False)])
|
||||
|
||||
The first entry is the *old key*; it will be removed.
|
||||
|
||||
|
@ -152,42 +152,99 @@ class Settings(QtCore.QSettings):
|
|||
u'SettingsImport/type': u'OpenLP_settings_export',
|
||||
u'SettingsImport/version': u'',
|
||||
u'shortcuts/aboutItem': [QtGui.QKeySequence(u'Ctrl+F1')],
|
||||
u'shortcuts/addToService': [],
|
||||
u'shortcuts/audioPauseItem': [],
|
||||
u'shortcuts/displayTagItem': [],
|
||||
u'shortcuts/blankScreen': [QtCore.Qt.Key_Period],
|
||||
u'shortcuts/collapse': [QtCore.Qt.Key_Minus],
|
||||
u'shortcuts/blankScreen': [QtGui.QKeySequence(QtCore.Qt.Key_Period)],
|
||||
u'shortcuts/collapse': [QtGui.QKeySequence(QtCore.Qt.Key_Minus)],
|
||||
u'shortcuts/desktopScreen': [QtGui.QKeySequence(u'D')],
|
||||
u'shortcuts/down': [QtCore.Qt.Key_Down],
|
||||
u'shortcuts/escapeItem': [QtCore.Qt.Key_Escape],
|
||||
u'shortcuts/expand': [QtCore.Qt.Key_Plus],
|
||||
u'shortcuts/delete': [],
|
||||
u'shortcuts/down': [QtGui.QKeySequence(QtCore.Qt.Key_Down)],
|
||||
u'shortcuts/editSong': [],
|
||||
u'shortcuts/escapeItem': [QtGui.QKeySequence(QtCore.Qt.Key_Escape)],
|
||||
u'shortcuts/expand': [QtGui.QKeySequence(QtCore.Qt.Key_Plus)],
|
||||
u'shortcuts/exportThemeItem': [],
|
||||
u'shortcuts/fileNewItem': [QtGui.QKeySequence(u'Ctrl+N')],
|
||||
u'shortcuts/fileSaveAsItem': [QtGui.QKeySequence(u'Ctrl+Shift+S')],
|
||||
u'shortcuts/fileExitItem': [QtGui.QKeySequence(u'Alt+F4')],
|
||||
u'shortcuts/fileSaveItem': [QtGui.QKeySequence(u'Ctrl+S')],
|
||||
u'shortcuts/fileOpenItem': [QtGui.QKeySequence(u'Ctrl+O')],
|
||||
u'shortcuts/goLive': [],
|
||||
u'shortcuts/importThemeItem': [],
|
||||
u'shortcuts/importBibleItem': [],
|
||||
u'shortcuts/listViewBiblesDeleteItem': [QtGui.QKeySequence(QtCore.Qt.Key_Delete)],
|
||||
u'shortcuts/listViewBiblesPreviewItem': [QtGui.QKeySequence(QtCore.Qt.Key_Enter),
|
||||
QtGui.QKeySequence(QtCore.Qt.Key_Return)],
|
||||
u'shortcuts/listViewBiblesLiveItem': [QtGui.QKeySequence(QtCore.Qt.ShiftModifier | QtCore.Qt.Key_Enter),
|
||||
QtGui.QKeySequence(QtCore.Qt.ShiftModifier | QtCore.Qt.Key_Return)],
|
||||
u'shortcuts/listViewBiblesServiceItem': [QtGui.QKeySequence(QtCore.Qt.Key_Plus),
|
||||
QtGui.QKeySequence(QtCore.Qt.Key_Equal)],
|
||||
u'shortcuts/listViewCustomDeleteItem': [QtGui.QKeySequence(QtCore.Qt.Key_Delete)],
|
||||
u'shortcuts/listViewCustomPreviewItem': [QtGui.QKeySequence(QtCore.Qt.Key_Enter),
|
||||
QtGui.QKeySequence(QtCore.Qt.Key_Return)],
|
||||
u'shortcuts/listViewCustomLiveItem': [QtGui.QKeySequence(QtCore.Qt.ShiftModifier | QtCore.Qt.Key_Enter),
|
||||
QtGui.QKeySequence(QtCore.Qt.ShiftModifier | QtCore.Qt.Key_Return)],
|
||||
u'shortcuts/listViewCustomServiceItem': [QtGui.QKeySequence(QtCore.Qt.Key_Plus),
|
||||
QtGui.QKeySequence(QtCore.Qt.Key_Equal)],
|
||||
u'shortcuts/listViewImagesDeleteItem': [QtGui.QKeySequence(QtCore.Qt.Key_Delete)],
|
||||
u'shortcuts/listViewImagesPreviewItem': [QtGui.QKeySequence(QtCore.Qt.Key_Enter),
|
||||
QtGui.QKeySequence(QtCore.Qt.Key_Return)],
|
||||
u'shortcuts/listViewImagesLiveItem': [QtGui.QKeySequence(QtCore.Qt.ShiftModifier | QtCore.Qt.Key_Enter),
|
||||
QtGui.QKeySequence(QtCore.Qt.ShiftModifier | QtCore.Qt.Key_Return)],
|
||||
u'shortcuts/listViewImagesServiceItem': [QtGui.QKeySequence(QtCore.Qt.Key_Plus),
|
||||
QtGui.QKeySequence(QtCore.Qt.Key_Equal)],
|
||||
u'shortcuts/listViewMediaDeleteItem': [QtGui.QKeySequence(QtCore.Qt.Key_Delete)],
|
||||
u'shortcuts/listViewMediaPreviewItem': [QtGui.QKeySequence(QtCore.Qt.Key_Enter),
|
||||
QtGui.QKeySequence(QtCore.Qt.Key_Return)],
|
||||
u'shortcuts/listViewMediaLiveItem': [QtGui.QKeySequence(QtCore.Qt.ShiftModifier | QtCore.Qt.Key_Enter),
|
||||
QtGui.QKeySequence(QtCore.Qt.ShiftModifier | QtCore.Qt.Key_Return)],
|
||||
u'shortcuts/listViewMediaServiceItem': [QtGui.QKeySequence(QtCore.Qt.Key_Plus),
|
||||
QtGui.QKeySequence(QtCore.Qt.Key_Equal)],
|
||||
u'shortcuts/listViewPresentationsDeleteItem': [QtGui.QKeySequence(QtCore.Qt.Key_Delete)],
|
||||
u'shortcuts/listViewPresentationsPreviewItem': [QtGui.QKeySequence(QtCore.Qt.Key_Enter),
|
||||
QtGui.QKeySequence(QtCore.Qt.Key_Return)],
|
||||
u'shortcuts/listViewPresentationsLiveItem': [QtGui.QKeySequence(QtCore.Qt.ShiftModifier | QtCore.Qt.Key_Enter),
|
||||
QtGui.QKeySequence(QtCore.Qt.ShiftModifier | QtCore.Qt.Key_Return)],
|
||||
u'shortcuts/listViewPresentationsServiceItem': [QtGui.QKeySequence(QtCore.Qt.Key_Plus),
|
||||
QtGui.QKeySequence(QtCore.Qt.Key_Equal)],
|
||||
u'shortcuts/listViewSongsDeleteItem': [QtGui.QKeySequence(QtCore.Qt.Key_Delete)],
|
||||
u'shortcuts/listViewSongsPreviewItem': [QtGui.QKeySequence(QtCore.Qt.Key_Enter),
|
||||
QtGui.QKeySequence(QtCore.Qt.Key_Return)],
|
||||
u'shortcuts/listViewSongsLiveItem': [QtGui.QKeySequence(QtCore.Qt.ShiftModifier | QtCore.Qt.Key_Enter),
|
||||
QtGui.QKeySequence(QtCore.Qt.ShiftModifier | QtCore.Qt.Key_Return)],
|
||||
u'shortcuts/listViewSongsServiceItem': [QtGui.QKeySequence(QtCore.Qt.Key_Plus),
|
||||
QtGui.QKeySequence(QtCore.Qt.Key_Equal)],
|
||||
u'shortcuts/lockPanel': [],
|
||||
u'shortcuts/modeDefaultItem': [],
|
||||
u'shortcuts/modeLiveItem': [],
|
||||
u'shortcuts/make_live': [QtCore.Qt.Key_Enter, QtCore.Qt.Key_Return],
|
||||
u'shortcuts/moveUp': [QtCore.Qt.Key_PageUp],
|
||||
u'shortcuts/moveTop': [QtCore.Qt.Key_Home],
|
||||
u'shortcuts/make_live': [QtGui.QKeySequence(QtCore.Qt.Key_Enter), QtGui.QKeySequence(QtCore.Qt.Key_Return)],
|
||||
u'shortcuts/moveUp': [QtGui.QKeySequence(QtCore.Qt.Key_PageUp)],
|
||||
u'shortcuts/moveTop': [QtGui.QKeySequence(QtCore.Qt.Key_Home)],
|
||||
u'shortcuts/modeSetupItem': [],
|
||||
u'shortcuts/moveBottom': [QtCore.Qt.Key_End],
|
||||
u'shortcuts/moveDown': [QtCore.Qt.Key_PageDown],
|
||||
u'shortcuts/moveBottom': [QtGui.QKeySequence(QtCore.Qt.Key_End)],
|
||||
u'shortcuts/moveDown': [QtGui.QKeySequence(QtCore.Qt.Key_PageDown)],
|
||||
u'shortcuts/nextTrackItem': [],
|
||||
u'shortcuts/nextItem_live': [QtCore.Qt.Key_Down, QtCore.Qt.Key_PageDown],
|
||||
u'shortcuts/nextService': [QtCore.Qt.Key_Right],
|
||||
u'shortcuts/nextItem_live': [QtGui.QKeySequence(QtCore.Qt.Key_Down),
|
||||
QtGui.QKeySequence(QtCore.Qt.Key_PageDown)],
|
||||
u'shortcuts/nextItem_preview': [],
|
||||
u'shortcuts/nextService': [QtGui.QKeySequence(QtCore.Qt.Key_Right)],
|
||||
u'shortcuts/newService': [],
|
||||
u'shortcuts/offlineHelpItem': [],
|
||||
u'shortcuts/onlineHelpItem': [QtGui.QKeySequence(u'Alt+F1')],
|
||||
u'shortcuts/previousItem_live': [QtCore.Qt.Key_Up, QtCore.Qt.Key_PageUp],
|
||||
u'shortcuts/openService': [],
|
||||
u'shortcuts/saveService': [],
|
||||
u'shortcuts/previousItem_live': [QtGui.QKeySequence(QtCore.Qt.Key_Up),
|
||||
QtGui.QKeySequence(QtCore.Qt.Key_PageUp)],
|
||||
u'shortcuts/playbackPause': [],
|
||||
u'shortcuts/playbackPlay': [],
|
||||
u'shortcuts/playbackStop': [],
|
||||
u'shortcuts/playSlidesLoop': [],
|
||||
u'shortcuts/playSlidesOnce': [],
|
||||
u'shortcuts/previousService': [QtCore.Qt.Key_Left],
|
||||
u'shortcuts/previousService': [QtGui.QKeySequence(QtCore.Qt.Key_Left)],
|
||||
u'shortcuts/previousItem_preview': [],
|
||||
u'shortcuts/printServiceItem': [QtGui.QKeySequence(u'Ctrl+P')],
|
||||
u'shortcuts/songExportItem': [],
|
||||
u'shortcuts/songUsageStatus': [QtCore.Qt.Key_F4],
|
||||
u'shortcuts/songUsageStatus': [QtGui.QKeySequence(QtCore.Qt.Key_F4)],
|
||||
u'shortcuts/settingsShortcutsItem': [],
|
||||
u'shortcuts/settingsImportItem': [],
|
||||
u'shortcuts/settingsPluginListItem': [QtGui.QKeySequence(u'Alt+F7')],
|
||||
|
@ -200,18 +257,28 @@ class Settings(QtCore.QSettings):
|
|||
u'shortcuts/shortcutAction_O': [QtGui.QKeySequence(u'O')],
|
||||
u'shortcuts/shortcutAction_P': [QtGui.QKeySequence(u'P')],
|
||||
u'shortcuts/shortcutAction_V': [QtGui.QKeySequence(u'V')],
|
||||
u'shortcuts/shortcutAction_0': [QtGui.QKeySequence(u'0')],
|
||||
u'shortcuts/shortcutAction_1': [QtGui.QKeySequence(u'1')],
|
||||
u'shortcuts/shortcutAction_2': [QtGui.QKeySequence(u'2')],
|
||||
u'shortcuts/shortcutAction_3': [QtGui.QKeySequence(u'3')],
|
||||
u'shortcuts/shortcutAction_4': [QtGui.QKeySequence(u'4')],
|
||||
u'shortcuts/shortcutAction_5': [QtGui.QKeySequence(u'5')],
|
||||
u'shortcuts/shortcutAction_6': [QtGui.QKeySequence(u'6')],
|
||||
u'shortcuts/shortcutAction_7': [QtGui.QKeySequence(u'7')],
|
||||
u'shortcuts/shortcutAction_8': [QtGui.QKeySequence(u'8')],
|
||||
u'shortcuts/shortcutAction_9': [QtGui.QKeySequence(u'9')],
|
||||
u'shortcuts/settingsExportItem': [],
|
||||
u'shortcuts/songUsageReport': [],
|
||||
u'shortcuts/songImportItem': [],
|
||||
u'shortcuts/themeScreen': [QtGui.QKeySequence(u'T')],
|
||||
u'shortcuts/toolsReindexItem': [],
|
||||
u'shortcuts/toolsFindDuplicates': [],
|
||||
u'shortcuts/toolsAlertItem': [u'F7'],
|
||||
u'shortcuts/toolsAlertItem': [QtGui.QKeySequence(u'F7')],
|
||||
u'shortcuts/toolsFirstTimeWizard': [],
|
||||
u'shortcuts/toolsOpenDataFolder': [],
|
||||
u'shortcuts/toolsAddToolItem': [],
|
||||
u'shortcuts/updateThemeImages': [],
|
||||
u'shortcuts/up': [QtCore.Qt.Key_Up],
|
||||
u'shortcuts/up': [QtGui.QKeySequence(QtCore.Qt.Key_Up)],
|
||||
u'shortcuts/viewThemeManagerItem': [QtGui.QKeySequence(u'F10')],
|
||||
u'shortcuts/viewMediaManagerItem': [QtGui.QKeySequence(u'F8')],
|
||||
u'shortcuts/viewPreviewPanel': [QtGui.QKeySequence(u'F11')],
|
||||
|
@ -261,7 +328,6 @@ class Settings(QtCore.QSettings):
|
|||
"""
|
||||
Settings.__default_settings__ = dict(default_values.items() + Settings.__default_settings__.items())
|
||||
|
||||
|
||||
@staticmethod
|
||||
def set_filename(ini_file):
|
||||
"""
|
||||
|
@ -289,6 +355,14 @@ class Settings(QtCore.QSettings):
|
|||
else:
|
||||
QtCore.QSettings.__init__(self, *args)
|
||||
|
||||
def get_default_value(self, key):
|
||||
"""
|
||||
Get the default value of the given key
|
||||
"""
|
||||
if self.group():
|
||||
key = self.group() + u'/' + key
|
||||
return Settings.__default_settings__[key]
|
||||
|
||||
def remove_obsolete_settings(self):
|
||||
"""
|
||||
This method is only called to clean up the config. It removes old settings and it renames settings. See
|
||||
|
|
|
@ -1,66 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
|
||||
|
||||
###############################################################################
|
||||
# OpenLP - Open Source Lyrics Projection #
|
||||
# --------------------------------------------------------------------------- #
|
||||
# Copyright (c) 2008-2013 Raoul Snyman #
|
||||
# Portions copyright (c) 2008-2013 Tim Bentley, Gerald Britton, Jonathan #
|
||||
# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, #
|
||||
# Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer. #
|
||||
# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru, #
|
||||
# Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, #
|
||||
# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Dave Warnock, #
|
||||
# Frode Woldsund, Martin Zibricky, Patrick Zimmermann #
|
||||
# --------------------------------------------------------------------------- #
|
||||
# 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 #
|
||||
###############################################################################
|
||||
"""
|
||||
Provide handling for persisting OpenLP settings. OpenLP uses QSettings to manage settings persistence. QSettings
|
||||
provides a single API for saving and retrieving settings from the application but writes to disk in an OS dependant
|
||||
format.
|
||||
"""
|
||||
import os
|
||||
|
||||
from openlp.core.utils import AppLocation
|
||||
|
||||
|
||||
class SettingsManager(object):
|
||||
"""
|
||||
Class to provide helper functions for the loading and saving of application settings.
|
||||
"""
|
||||
|
||||
@staticmethod
|
||||
def get_files(section=None, extension=None):
|
||||
"""
|
||||
Get a list of files from the data files path.
|
||||
|
||||
``section``
|
||||
Defaults to *None*. The section of code getting the files - used to load from a section's data subdirectory.
|
||||
|
||||
``extension``
|
||||
Defaults to *None*. The extension to search for.
|
||||
"""
|
||||
path = AppLocation.get_data_path()
|
||||
if section:
|
||||
path = os.path.join(path, section)
|
||||
try:
|
||||
files = os.listdir(path)
|
||||
except OSError:
|
||||
return []
|
||||
if extension:
|
||||
return [filename for filename in files if extension == os.path.splitext(filename)[1]]
|
||||
else:
|
||||
# no filtering required
|
||||
return files
|
|
@ -69,9 +69,8 @@ def add_welcome_page(parent, image):
|
|||
|
||||
def create_button_box(dialog, name, standard_buttons, custom_buttons=None):
|
||||
"""
|
||||
Creates a QDialogButtonBox with the given buttons. The ``accepted()`` and
|
||||
``rejected()`` signals of the button box are connected with the dialogs
|
||||
``accept()`` and ``reject()`` slots.
|
||||
Creates a QDialogButtonBox with the given buttons. The ``accepted()`` and ``rejected()`` signals of the button box
|
||||
are connected with the dialogs ``accept()`` and ``reject()`` slots.
|
||||
|
||||
``dialog``
|
||||
The parent object. This has to be a ``QDialog`` descendant.
|
||||
|
@ -80,13 +79,12 @@ def create_button_box(dialog, name, standard_buttons, custom_buttons=None):
|
|||
A string which is set as object name.
|
||||
|
||||
``standard_buttons``
|
||||
A list of strings for the used buttons. It might contain: ``ok``,
|
||||
``save``, ``cancel``, ``close``, and ``defaults``.
|
||||
A list of strings for the used buttons. It might contain: ``ok``, ``save``, ``cancel``, ``close``, and
|
||||
``defaults``.
|
||||
|
||||
``custom_buttons``
|
||||
A list of additional buttons. If a item is a instance of
|
||||
QtGui.QAbstractButton it is added with QDialogButtonBox.ActionRole.
|
||||
Otherwhise the item has to be a tuple of a button and a ButtonRole.
|
||||
A list of additional buttons. If a item is a instance of QtGui.QAbstractButton it is added with
|
||||
QDialogButtonBox.ActionRole. Otherwhise the item has to be a tuple of a button and a ButtonRole.
|
||||
"""
|
||||
if custom_buttons is None:
|
||||
custom_buttons = []
|
||||
|
@ -109,15 +107,14 @@ def create_button_box(dialog, name, standard_buttons, custom_buttons=None):
|
|||
button_box.addButton(button, QtGui.QDialogButtonBox.ActionRole)
|
||||
else:
|
||||
button_box.addButton(*button)
|
||||
QtCore.QObject.connect(button_box, QtCore.SIGNAL(u'accepted()'), dialog.accept)
|
||||
QtCore.QObject.connect(button_box, QtCore.SIGNAL(u'rejected()'), dialog.reject)
|
||||
button_box.accepted.connect(dialog.accept)
|
||||
button_box.rejected.connect(dialog.reject)
|
||||
return button_box
|
||||
|
||||
|
||||
def critical_error_message_box(title=None, message=None, parent=None, question=False):
|
||||
"""
|
||||
Provides a standard critical message box for errors that OpenLP displays
|
||||
to users.
|
||||
Provides a standard critical message box for errors that OpenLP displays to users.
|
||||
|
||||
``title``
|
||||
The title for the message box.
|
||||
|
@ -134,7 +131,6 @@ def critical_error_message_box(title=None, message=None, parent=None, question=F
|
|||
if question:
|
||||
return QtGui.QMessageBox.critical(parent, UiStrings().Error, message,
|
||||
QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Yes | QtGui.QMessageBox.No))
|
||||
data = {u'message': message}
|
||||
return Registry().get(u'main_window').error_message(title if title else UiStrings().Error, message)
|
||||
|
||||
|
||||
|
@ -166,16 +162,14 @@ def create_button(parent, name, **kwargs):
|
|||
A string which is set as object name (required).
|
||||
|
||||
``role``
|
||||
A string which can have one value out of ``delete``, ``up``, and
|
||||
``down``. This decides about default values for properties like text,
|
||||
icon, or tooltip.
|
||||
A string which can have one value out of ``delete``, ``up``, and ``down``. This decides about default values
|
||||
for properties like text, icon, or tooltip.
|
||||
|
||||
``text``
|
||||
A string for the action text.
|
||||
|
||||
``icon``
|
||||
Either a QIcon, a resource string, or a file location string for the
|
||||
action icon.
|
||||
Either a QIcon, a resource string, or a file location string for the action icon.
|
||||
|
||||
``tooltip``
|
||||
A string for the action tool tip.
|
||||
|
@ -195,8 +189,7 @@ def create_button(parent, name, **kwargs):
|
|||
kwargs.setdefault(u'icon', u':/services/service_down.png')
|
||||
kwargs.setdefault(u'tooltip', translate('OpenLP.Ui', 'Move selection down one position.'))
|
||||
else:
|
||||
log.warn(u'The role "%s" is not defined in create_push_button().',
|
||||
role)
|
||||
log.warn(u'The role "%s" is not defined in create_push_button().', role)
|
||||
if kwargs.pop(u'class', u'') == u'toolbutton':
|
||||
button = QtGui.QToolButton(parent)
|
||||
else:
|
||||
|
@ -211,7 +204,7 @@ def create_button(parent, name, **kwargs):
|
|||
if not kwargs.pop(u'enabled', True):
|
||||
button.setEnabled(False)
|
||||
if kwargs.get(u'click'):
|
||||
QtCore.QObject.connect(button, QtCore.SIGNAL(u'clicked()'), kwargs.pop(u'click'))
|
||||
button.clicked.connect(kwargs.pop(u'click'))
|
||||
for key in kwargs.keys():
|
||||
if key not in [u'text', u'icon', u'tooltip', u'click']:
|
||||
log.warn(u'Parameter %s was not consumed in create_button().', key)
|
||||
|
@ -256,8 +249,10 @@ def create_action(parent, name, **kwargs):
|
|||
``data``
|
||||
The action's data.
|
||||
|
||||
``shortcuts``
|
||||
A QList<QKeySequence> (or a list of strings) which are set as shortcuts.
|
||||
``can_shortcuts``
|
||||
Capability stating if this action can have shortcuts. If ``True`` the action is added to shortcut dialog
|
||||
otherwise it it not. Define your shortcut in the :class:`~openlp.core.lib.Settings` class. *Note*: When *not*
|
||||
``True`` you *must not* set a shortcuts at all.
|
||||
|
||||
``context``
|
||||
A context for the shortcut execution.
|
||||
|
@ -289,27 +284,24 @@ def create_action(parent, name, **kwargs):
|
|||
action.setSeparator(True)
|
||||
if u'data' in kwargs:
|
||||
action.setData(kwargs.pop(u'data'))
|
||||
if kwargs.get(u'shortcuts'):
|
||||
action.setShortcuts(kwargs.pop(u'shortcuts'))
|
||||
if kwargs.pop(u'can_shortcuts', False):
|
||||
action_list = ActionList.get_instance()
|
||||
action_list.add_action(action, kwargs.pop(u'category', None))
|
||||
if u'context' in kwargs:
|
||||
action.setShortcutContext(kwargs.pop(u'context'))
|
||||
if kwargs.get(u'category'):
|
||||
action_list = ActionList.get_instance()
|
||||
action_list.add_action(action, unicode(kwargs.pop(u'category')))
|
||||
if kwargs.get(u'triggers'):
|
||||
QtCore.QObject.connect(action, QtCore.SIGNAL(u'triggered(bool)'),
|
||||
kwargs.pop(u'triggers'))
|
||||
action.triggered.connect(kwargs.pop(u'triggers'))
|
||||
for key in kwargs.keys():
|
||||
if key not in [u'text', u'icon', u'tooltip', u'statustip', u'checked', u'shortcuts', u'category', u'triggers']:
|
||||
if key not in [u'text', u'icon', u'tooltip', u'statustip', u'checked', u'can_shortcuts',
|
||||
u'category', u'triggers']:
|
||||
log.warn(u'Parameter %s was not consumed in create_action().', key)
|
||||
return action
|
||||
|
||||
|
||||
def create_widget_action(parent, name=u'', **kwargs):
|
||||
"""
|
||||
Return a new QAction by calling ``create_action(parent, name, **kwargs)``.
|
||||
The shortcut context defaults to ``QtCore.Qt.WidgetShortcut`` and the action
|
||||
is added to the parents action list.
|
||||
Return a new QAction by calling ``create_action(parent, name, **kwargs)``. The shortcut context defaults to
|
||||
``QtCore.Qt.WidgetShortcut`` and the action is added to the parents action list.
|
||||
"""
|
||||
kwargs.setdefault(u'context', QtCore.Qt.WidgetShortcut)
|
||||
action = create_action(parent, name, **kwargs)
|
||||
|
@ -334,8 +326,7 @@ def set_case_insensitive_completer(cache, widget):
|
|||
|
||||
def create_valign_selection_widgets(parent):
|
||||
"""
|
||||
Creates a standard label and combo box for asking users to select a
|
||||
vertical alignment.
|
||||
Creates a standard label and combo box for asking users to select a vertical alignment.
|
||||
|
||||
``parent``
|
||||
The parent object. This should be a ``QWidget`` descendant.
|
||||
|
|
|
@ -106,7 +106,7 @@ class ExceptionForm(QtGui.QDialog, Ui_ExceptionDialog):
|
|||
"""
|
||||
QtGui.QDialog.__init__(self, parent)
|
||||
self.setupUi(self)
|
||||
self.settingsSection = u'crashreport'
|
||||
self.settings_section = u'crashreport'
|
||||
|
||||
def exec_(self):
|
||||
"""
|
||||
|
@ -159,12 +159,11 @@ class ExceptionForm(QtGui.QDialog, Ui_ExceptionDialog):
|
|||
'--- Library Versions ---\n%s\n')
|
||||
filename = QtGui.QFileDialog.getSaveFileName(self,
|
||||
translate('OpenLP.ExceptionForm', 'Save Crash Report'),
|
||||
Settings().value(self.settingsSection + u'/last directory'),
|
||||
translate('OpenLP.ExceptionForm',
|
||||
'Text files (*.txt *.log *.text)'))
|
||||
Settings().value(self.settings_section + u'/last directory'),
|
||||
translate('OpenLP.ExceptionForm', 'Text files (*.txt *.log *.text)'))
|
||||
if filename:
|
||||
filename = unicode(filename).replace(u'/', os.path.sep)
|
||||
Settings().setValue(self.settingsSection + u'/last directory', os.path.dirname(filename))
|
||||
Settings().setValue(self.settings_section + u'/last directory', os.path.dirname(filename))
|
||||
report_text = report_text % self._createReport()
|
||||
try:
|
||||
report_file = open(filename, u'w')
|
||||
|
@ -230,7 +229,7 @@ class ExceptionForm(QtGui.QDialog, Ui_ExceptionDialog):
|
|||
"""
|
||||
files = QtGui.QFileDialog.getOpenFileName(
|
||||
self, translate('ImagePlugin.ExceptionDialog', 'Select Attachment'),
|
||||
Settings().value(self.settingsSection + u'/last directory'), u'%s (*.*) (*)' % UiStrings().AllFiles)
|
||||
Settings().value(self.settings_section + u'/last directory'), u'%s (*.*) (*)' % UiStrings().AllFiles)
|
||||
log.info(u'New files(s) %s', unicode(files))
|
||||
if files:
|
||||
self.fileAttachment = unicode(files)
|
||||
|
|
|
@ -300,7 +300,7 @@ class MainDisplay(Display):
|
|||
self.image(path)
|
||||
# Update the preview frame.
|
||||
if self.isLive:
|
||||
self.parent().updatePreview()
|
||||
self.live_controller.updatePreview()
|
||||
return True
|
||||
|
||||
def image(self, path):
|
||||
|
@ -513,6 +513,16 @@ class MainDisplay(Display):
|
|||
|
||||
application = property(_get_application)
|
||||
|
||||
def _get_live_controller(self):
|
||||
"""
|
||||
Adds the live controller to the class dynamically
|
||||
"""
|
||||
if not hasattr(self, u'_live_controller'):
|
||||
self._live_controller = Registry().get(u'live_controller')
|
||||
return self._live_controller
|
||||
|
||||
live_controller = property(_get_live_controller)
|
||||
|
||||
|
||||
class AudioPlayer(QtCore.QObject):
|
||||
"""
|
||||
|
|
|
@ -174,99 +174,101 @@ class Ui_MainWindow(object):
|
|||
main_window.addDockWidget(QtCore.Qt.RightDockWidgetArea, self.themeManagerDock)
|
||||
# Create the menu items
|
||||
action_list = ActionList.get_instance()
|
||||
action_list.add_category(UiStrings().File, CategoryOrder.standardMenu)
|
||||
action_list.add_category(UiStrings().File, CategoryOrder.standard_menu)
|
||||
self.fileNewItem = create_action(main_window, u'fileNewItem',
|
||||
icon=u':/general/general_new.png',
|
||||
shortcuts=[QtGui.QKeySequence(u'Ctrl+N')],
|
||||
can_shortcuts=True,
|
||||
category=UiStrings().File,
|
||||
triggers=self.serviceManagerContents.on_new_service_clicked)
|
||||
self.fileOpenItem = create_action(main_window, u'fileOpenItem',
|
||||
icon=u':/general/general_open.png',
|
||||
shortcuts=[QtGui.QKeySequence(u'Ctrl+O')],
|
||||
can_shortcuts=True,
|
||||
category=UiStrings().File,
|
||||
triggers=self.serviceManagerContents.on_load_service_clicked)
|
||||
self.fileSaveItem = create_action(main_window, u'fileSaveItem',
|
||||
icon=u':/general/general_save.png',
|
||||
shortcuts=[QtGui.QKeySequence(u'Ctrl+S')],
|
||||
can_shortcuts=True,
|
||||
category=UiStrings().File,
|
||||
triggers=self.serviceManagerContents.save_file)
|
||||
self.fileSaveAsItem = create_action(main_window, u'fileSaveAsItem',
|
||||
shortcuts=[QtGui.QKeySequence(u'Ctrl+Shift+S')],
|
||||
can_shortcuts=True,
|
||||
category=UiStrings().File,
|
||||
triggers=self.serviceManagerContents.save_file_as)
|
||||
self.printServiceOrderItem = create_action(main_window,
|
||||
u'printServiceItem', shortcuts=[QtGui.QKeySequence(u'Ctrl+P')],
|
||||
u'printServiceItem', can_shortcuts=True,
|
||||
category=UiStrings().File,
|
||||
triggers=self.serviceManagerContents.print_service_order)
|
||||
self.fileExitItem = create_action(main_window, u'fileExitItem',
|
||||
icon=u':/system/system_exit.png',
|
||||
shortcuts=[QtGui.QKeySequence(u'Alt+F4')],
|
||||
can_shortcuts=True,
|
||||
category=UiStrings().File, triggers=main_window.close)
|
||||
# Give QT Extra Hint that this is the Exit Menu Item
|
||||
self.fileExitItem.setMenuRole(QtGui.QAction.QuitRole)
|
||||
action_list.add_category(UiStrings().Import, CategoryOrder.standardMenu)
|
||||
self.importThemeItem = create_action(main_window, u'importThemeItem', category=UiStrings().Import)
|
||||
action_list.add_category(UiStrings().Import, CategoryOrder.standard_menu)
|
||||
self.importThemeItem = create_action(
|
||||
main_window, u'importThemeItem', category=UiStrings().Import, can_shortcuts=True)
|
||||
self.importLanguageItem = create_action(main_window, u'importLanguageItem')
|
||||
action_list.add_category(UiStrings().Export, CategoryOrder.standardMenu)
|
||||
self.exportThemeItem = create_action(main_window, u'exportThemeItem', category=UiStrings().Export)
|
||||
action_list.add_category(UiStrings().Export, CategoryOrder.standard_menu)
|
||||
self.exportThemeItem = create_action(
|
||||
main_window, u'exportThemeItem', category=UiStrings().Export, can_shortcuts=True)
|
||||
self.exportLanguageItem = create_action(main_window, u'exportLanguageItem')
|
||||
action_list.add_category(UiStrings().View, CategoryOrder.standardMenu)
|
||||
action_list.add_category(UiStrings().View, CategoryOrder.standard_menu)
|
||||
self.viewMediaManagerItem = create_action(main_window,
|
||||
u'viewMediaManagerItem', shortcuts=[QtGui.QKeySequence(u'F8')],
|
||||
u'viewMediaManagerItem',
|
||||
icon=u':/system/system_mediamanager.png',
|
||||
checked=self.mediaManagerDock.isVisible(),
|
||||
can_shortcuts=True,
|
||||
category=UiStrings().View, triggers=self.toggleMediaManager)
|
||||
self.viewThemeManagerItem = create_action(main_window,
|
||||
u'viewThemeManagerItem', shortcuts=[QtGui.QKeySequence(u'F10')],
|
||||
u'viewThemeManagerItem', can_shortcuts=True,
|
||||
icon=u':/system/system_thememanager.png',
|
||||
checked=self.themeManagerDock.isVisible(),
|
||||
category=UiStrings().View, triggers=self.toggleThemeManager)
|
||||
self.viewServiceManagerItem = create_action(main_window,
|
||||
u'viewServiceManagerItem', shortcuts=[QtGui.QKeySequence(u'F9')],
|
||||
u'viewServiceManagerItem', can_shortcuts=True,
|
||||
icon=u':/system/system_servicemanager.png',
|
||||
checked=self.serviceManagerDock.isVisible(),
|
||||
category=UiStrings().View, triggers=self.toggleServiceManager)
|
||||
self.viewPreviewPanel = create_action(main_window, u'viewPreviewPanel',
|
||||
shortcuts=[QtGui.QKeySequence(u'F11')], checked=previewVisible,
|
||||
can_shortcuts=True, checked=previewVisible,
|
||||
category=UiStrings().View, triggers=self.setPreviewPanelVisibility)
|
||||
self.viewLivePanel = create_action(main_window, u'viewLivePanel',
|
||||
shortcuts=[QtGui.QKeySequence(u'F12')], checked=liveVisible,
|
||||
can_shortcuts=True, checked=liveVisible,
|
||||
category=UiStrings().View, triggers=self.setLivePanelVisibility)
|
||||
self.lockPanel = create_action(main_window, u'lockPanel',
|
||||
checked=panelLocked, triggers=self.setLockPanel)
|
||||
action_list.add_category(UiStrings().ViewMode,
|
||||
CategoryOrder.standardMenu)
|
||||
self.modeDefaultItem = create_action(main_window, u'modeDefaultItem', checked=False,
|
||||
category=UiStrings().ViewMode)
|
||||
self.modeSetupItem = create_action(main_window, u'modeSetupItem', checked=False, category=UiStrings().ViewMode)
|
||||
self.modeLiveItem = create_action(main_window, u'modeLiveItem', checked=True, category=UiStrings().ViewMode)
|
||||
can_shortcuts=True, checked=panelLocked,
|
||||
category=UiStrings().View,
|
||||
triggers=self.setLockPanel)
|
||||
action_list.add_category(UiStrings().ViewMode, CategoryOrder.standard_menu)
|
||||
self.modeDefaultItem = create_action(
|
||||
main_window, u'modeDefaultItem', checked=False, category=UiStrings().ViewMode, can_shortcuts=True)
|
||||
self.modeSetupItem = create_action(
|
||||
main_window, u'modeSetupItem', checked=False, category=UiStrings().ViewMode, can_shortcuts=True)
|
||||
self.modeLiveItem = create_action(
|
||||
main_window, u'modeLiveItem', checked=True, category=UiStrings().ViewMode, can_shortcuts=True)
|
||||
self.modeGroup = QtGui.QActionGroup(main_window)
|
||||
self.modeGroup.addAction(self.modeDefaultItem)
|
||||
self.modeGroup.addAction(self.modeSetupItem)
|
||||
self.modeGroup.addAction(self.modeLiveItem)
|
||||
self.modeDefaultItem.setChecked(True)
|
||||
action_list.add_category(UiStrings().Tools, CategoryOrder.standardMenu)
|
||||
action_list.add_category(UiStrings().Tools, CategoryOrder.standard_menu)
|
||||
self.toolsAddToolItem = create_action(main_window,
|
||||
u'toolsAddToolItem', icon=u':/tools/tools_add.png',
|
||||
category=UiStrings().Tools)
|
||||
u'toolsAddToolItem', icon=u':/tools/tools_add.png', category=UiStrings().Tools, can_shortcuts=True)
|
||||
self.toolsOpenDataFolder = create_action(main_window,
|
||||
u'toolsOpenDataFolder', icon=u':/general/general_open.png',
|
||||
category=UiStrings().Tools)
|
||||
u'toolsOpenDataFolder', icon=u':/general/general_open.png', category=UiStrings().Tools, can_shortcuts=True)
|
||||
self.toolsFirstTimeWizard = create_action(main_window,
|
||||
u'toolsFirstTimeWizard', icon=u':/general/general_revert.png',
|
||||
category=UiStrings().Tools)
|
||||
category=UiStrings().Tools, can_shortcuts=True)
|
||||
self.updateThemeImages = create_action(main_window,
|
||||
u'updateThemeImages', category=UiStrings().Tools)
|
||||
action_list.add_category(UiStrings().Settings,
|
||||
CategoryOrder.standardMenu)
|
||||
u'updateThemeImages', category=UiStrings().Tools, can_shortcuts=True)
|
||||
action_list.add_category(UiStrings().Settings, CategoryOrder.standard_menu)
|
||||
self.settingsPluginListItem = create_action(main_window,
|
||||
u'settingsPluginListItem',
|
||||
icon=u':/system/settings_plugin_list.png',
|
||||
shortcuts=[QtGui.QKeySequence(u'Alt+F7')],
|
||||
can_shortcuts=True,
|
||||
category=UiStrings().Settings, triggers=self.onPluginItemClicked)
|
||||
# i18n Language Items
|
||||
self.autoLanguageItem = create_action(main_window, u'autoLanguageItem',
|
||||
checked=LanguageManager.auto_language)
|
||||
self.autoLanguageItem = create_action(main_window, u'autoLanguageItem', checked=LanguageManager.auto_language)
|
||||
self.languageGroup = QtGui.QActionGroup(main_window)
|
||||
self.languageGroup.setExclusive(True)
|
||||
self.languageGroup.setObjectName(u'languageGroup')
|
||||
|
@ -277,20 +279,21 @@ class Ui_MainWindow(object):
|
|||
languageItem = create_action(main_window, key, checked=qmList[key] == savedLanguage)
|
||||
add_actions(self.languageGroup, [languageItem])
|
||||
self.settingsShortcutsItem = create_action(main_window, u'settingsShortcutsItem',
|
||||
icon=u':/system/system_configure_shortcuts.png', category=UiStrings().Settings)
|
||||
icon=u':/system/system_configure_shortcuts.png', category=UiStrings().Settings, can_shortcuts=True)
|
||||
# Formatting Tags were also known as display tags.
|
||||
self.formattingTagItem = create_action(main_window, u'displayTagItem',
|
||||
icon=u':/system/tag_editor.png', category=UiStrings().Settings)
|
||||
icon=u':/system/tag_editor.png', category=UiStrings().Settings, can_shortcuts=True)
|
||||
self.settingsConfigureItem = create_action(main_window, u'settingsConfigureItem',
|
||||
icon=u':/system/system_settings.png', category=UiStrings().Settings)
|
||||
icon=u':/system/system_settings.png', can_shortcuts=True, category=UiStrings().Settings)
|
||||
# Give QT Extra Hint that this is the Preferences Menu Item
|
||||
self.settingsConfigureItem.setMenuRole(QtGui.QAction.PreferencesRole)
|
||||
self.settingsImportItem = create_action(main_window, u'settingsImportItem', category=UiStrings().Settings)
|
||||
self.settingsExportItem = create_action(main_window, u'settingsExportItem', category=UiStrings().Settings)
|
||||
action_list.add_category(UiStrings().Help, CategoryOrder.standardMenu)
|
||||
self.settingsImportItem = create_action(
|
||||
main_window, u'settingsImportItem', category=UiStrings().Import, can_shortcuts=True)
|
||||
self.settingsExportItem = create_action(
|
||||
main_window, u'settingsExportItem', category=UiStrings().Export, can_shortcuts=True)
|
||||
action_list.add_category(UiStrings().Help, CategoryOrder.standard_menu)
|
||||
self.aboutItem = create_action(main_window, u'aboutItem', icon=u':/system/system_about.png',
|
||||
shortcuts=[QtGui.QKeySequence(u'Ctrl+F1')],
|
||||
category=UiStrings().Help, triggers=self.onAboutItemClicked)
|
||||
can_shortcuts=True, category=UiStrings().Help, triggers=self.onAboutItemClicked)
|
||||
# Give QT Extra Hint that this is an About Menu Item
|
||||
self.aboutItem.setMenuRole(QtGui.QAction.AboutRole)
|
||||
if os.name == u'nt':
|
||||
|
@ -298,13 +301,13 @@ class Ui_MainWindow(object):
|
|||
AppLocation.get_directory(AppLocation.AppDir), 'OpenLP.chm')
|
||||
self.offlineHelpItem = create_action(main_window, u'offlineHelpItem',
|
||||
icon=u':/system/system_help_contents.png',
|
||||
shortcuts=[QtGui.QKeySequence(u'F1')],
|
||||
can_shortcuts=True,
|
||||
category=UiStrings().Help, triggers=self.onOfflineHelpClicked)
|
||||
self.onlineHelpItem = create_action(main_window, u'onlineHelpItem',
|
||||
icon=u':/system/system_online_help.png',
|
||||
shortcuts=[QtGui.QKeySequence(u'Alt+F1')],
|
||||
can_shortcuts=True,
|
||||
category=UiStrings().Help, triggers=self.onOnlineHelpClicked)
|
||||
self.webSiteItem = create_action(main_window, u'webSiteItem', category=UiStrings().Help)
|
||||
self.webSiteItem = create_action(main_window, u'webSiteItem', can_shortcuts=True, category=UiStrings().Help)
|
||||
add_actions(self.fileImportMenu, (self.settingsImportItem, None, self.importThemeItem, self.importLanguageItem))
|
||||
add_actions(self.fileExportMenu, (self.settingsExportItem, None, self.exportThemeItem, self.exportLanguageItem))
|
||||
add_actions(self.fileMenu, (self.fileNewItem, self.fileOpenItem,
|
||||
|
@ -1349,7 +1352,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
|
|||
self.version_text)
|
||||
else:
|
||||
# the thread has not confirmed it is running or it has not yet sent any data so lets keep waiting
|
||||
if not hasattr(self,u'version_update_running') or self.version_update_running:
|
||||
if not hasattr(self, u'version_update_running') or self.version_update_running:
|
||||
self.timer_version_id = self.startTimer(1000)
|
||||
self.application.process_events()
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
# Python ctypes bindings for VLC
|
||||
#
|
||||
# Copyright (C) 2009-2013 the VideoLAN team
|
||||
# Copyright (C) 2009-2012 the VideoLAN team
|
||||
# $Id: $
|
||||
#
|
||||
# Authors: Olivier Aubert <olivier.aubert at liris.cnrs.fr>
|
||||
|
@ -48,7 +48,7 @@ import sys
|
|||
from inspect import getargspec
|
||||
|
||||
__version__ = "N/A"
|
||||
build_date = "Fri Oct 5 21:35:59 2012"
|
||||
build_date = "Wed Feb 13 18:40:24 2013"
|
||||
|
||||
if sys.version_info[0] > 2:
|
||||
str = str
|
||||
|
@ -1000,6 +1000,50 @@ class MediaTrackInfo(_Cstruct):
|
|||
('rate_or_width', ctypes.c_uint ),
|
||||
]
|
||||
|
||||
class AudioTrack(_Cstruct):
|
||||
_fields_ = [
|
||||
('channels', ctypes.c_uint),
|
||||
('rate', ctypes.c_uint),
|
||||
]
|
||||
|
||||
class VideoTrack(_Cstruct):
|
||||
_fields_ = [
|
||||
('height', ctypes.c_uint),
|
||||
('width', ctypes.c_uint),
|
||||
('sar_num', ctypes.c_uint),
|
||||
('sar_den', ctypes.c_uint),
|
||||
('frame_rate_num', ctypes.c_uint),
|
||||
('frame_rate_den', ctypes.c_uint),
|
||||
]
|
||||
|
||||
class SubtitleTrack(_Cstruct):
|
||||
_fields_ = [
|
||||
('encoding', ctypes.c_char_p),
|
||||
]
|
||||
|
||||
class MediaTrackTracks(ctypes.Union):
|
||||
_fields_ = [
|
||||
('audio', ctypes.POINTER(AudioTrack)),
|
||||
('video', ctypes.POINTER(VideoTrack)),
|
||||
('subtitle', ctypes.POINTER(SubtitleTrack)),
|
||||
]
|
||||
|
||||
class MediaTrack(_Cstruct):
|
||||
_anonymous_ = ("u",)
|
||||
_fields_ = [
|
||||
('codec', ctypes.c_uint32),
|
||||
('original_fourcc', ctypes.c_uint32),
|
||||
('id', ctypes.c_int ),
|
||||
('type', TrackType ),
|
||||
('profile', ctypes.c_int ),
|
||||
('level', ctypes.c_int ),
|
||||
|
||||
('u', MediaTrackTracks),
|
||||
('bitrate', ctypes.c_uint),
|
||||
('language', ctypes.c_char_p),
|
||||
('description', ctypes.c_char_p),
|
||||
]
|
||||
|
||||
class PlaylistItem(_Cstruct):
|
||||
_fields_ = [
|
||||
('id', ctypes.c_int ),
|
||||
|
@ -1122,6 +1166,17 @@ def module_description_list(head):
|
|||
libvlc_module_description_list_release(head)
|
||||
return r
|
||||
|
||||
class AudioOutputDevice(_Cstruct):
|
||||
|
||||
def __str__(self):
|
||||
return '%s(%d:%s)' % (self.__class__.__name__, self.id, self.name)
|
||||
|
||||
AudioOutputDevice._fields_ = [ # recursive struct
|
||||
('next', ctypes.POINTER(AudioOutputDevice)),
|
||||
('device', ctypes.c_char_p ),
|
||||
('description', ctypes.c_char_p),
|
||||
]
|
||||
|
||||
# End of header.py #
|
||||
|
||||
class EventManager(_Ctype):
|
||||
|
@ -1282,7 +1337,7 @@ class Instance(_Ctype):
|
|||
m = libvlc_media_new_location(self, str_to_bytes(mrl))
|
||||
else:
|
||||
# Else it should be a local path.
|
||||
m = libvlc_media_new_path(self, str_to_bytes(mrl))
|
||||
m = libvlc_media_new_path(self, str_to_bytes(os.path.normpath(mrl)))
|
||||
for o in options:
|
||||
libvlc_media_add_option(m, str_to_bytes(o))
|
||||
m._instance = self
|
||||
|
@ -1361,27 +1416,6 @@ class Instance(_Ctype):
|
|||
'''
|
||||
return libvlc_set_user_agent(self, name, http)
|
||||
|
||||
def get_log_verbosity(self):
|
||||
'''Always returns minus one.
|
||||
This function is only provided for backward compatibility.
|
||||
@return: always -1.
|
||||
'''
|
||||
return libvlc_get_log_verbosity(self)
|
||||
|
||||
def set_log_verbosity(self, level):
|
||||
'''This function does nothing.
|
||||
It is only provided for backward compatibility.
|
||||
@param level: ignored.
|
||||
'''
|
||||
return libvlc_set_log_verbosity(self, level)
|
||||
|
||||
def log_open(self):
|
||||
'''This function does nothing useful.
|
||||
It is only provided for backward compatibility.
|
||||
@return: an unique pointer or NULL on error.
|
||||
'''
|
||||
return libvlc_log_open(self)
|
||||
|
||||
def media_new_location(self, psz_mrl):
|
||||
'''Create a media with a certain given media resource location,
|
||||
for instance a valid URL.
|
||||
|
@ -1445,34 +1479,26 @@ class Instance(_Ctype):
|
|||
return libvlc_media_library_new(self)
|
||||
|
||||
def audio_output_list_get(self):
|
||||
'''Get the list of available audio outputs.
|
||||
'''Gets the list of available audio outputs.
|
||||
@return: list of available audio outputs. It must be freed it with In case of error, NULL is returned.
|
||||
'''
|
||||
return libvlc_audio_output_list_get(self)
|
||||
|
||||
def audio_output_device_count(self, psz_audio_output):
|
||||
'''Get count of devices for audio output, these devices are hardware oriented
|
||||
like analor or digital output of sound card.
|
||||
@param psz_audio_output: - name of audio output, See L{AudioOutput}.
|
||||
@return: number of devices.
|
||||
def audio_output_device_list_get(self, aout):
|
||||
'''Gets a list of audio output devices for a given audio output.
|
||||
See L{audio_output_device_set}().
|
||||
@note: Not all audio outputs support this. In particular, an empty (NULL)
|
||||
list of devices does B{not} imply that the specified audio output does
|
||||
not work.
|
||||
@note: The list might not be exhaustive.
|
||||
@warning: Some audio output devices in the list might not actually work in
|
||||
some circumstances. By default, it is recommended to not specify any
|
||||
explicit audio device.
|
||||
@param psz_aout: audio output name (as returned by L{audio_output_list_get}()).
|
||||
@return: A NULL-terminated linked list of potential audio output devices. It must be freed it with L{audio_output_device_list_release}().
|
||||
@version: LibVLC 2.1.0 or later.
|
||||
'''
|
||||
return libvlc_audio_output_device_count(self, psz_audio_output)
|
||||
|
||||
def audio_output_device_longname(self, psz_audio_output, i_device):
|
||||
'''Get long name of device, if not available short name given.
|
||||
@param psz_audio_output: - name of audio output, See L{AudioOutput}.
|
||||
@param i_device: device index.
|
||||
@return: long name of device.
|
||||
'''
|
||||
return libvlc_audio_output_device_longname(self, psz_audio_output, i_device)
|
||||
|
||||
def audio_output_device_id(self, psz_audio_output, i_device):
|
||||
'''Get id name of device.
|
||||
@param psz_audio_output: - name of audio output, See L{AudioOutput}.
|
||||
@param i_device: device index.
|
||||
@return: id name of device, use for setting device, need to be free after use.
|
||||
'''
|
||||
return libvlc_audio_output_device_id(self, psz_audio_output, i_device)
|
||||
return libvlc_audio_output_device_list_get(self, aout)
|
||||
|
||||
def vlm_release(self):
|
||||
'''Release the vlm instance related to the given L{Instance}.
|
||||
|
@ -1683,87 +1709,6 @@ class Instance(_Ctype):
|
|||
'''
|
||||
return libvlc_vlm_get_event_manager(self)
|
||||
|
||||
class Log(_Ctype):
|
||||
'''Create a new VLC log instance.
|
||||
|
||||
'''
|
||||
|
||||
def __new__(cls, ptr=_internal_guard):
|
||||
'''(INTERNAL) ctypes wrapper constructor.
|
||||
'''
|
||||
return _Constructor(cls, ptr)
|
||||
|
||||
def __iter__(self):
|
||||
return self.get_iterator()
|
||||
|
||||
def dump(self):
|
||||
return [ str(m) for m in self ]
|
||||
|
||||
|
||||
def close(self):
|
||||
'''Frees memory allocated by L{open}().
|
||||
'''
|
||||
return libvlc_log_close(self)
|
||||
|
||||
def count(self):
|
||||
'''Always returns zero.
|
||||
This function is only provided for backward compatibility.
|
||||
@return: always zero.
|
||||
'''
|
||||
return libvlc_log_count(self)
|
||||
|
||||
def __len__(self):
|
||||
return libvlc_log_count(self)
|
||||
|
||||
def clear(self):
|
||||
'''This function does nothing.
|
||||
It is only provided for backward compatibility.
|
||||
'''
|
||||
return libvlc_log_clear(self)
|
||||
|
||||
def get_iterator(self):
|
||||
'''This function does nothing useful.
|
||||
It is only provided for backward compatibility.
|
||||
@return: an unique pointer or NULL on error or if the parameter was NULL.
|
||||
'''
|
||||
return libvlc_log_get_iterator(self)
|
||||
|
||||
class LogIterator(_Ctype):
|
||||
'''Create a new VLC log iterator.
|
||||
|
||||
'''
|
||||
|
||||
def __new__(cls, ptr=_internal_guard):
|
||||
'''(INTERNAL) ctypes wrapper constructor.
|
||||
'''
|
||||
return _Constructor(cls, ptr)
|
||||
|
||||
def __iter__(self):
|
||||
return self
|
||||
|
||||
def next(self):
|
||||
if self.has_next():
|
||||
b = LogMessage()
|
||||
i = libvlc_log_iterator_next(self, b)
|
||||
return i.contents
|
||||
raise StopIteration
|
||||
|
||||
def __next__(self):
|
||||
return self.next()
|
||||
|
||||
|
||||
def free(self):
|
||||
'''Frees memory allocated by L{log_get_iterator}().
|
||||
'''
|
||||
return libvlc_log_iterator_free(self)
|
||||
|
||||
def has_next(self):
|
||||
'''Always returns zero.
|
||||
This function is only provided for backward compatibility.
|
||||
@return: always zero.
|
||||
'''
|
||||
return libvlc_log_iterator_has_next(self)
|
||||
|
||||
class Media(_Ctype):
|
||||
'''Create a new Media instance.
|
||||
|
||||
|
@ -1809,11 +1754,13 @@ class Media(_Ctype):
|
|||
This option will be used to determine how the media_player will
|
||||
read the media. This allows to use VLC's advanced
|
||||
reading/streaming options on a per-media basis.
|
||||
The options are detailed in vlc --long-help, for instance
|
||||
"--sout-all". Note that all options are not usable on medias:
|
||||
specifically, due to architectural issues, video-related options
|
||||
such as text renderer options cannot be set on a single media. They
|
||||
must be set on the whole libvlc instance instead.
|
||||
@note: The options are listed in 'vlc --long-help' from the command line,
|
||||
e.g. "-sout-all". Keep in mind that available options and their semantics
|
||||
vary across LibVLC versions and builds.
|
||||
@warning: Not all options affects L{Media} objects:
|
||||
Specifically, due to architectural issues most audio and video options,
|
||||
such as text renderer options, have no effects on an individual media.
|
||||
These options must be set through L{new}() instead.
|
||||
@param ppsz_options: the options (as a string).
|
||||
'''
|
||||
return libvlc_media_add_option(self, ppsz_options)
|
||||
|
@ -1906,6 +1853,14 @@ class Media(_Ctype):
|
|||
'''
|
||||
return libvlc_media_get_stats(self, p_stats)
|
||||
|
||||
def subitems(self):
|
||||
'''Get subitems of media descriptor object. This will increment
|
||||
the reference count of supplied media descriptor object. Use
|
||||
L{list_release}() to decrement the reference counting.
|
||||
@return: list of media descriptor subitems or NULL.
|
||||
'''
|
||||
return libvlc_media_subitems(self)
|
||||
|
||||
def event_manager(self):
|
||||
'''Get event manager from media descriptor object.
|
||||
NOTE: this function doesn't increment reference counting.
|
||||
|
@ -1925,7 +1880,7 @@ class Media(_Ctype):
|
|||
The method is synchronous.
|
||||
See L{parse_async}
|
||||
See L{get_meta}
|
||||
See L{get_tracks_info}.
|
||||
See libvlc_media_get_tracks_info.
|
||||
'''
|
||||
return libvlc_media_parse(self)
|
||||
|
||||
|
@ -1939,7 +1894,7 @@ class Media(_Ctype):
|
|||
See L{parse}
|
||||
See libvlc_MediaParsedChanged
|
||||
See L{get_meta}
|
||||
See L{get_tracks_info}.
|
||||
See libvlc_media_get_tracks_info.
|
||||
'''
|
||||
return libvlc_media_parse_async(self)
|
||||
|
||||
|
@ -1965,15 +1920,16 @@ class Media(_Ctype):
|
|||
'''
|
||||
return libvlc_media_get_user_data(self)
|
||||
|
||||
def get_tracks_info(self):
|
||||
def tracks_get(self, tracks):
|
||||
'''Get media descriptor's elementary streams description
|
||||
Note, you need to call L{parse}() or play the media at least once
|
||||
before calling this function.
|
||||
Not doing this will result in an empty array.
|
||||
@param tracks: address to store an allocated array of Elementary Streams descriptions (must be freed by the caller) [OUT].
|
||||
@return: the number of Elementary Streams.
|
||||
@param tracks: address to store an allocated array of Elementary Streams descriptions (must be freed with L{tracks_release}.
|
||||
@return: the number of Elementary Streams (zero on error).
|
||||
@version: LibVLC 2.1.0 and later.
|
||||
'''
|
||||
return libvlc_media_get_tracks_info(self)
|
||||
return libvlc_media_tracks_get(self, tracks)
|
||||
|
||||
def player_new_from_media(self):
|
||||
'''Create a Media Player object from a Media.
|
||||
|
@ -2255,7 +2211,7 @@ class MediaListPlayer(_Ctype):
|
|||
return libvlc_media_list_player_play(self)
|
||||
|
||||
def pause(self):
|
||||
'''Pause media list.
|
||||
'''Toggle pause (or resume) media list.
|
||||
'''
|
||||
return libvlc_media_list_player_pause(self)
|
||||
|
||||
|
@ -2681,13 +2637,14 @@ class MediaPlayer(_Ctype):
|
|||
return libvlc_media_player_set_time(self, i_time)
|
||||
|
||||
def get_position(self):
|
||||
'''Get movie position.
|
||||
'''Get movie position as percentage between 0.0 and 1.0.
|
||||
@return: movie position, or -1. in case of error.
|
||||
'''
|
||||
return libvlc_media_player_get_position(self)
|
||||
|
||||
def set_position(self, f_pos):
|
||||
'''Set movie position. This has no effect if playback is not enabled.
|
||||
'''Set movie position as percentage between 0.0 and 1.0.
|
||||
This has no effect if playback is not enabled.
|
||||
This might not work depending on the underlying input format and protocol.
|
||||
@param f_pos: the position.
|
||||
'''
|
||||
|
@ -2968,13 +2925,13 @@ class MediaPlayer(_Ctype):
|
|||
|
||||
def video_get_track(self):
|
||||
'''Get current video track.
|
||||
@return: the video track (int) or -1 if none.
|
||||
@return: the video track ID (int) or -1 if no active input.
|
||||
'''
|
||||
return libvlc_video_get_track(self)
|
||||
|
||||
def video_set_track(self, i_track):
|
||||
'''Set video track.
|
||||
@param i_track: the track (int).
|
||||
@param i_track: the track ID (i_id field from track description).
|
||||
@return: 0 on success, -1 if out of range.
|
||||
'''
|
||||
return libvlc_video_set_track(self, i_track)
|
||||
|
@ -3084,33 +3041,30 @@ class MediaPlayer(_Ctype):
|
|||
return libvlc_video_set_adjust_float(self, option, value)
|
||||
|
||||
def audio_output_set(self, psz_name):
|
||||
'''Set the audio output.
|
||||
Change will be applied after stop and play.
|
||||
'''Sets the audio output.
|
||||
@note: Any change will take be effect only after playback is stopped and
|
||||
restarted. Audio output cannot be changed while playing.
|
||||
@param psz_name: name of audio output, use psz_name of See L{AudioOutput}.
|
||||
@return: 0 if function succeded, -1 on error.
|
||||
'''
|
||||
return libvlc_audio_output_set(self, psz_name)
|
||||
|
||||
def audio_output_device_set(self, psz_audio_output, psz_device_id):
|
||||
'''Set audio output device. Changes are only effective after stop and play.
|
||||
'''Configures an explicit audio output device for a given audio output plugin.
|
||||
A list of possible devices can be obtained with
|
||||
L{audio_output_device_list_get}().
|
||||
@note: This function does not select the specified audio output plugin.
|
||||
L{audio_output_set}() is used for that purpose.
|
||||
@warning: The syntax for the device parameter depends on the audio output.
|
||||
This is not portable. Only use this function if you know what you are doing.
|
||||
Some audio outputs do not support this function (e.g. PulseAudio, WASAPI).
|
||||
Some audio outputs require further parameters (e.g. ALSA: channels map).
|
||||
@param psz_audio_output: - name of audio output, See L{AudioOutput}.
|
||||
@param psz_device_id: device.
|
||||
@return: Nothing. Errors are ignored.
|
||||
'''
|
||||
return libvlc_audio_output_device_set(self, psz_audio_output, psz_device_id)
|
||||
|
||||
def audio_output_get_device_type(self):
|
||||
'''Get current audio device type. Device type describes something like
|
||||
character of output sound - stereo sound, 2.1, 5.1 etc.
|
||||
@return: the audio devices type See libvlc_audio_output_device_types_t.
|
||||
'''
|
||||
return libvlc_audio_output_get_device_type(self)
|
||||
|
||||
def audio_output_set_device_type(self, device_type):
|
||||
'''Set current audio device type.
|
||||
@param device_type: the audio device type,
|
||||
'''
|
||||
return libvlc_audio_output_set_device_type(self, device_type)
|
||||
|
||||
def audio_toggle_mute(self):
|
||||
'''Toggle mute status.
|
||||
'''
|
||||
|
@ -3118,13 +3072,13 @@ class MediaPlayer(_Ctype):
|
|||
|
||||
def audio_get_mute(self):
|
||||
'''Get current mute status.
|
||||
@return: the mute status (boolean) \libvlc_return_bool.
|
||||
@return: the mute status (boolean) if defined, -1 if undefined/unapplicable.
|
||||
'''
|
||||
return libvlc_audio_get_mute(self)
|
||||
|
||||
def audio_set_mute(self, status):
|
||||
'''Set mute status.
|
||||
@param status: If status is true then mute, otherwise unmute.
|
||||
@param status: If status is true then mute, otherwise unmute @warning This function does not always work. If there are no active audio playback stream, the mute status might not be available. If digital pass-through (S/PDIF, HDMI...) is in use, muting may be unapplicable. Also some audio output plugins do not support muting at all. @note To force silent playback, disable all audio tracks. This is more efficient and reliable than mute.
|
||||
'''
|
||||
return libvlc_audio_set_mute(self, status)
|
||||
|
||||
|
@ -3149,13 +3103,13 @@ class MediaPlayer(_Ctype):
|
|||
|
||||
def audio_get_track(self):
|
||||
'''Get current audio track.
|
||||
@return: the audio track (int), or -1 if none.
|
||||
@return: the audio track ID or -1 if no active input.
|
||||
'''
|
||||
return libvlc_audio_get_track(self)
|
||||
|
||||
def audio_set_track(self, i_track):
|
||||
'''Set current audio track.
|
||||
@param i_track: the track (int).
|
||||
@param i_track: the track ID (i_id field from track description).
|
||||
@return: 0 on success, -1 on error.
|
||||
'''
|
||||
return libvlc_audio_set_track(self, i_track)
|
||||
|
@ -3397,112 +3351,6 @@ def libvlc_log_unsubscribe(sub):
|
|||
None, ctypes.c_void_p)
|
||||
return f(sub)
|
||||
|
||||
def libvlc_get_log_verbosity(p_instance):
|
||||
'''Always returns minus one.
|
||||
This function is only provided for backward compatibility.
|
||||
@param p_instance: ignored.
|
||||
@return: always -1.
|
||||
'''
|
||||
f = _Cfunctions.get('libvlc_get_log_verbosity', None) or \
|
||||
_Cfunction('libvlc_get_log_verbosity', ((1,),), None,
|
||||
ctypes.c_uint, Instance)
|
||||
return f(p_instance)
|
||||
|
||||
def libvlc_set_log_verbosity(p_instance, level):
|
||||
'''This function does nothing.
|
||||
It is only provided for backward compatibility.
|
||||
@param p_instance: ignored.
|
||||
@param level: ignored.
|
||||
'''
|
||||
f = _Cfunctions.get('libvlc_set_log_verbosity', None) or \
|
||||
_Cfunction('libvlc_set_log_verbosity', ((1,), (1,),), None,
|
||||
None, Instance, ctypes.c_uint)
|
||||
return f(p_instance, level)
|
||||
|
||||
def libvlc_log_open(p_instance):
|
||||
'''This function does nothing useful.
|
||||
It is only provided for backward compatibility.
|
||||
@param p_instance: libvlc instance.
|
||||
@return: an unique pointer or NULL on error.
|
||||
'''
|
||||
f = _Cfunctions.get('libvlc_log_open', None) or \
|
||||
_Cfunction('libvlc_log_open', ((1,),), class_result(Log),
|
||||
ctypes.c_void_p, Instance)
|
||||
return f(p_instance)
|
||||
|
||||
def libvlc_log_close(p_log):
|
||||
'''Frees memory allocated by L{libvlc_log_open}().
|
||||
@param p_log: libvlc log instance or NULL.
|
||||
'''
|
||||
f = _Cfunctions.get('libvlc_log_close', None) or \
|
||||
_Cfunction('libvlc_log_close', ((1,),), None,
|
||||
None, Log)
|
||||
return f(p_log)
|
||||
|
||||
def libvlc_log_count(p_log):
|
||||
'''Always returns zero.
|
||||
This function is only provided for backward compatibility.
|
||||
@param p_log: ignored.
|
||||
@return: always zero.
|
||||
'''
|
||||
f = _Cfunctions.get('libvlc_log_count', None) or \
|
||||
_Cfunction('libvlc_log_count', ((1,),), None,
|
||||
ctypes.c_uint, Log)
|
||||
return f(p_log)
|
||||
|
||||
def libvlc_log_clear(p_log):
|
||||
'''This function does nothing.
|
||||
It is only provided for backward compatibility.
|
||||
@param p_log: ignored.
|
||||
'''
|
||||
f = _Cfunctions.get('libvlc_log_clear', None) or \
|
||||
_Cfunction('libvlc_log_clear', ((1,),), None,
|
||||
None, Log)
|
||||
return f(p_log)
|
||||
|
||||
def libvlc_log_get_iterator(p_log):
|
||||
'''This function does nothing useful.
|
||||
It is only provided for backward compatibility.
|
||||
@param p_log: ignored.
|
||||
@return: an unique pointer or NULL on error or if the parameter was NULL.
|
||||
'''
|
||||
f = _Cfunctions.get('libvlc_log_get_iterator', None) or \
|
||||
_Cfunction('libvlc_log_get_iterator', ((1,),), class_result(LogIterator),
|
||||
ctypes.c_void_p, Log)
|
||||
return f(p_log)
|
||||
|
||||
def libvlc_log_iterator_free(p_iter):
|
||||
'''Frees memory allocated by L{libvlc_log_get_iterator}().
|
||||
@param p_iter: libvlc log iterator or NULL.
|
||||
'''
|
||||
f = _Cfunctions.get('libvlc_log_iterator_free', None) or \
|
||||
_Cfunction('libvlc_log_iterator_free', ((1,),), None,
|
||||
None, LogIterator)
|
||||
return f(p_iter)
|
||||
|
||||
def libvlc_log_iterator_has_next(p_iter):
|
||||
'''Always returns zero.
|
||||
This function is only provided for backward compatibility.
|
||||
@param p_iter: ignored.
|
||||
@return: always zero.
|
||||
'''
|
||||
f = _Cfunctions.get('libvlc_log_iterator_has_next', None) or \
|
||||
_Cfunction('libvlc_log_iterator_has_next', ((1,),), None,
|
||||
ctypes.c_int, LogIterator)
|
||||
return f(p_iter)
|
||||
|
||||
def libvlc_log_iterator_next(p_iter, p_buffer):
|
||||
'''Always returns NULL.
|
||||
This function is only provided for backward compatibility.
|
||||
@param p_iter: libvlc log iterator or NULL.
|
||||
@param p_buffer: ignored.
|
||||
@return: always NULL.
|
||||
'''
|
||||
f = _Cfunctions.get('libvlc_log_iterator_next', None) or \
|
||||
_Cfunction('libvlc_log_iterator_next', ((1,), (1,),), None,
|
||||
ctypes.POINTER(LogMessage), LogIterator, ctypes.POINTER(LogMessage))
|
||||
return f(p_iter, p_buffer)
|
||||
|
||||
def libvlc_module_description_list_release(p_list):
|
||||
'''Release a list of module descriptions.
|
||||
@param p_list: the list to be released.
|
||||
|
@ -3615,11 +3463,13 @@ def libvlc_media_add_option(p_md, ppsz_options):
|
|||
This option will be used to determine how the media_player will
|
||||
read the media. This allows to use VLC's advanced
|
||||
reading/streaming options on a per-media basis.
|
||||
The options are detailed in vlc --long-help, for instance
|
||||
"--sout-all". Note that all options are not usable on medias:
|
||||
specifically, due to architectural issues, video-related options
|
||||
such as text renderer options cannot be set on a single media. They
|
||||
must be set on the whole libvlc instance instead.
|
||||
@note: The options are listed in 'vlc --long-help' from the command line,
|
||||
e.g. "-sout-all". Keep in mind that available options and their semantics
|
||||
vary across LibVLC versions and builds.
|
||||
@warning: Not all options affects L{Media} objects:
|
||||
Specifically, due to architectural issues most audio and video options,
|
||||
such as text renderer options, have no effects on an individual media.
|
||||
These options must be set through L{libvlc_new}() instead.
|
||||
@param p_md: the media descriptor.
|
||||
@param ppsz_options: the options (as a string).
|
||||
'''
|
||||
|
@ -3756,6 +3606,18 @@ def libvlc_media_get_stats(p_md, p_stats):
|
|||
ctypes.c_int, Media, ctypes.POINTER(MediaStats))
|
||||
return f(p_md, p_stats)
|
||||
|
||||
def libvlc_media_subitems(p_md):
|
||||
'''Get subitems of media descriptor object. This will increment
|
||||
the reference count of supplied media descriptor object. Use
|
||||
L{libvlc_media_list_release}() to decrement the reference counting.
|
||||
@param p_md: media descriptor object.
|
||||
@return: list of media descriptor subitems or NULL.
|
||||
'''
|
||||
f = _Cfunctions.get('libvlc_media_subitems', None) or \
|
||||
_Cfunction('libvlc_media_subitems', ((1,),), class_result(MediaList),
|
||||
ctypes.c_void_p, Media)
|
||||
return f(p_md)
|
||||
|
||||
def libvlc_media_event_manager(p_md):
|
||||
'''Get event manager from media descriptor object.
|
||||
NOTE: this function doesn't increment reference counting.
|
||||
|
@ -3783,7 +3645,7 @@ def libvlc_media_parse(p_md):
|
|||
The method is synchronous.
|
||||
See L{libvlc_media_parse_async}
|
||||
See L{libvlc_media_get_meta}
|
||||
See L{libvlc_media_get_tracks_info}.
|
||||
See libvlc_media_get_tracks_info.
|
||||
@param p_md: media descriptor object.
|
||||
'''
|
||||
f = _Cfunctions.get('libvlc_media_parse', None) or \
|
||||
|
@ -3801,7 +3663,7 @@ def libvlc_media_parse_async(p_md):
|
|||
See L{libvlc_media_parse}
|
||||
See libvlc_MediaParsedChanged
|
||||
See L{libvlc_media_get_meta}
|
||||
See L{libvlc_media_get_tracks_info}.
|
||||
See libvlc_media_get_tracks_info.
|
||||
@param p_md: media descriptor object.
|
||||
'''
|
||||
f = _Cfunctions.get('libvlc_media_parse_async', None) or \
|
||||
|
@ -3843,19 +3705,31 @@ def libvlc_media_get_user_data(p_md):
|
|||
ctypes.c_void_p, Media)
|
||||
return f(p_md)
|
||||
|
||||
def libvlc_media_get_tracks_info(p_md):
|
||||
def libvlc_media_tracks_get(p_md, tracks):
|
||||
'''Get media descriptor's elementary streams description
|
||||
Note, you need to call L{libvlc_media_parse}() or play the media at least once
|
||||
before calling this function.
|
||||
Not doing this will result in an empty array.
|
||||
@param p_md: media descriptor object.
|
||||
@param tracks: address to store an allocated array of Elementary Streams descriptions (must be freed by the caller) [OUT].
|
||||
@return: the number of Elementary Streams.
|
||||
@param tracks: address to store an allocated array of Elementary Streams descriptions (must be freed with L{libvlc_media_tracks_release}.
|
||||
@return: the number of Elementary Streams (zero on error).
|
||||
@version: LibVLC 2.1.0 and later.
|
||||
'''
|
||||
f = _Cfunctions.get('libvlc_media_get_tracks_info', None) or \
|
||||
_Cfunction('libvlc_media_get_tracks_info', ((1,), (2,),), None,
|
||||
ctypes.c_int, Media, ctypes.POINTER(ctypes.c_void_p))
|
||||
return f(p_md)
|
||||
f = _Cfunctions.get('libvlc_media_tracks_get', None) or \
|
||||
_Cfunction('libvlc_media_tracks_get', ((1,), (1,),), None,
|
||||
ctypes.c_uint, Media, ctypes.POINTER(ctypes.POINTER(MediaTrack)))
|
||||
return f(p_md, tracks)
|
||||
|
||||
def libvlc_media_tracks_release(p_tracks, i_count):
|
||||
'''Release media descriptor's elementary streams description array.
|
||||
@param p_tracks: tracks info array to release.
|
||||
@param i_count: number of elements in the array.
|
||||
@version: LibVLC 2.1.0 and later.
|
||||
'''
|
||||
f = _Cfunctions.get('libvlc_media_tracks_release', None) or \
|
||||
_Cfunction('libvlc_media_tracks_release', ((1,), (1,),), None,
|
||||
None, ctypes.POINTER(MediaTrack), ctypes.c_uint)
|
||||
return f(p_tracks, i_count)
|
||||
|
||||
def libvlc_media_discoverer_new_from_name(p_inst, psz_name):
|
||||
'''Discover media service by name.
|
||||
|
@ -4208,7 +4082,7 @@ def libvlc_media_list_player_play(p_mlp):
|
|||
return f(p_mlp)
|
||||
|
||||
def libvlc_media_list_player_pause(p_mlp):
|
||||
'''Pause media list.
|
||||
'''Toggle pause (or resume) media list.
|
||||
@param p_mlp: media list player instance.
|
||||
'''
|
||||
f = _Cfunctions.get('libvlc_media_list_player_pause', None) or \
|
||||
|
@ -4673,7 +4547,7 @@ def libvlc_media_player_set_time(p_mi, i_time):
|
|||
return f(p_mi, i_time)
|
||||
|
||||
def libvlc_media_player_get_position(p_mi):
|
||||
'''Get movie position.
|
||||
'''Get movie position as percentage between 0.0 and 1.0.
|
||||
@param p_mi: the Media Player.
|
||||
@return: movie position, or -1. in case of error.
|
||||
'''
|
||||
|
@ -4683,7 +4557,8 @@ def libvlc_media_player_get_position(p_mi):
|
|||
return f(p_mi)
|
||||
|
||||
def libvlc_media_player_set_position(p_mi, f_pos):
|
||||
'''Set movie position. This has no effect if playback is not enabled.
|
||||
'''Set movie position as percentage between 0.0 and 1.0.
|
||||
This has no effect if playback is not enabled.
|
||||
This might not work depending on the underlying input format and protocol.
|
||||
@param p_mi: the Media Player.
|
||||
@param f_pos: the position.
|
||||
|
@ -4894,14 +4769,6 @@ def libvlc_track_description_list_release(p_track_description):
|
|||
None, ctypes.POINTER(TrackDescription))
|
||||
return f(p_track_description)
|
||||
|
||||
def libvlc_track_description_release(p_track_description):
|
||||
'''\deprecated Use L{libvlc_track_description_list_release} instead.
|
||||
'''
|
||||
f = _Cfunctions.get('libvlc_track_description_release', None) or \
|
||||
_Cfunction('libvlc_track_description_release', ((1,),), None,
|
||||
None, ctypes.POINTER(TrackDescription))
|
||||
return f(p_track_description)
|
||||
|
||||
def libvlc_toggle_fullscreen(p_mi):
|
||||
'''Toggle fullscreen status on non-embedded video outputs.
|
||||
@warning: The same limitations applies to this function
|
||||
|
@ -5219,7 +5086,7 @@ def libvlc_video_get_track_description(p_mi):
|
|||
def libvlc_video_get_track(p_mi):
|
||||
'''Get current video track.
|
||||
@param p_mi: media player.
|
||||
@return: the video track (int) or -1 if none.
|
||||
@return: the video track ID (int) or -1 if no active input.
|
||||
'''
|
||||
f = _Cfunctions.get('libvlc_video_get_track', None) or \
|
||||
_Cfunction('libvlc_video_get_track', ((1,),), None,
|
||||
|
@ -5229,7 +5096,7 @@ def libvlc_video_get_track(p_mi):
|
|||
def libvlc_video_set_track(p_mi, i_track):
|
||||
'''Set video track.
|
||||
@param p_mi: media player.
|
||||
@param i_track: the track (int).
|
||||
@param i_track: the track ID (i_id field from track description).
|
||||
@return: 0 on success, -1 if out of range.
|
||||
'''
|
||||
f = _Cfunctions.get('libvlc_video_set_track', None) or \
|
||||
|
@ -5394,7 +5261,7 @@ def libvlc_video_set_adjust_float(p_mi, option, value):
|
|||
return f(p_mi, option, value)
|
||||
|
||||
def libvlc_audio_output_list_get(p_instance):
|
||||
'''Get the list of available audio outputs.
|
||||
'''Gets the list of available audio outputs.
|
||||
@param p_instance: libvlc instance.
|
||||
@return: list of available audio outputs. It must be freed it with In case of error, NULL is returned.
|
||||
'''
|
||||
|
@ -5404,7 +5271,7 @@ def libvlc_audio_output_list_get(p_instance):
|
|||
return f(p_instance)
|
||||
|
||||
def libvlc_audio_output_list_release(p_list):
|
||||
'''Free the list of available audio outputs.
|
||||
'''Frees the list of available audio outputs.
|
||||
@param p_list: list with audio outputs for release.
|
||||
'''
|
||||
f = _Cfunctions.get('libvlc_audio_output_list_release', None) or \
|
||||
|
@ -5413,8 +5280,9 @@ def libvlc_audio_output_list_release(p_list):
|
|||
return f(p_list)
|
||||
|
||||
def libvlc_audio_output_set(p_mi, psz_name):
|
||||
'''Set the audio output.
|
||||
Change will be applied after stop and play.
|
||||
'''Sets the audio output.
|
||||
@note: Any change will take be effect only after playback is stopped and
|
||||
restarted. Audio output cannot be changed while playing.
|
||||
@param p_mi: media player.
|
||||
@param psz_name: name of audio output, use psz_name of See L{AudioOutput}.
|
||||
@return: 0 if function succeded, -1 on error.
|
||||
|
@ -5424,77 +5292,59 @@ def libvlc_audio_output_set(p_mi, psz_name):
|
|||
ctypes.c_int, MediaPlayer, ctypes.c_char_p)
|
||||
return f(p_mi, psz_name)
|
||||
|
||||
def libvlc_audio_output_device_count(p_instance, psz_audio_output):
|
||||
'''Get count of devices for audio output, these devices are hardware oriented
|
||||
like analor or digital output of sound card.
|
||||
def libvlc_audio_output_device_list_get(p_instance, aout):
|
||||
'''Gets a list of audio output devices for a given audio output.
|
||||
See L{libvlc_audio_output_device_set}().
|
||||
@note: Not all audio outputs support this. In particular, an empty (NULL)
|
||||
list of devices does B{not} imply that the specified audio output does
|
||||
not work.
|
||||
@note: The list might not be exhaustive.
|
||||
@warning: Some audio output devices in the list might not actually work in
|
||||
some circumstances. By default, it is recommended to not specify any
|
||||
explicit audio device.
|
||||
@param p_instance: libvlc instance.
|
||||
@param psz_audio_output: - name of audio output, See L{AudioOutput}.
|
||||
@return: number of devices.
|
||||
@param psz_aout: audio output name (as returned by L{libvlc_audio_output_list_get}()).
|
||||
@return: A NULL-terminated linked list of potential audio output devices. It must be freed it with L{libvlc_audio_output_device_list_release}().
|
||||
@version: LibVLC 2.1.0 or later.
|
||||
'''
|
||||
f = _Cfunctions.get('libvlc_audio_output_device_count', None) or \
|
||||
_Cfunction('libvlc_audio_output_device_count', ((1,), (1,),), None,
|
||||
ctypes.c_int, Instance, ctypes.c_char_p)
|
||||
return f(p_instance, psz_audio_output)
|
||||
f = _Cfunctions.get('libvlc_audio_output_device_list_get', None) or \
|
||||
_Cfunction('libvlc_audio_output_device_list_get', ((1,), (1,),), None,
|
||||
ctypes.POINTER(AudioOutputDevice), Instance, ctypes.c_char_p)
|
||||
return f(p_instance, aout)
|
||||
|
||||
def libvlc_audio_output_device_longname(p_instance, psz_audio_output, i_device):
|
||||
'''Get long name of device, if not available short name given.
|
||||
@param p_instance: libvlc instance.
|
||||
@param psz_audio_output: - name of audio output, See L{AudioOutput}.
|
||||
@param i_device: device index.
|
||||
@return: long name of device.
|
||||
def libvlc_audio_output_device_list_release(p_list):
|
||||
'''Frees a list of available audio output devices.
|
||||
@param p_list: list with audio outputs for release.
|
||||
@version: LibVLC 2.1.0 or later.
|
||||
'''
|
||||
f = _Cfunctions.get('libvlc_audio_output_device_longname', None) or \
|
||||
_Cfunction('libvlc_audio_output_device_longname', ((1,), (1,), (1,),), string_result,
|
||||
ctypes.c_void_p, Instance, ctypes.c_char_p, ctypes.c_int)
|
||||
return f(p_instance, psz_audio_output, i_device)
|
||||
|
||||
def libvlc_audio_output_device_id(p_instance, psz_audio_output, i_device):
|
||||
'''Get id name of device.
|
||||
@param p_instance: libvlc instance.
|
||||
@param psz_audio_output: - name of audio output, See L{AudioOutput}.
|
||||
@param i_device: device index.
|
||||
@return: id name of device, use for setting device, need to be free after use.
|
||||
'''
|
||||
f = _Cfunctions.get('libvlc_audio_output_device_id', None) or \
|
||||
_Cfunction('libvlc_audio_output_device_id', ((1,), (1,), (1,),), string_result,
|
||||
ctypes.c_void_p, Instance, ctypes.c_char_p, ctypes.c_int)
|
||||
return f(p_instance, psz_audio_output, i_device)
|
||||
f = _Cfunctions.get('libvlc_audio_output_device_list_release', None) or \
|
||||
_Cfunction('libvlc_audio_output_device_list_release', ((1,),), None,
|
||||
None, ctypes.POINTER(AudioOutputDevice))
|
||||
return f(p_list)
|
||||
|
||||
def libvlc_audio_output_device_set(p_mi, psz_audio_output, psz_device_id):
|
||||
'''Set audio output device. Changes are only effective after stop and play.
|
||||
'''Configures an explicit audio output device for a given audio output plugin.
|
||||
A list of possible devices can be obtained with
|
||||
L{libvlc_audio_output_device_list_get}().
|
||||
@note: This function does not select the specified audio output plugin.
|
||||
L{libvlc_audio_output_set}() is used for that purpose.
|
||||
@warning: The syntax for the device parameter depends on the audio output.
|
||||
This is not portable. Only use this function if you know what you are doing.
|
||||
Some audio outputs do not support this function (e.g. PulseAudio, WASAPI).
|
||||
Some audio outputs require further parameters (e.g. ALSA: channels map).
|
||||
@param p_mi: media player.
|
||||
@param psz_audio_output: - name of audio output, See L{AudioOutput}.
|
||||
@param psz_device_id: device.
|
||||
@return: Nothing. Errors are ignored.
|
||||
'''
|
||||
f = _Cfunctions.get('libvlc_audio_output_device_set', None) or \
|
||||
_Cfunction('libvlc_audio_output_device_set', ((1,), (1,), (1,),), None,
|
||||
None, MediaPlayer, ctypes.c_char_p, ctypes.c_char_p)
|
||||
return f(p_mi, psz_audio_output, psz_device_id)
|
||||
|
||||
def libvlc_audio_output_get_device_type(p_mi):
|
||||
'''Get current audio device type. Device type describes something like
|
||||
character of output sound - stereo sound, 2.1, 5.1 etc.
|
||||
@param p_mi: media player.
|
||||
@return: the audio devices type See libvlc_audio_output_device_types_t.
|
||||
'''
|
||||
f = _Cfunctions.get('libvlc_audio_output_get_device_type', None) or \
|
||||
_Cfunction('libvlc_audio_output_get_device_type', ((1,),), None,
|
||||
ctypes.c_int, MediaPlayer)
|
||||
return f(p_mi)
|
||||
|
||||
def libvlc_audio_output_set_device_type(p_mi, device_type):
|
||||
'''Set current audio device type.
|
||||
@param p_mi: vlc instance.
|
||||
@param device_type: the audio device type,
|
||||
'''
|
||||
f = _Cfunctions.get('libvlc_audio_output_set_device_type', None) or \
|
||||
_Cfunction('libvlc_audio_output_set_device_type', ((1,), (1,),), None,
|
||||
None, MediaPlayer, ctypes.c_int)
|
||||
return f(p_mi, device_type)
|
||||
|
||||
def libvlc_audio_toggle_mute(p_mi):
|
||||
'''Toggle mute status.
|
||||
@param p_mi: media player.
|
||||
@param p_mi: media player @warning Toggling mute atomically is not always possible: On some platforms, other processes can mute the VLC audio playback stream asynchronously. Thus, there is a small race condition where toggling will not work. See also the limitations of L{libvlc_audio_set_mute}().
|
||||
'''
|
||||
f = _Cfunctions.get('libvlc_audio_toggle_mute', None) or \
|
||||
_Cfunction('libvlc_audio_toggle_mute', ((1,),), None,
|
||||
|
@ -5504,7 +5354,7 @@ def libvlc_audio_toggle_mute(p_mi):
|
|||
def libvlc_audio_get_mute(p_mi):
|
||||
'''Get current mute status.
|
||||
@param p_mi: media player.
|
||||
@return: the mute status (boolean) \libvlc_return_bool.
|
||||
@return: the mute status (boolean) if defined, -1 if undefined/unapplicable.
|
||||
'''
|
||||
f = _Cfunctions.get('libvlc_audio_get_mute', None) or \
|
||||
_Cfunction('libvlc_audio_get_mute', ((1,),), None,
|
||||
|
@ -5514,7 +5364,7 @@ def libvlc_audio_get_mute(p_mi):
|
|||
def libvlc_audio_set_mute(p_mi, status):
|
||||
'''Set mute status.
|
||||
@param p_mi: media player.
|
||||
@param status: If status is true then mute, otherwise unmute.
|
||||
@param status: If status is true then mute, otherwise unmute @warning This function does not always work. If there are no active audio playback stream, the mute status might not be available. If digital pass-through (S/PDIF, HDMI...) is in use, muting may be unapplicable. Also some audio output plugins do not support muting at all. @note To force silent playback, disable all audio tracks. This is more efficient and reliable than mute.
|
||||
'''
|
||||
f = _Cfunctions.get('libvlc_audio_set_mute', None) or \
|
||||
_Cfunction('libvlc_audio_set_mute', ((1,), (1,),), None,
|
||||
|
@ -5565,7 +5415,7 @@ def libvlc_audio_get_track_description(p_mi):
|
|||
def libvlc_audio_get_track(p_mi):
|
||||
'''Get current audio track.
|
||||
@param p_mi: media player.
|
||||
@return: the audio track (int), or -1 if none.
|
||||
@return: the audio track ID or -1 if no active input.
|
||||
'''
|
||||
f = _Cfunctions.get('libvlc_audio_get_track', None) or \
|
||||
_Cfunction('libvlc_audio_get_track', ((1,),), None,
|
||||
|
@ -5575,7 +5425,7 @@ def libvlc_audio_get_track(p_mi):
|
|||
def libvlc_audio_set_track(p_mi, i_track):
|
||||
'''Set current audio track.
|
||||
@param p_mi: media player.
|
||||
@param i_track: the track (int).
|
||||
@param i_track: the track ID (i_id field from track description).
|
||||
@return: 0 on success, -1 on error.
|
||||
'''
|
||||
f = _Cfunctions.get('libvlc_audio_set_track', None) or \
|
||||
|
@ -5933,11 +5783,14 @@ def libvlc_vlm_get_event_manager(p_instance):
|
|||
return f(p_instance)
|
||||
|
||||
|
||||
# 2 function(s) blacklisted:
|
||||
# 4 function(s) blacklisted:
|
||||
# libvlc_audio_output_get_device_type
|
||||
# libvlc_audio_output_set_device_type
|
||||
# libvlc_printerr
|
||||
# libvlc_set_exit_handler
|
||||
|
||||
# 17 function(s) not wrapped as methods:
|
||||
# 18 function(s) not wrapped as methods:
|
||||
# libvlc_audio_output_device_list_release
|
||||
# libvlc_audio_output_list_release
|
||||
# libvlc_clearerr
|
||||
# libvlc_clock
|
||||
|
@ -5950,10 +5803,10 @@ def libvlc_vlm_get_event_manager(p_instance):
|
|||
# libvlc_log_subscribe
|
||||
# libvlc_log_subscribe_file
|
||||
# libvlc_log_unsubscribe
|
||||
# libvlc_media_tracks_release
|
||||
# libvlc_module_description_list_release
|
||||
# libvlc_new
|
||||
# libvlc_track_description_list_release
|
||||
# libvlc_track_description_release
|
||||
# libvlc_vprinterr
|
||||
|
||||
# Start of footer.py #
|
||||
|
@ -6075,9 +5928,9 @@ if __name__ == '__main__':
|
|||
print('Error: %s file not readable' % movie)
|
||||
sys.exit(1)
|
||||
|
||||
instance = Instance()
|
||||
instance = Instance("--sub-source marq")
|
||||
try:
|
||||
media = instance.media_new(movie, 'sub-filter=marq') # load marqee option
|
||||
media = instance.media_new(movie)
|
||||
except NameError:
|
||||
print('NameError: %s (%s vs LibVLC %s)' % (sys.exc_info()[1],
|
||||
__version__,
|
||||
|
@ -6087,13 +5940,12 @@ if __name__ == '__main__':
|
|||
player.set_media(media)
|
||||
player.play()
|
||||
|
||||
# Some marquee examples. Marquee requires 'sub-filter=marq' in the
|
||||
# media_new() call above. See also the Media.add_options method
|
||||
# and <http://www.videolan.org/doc/play-howto/en/ch04.html>
|
||||
# Some marquee examples. Marquee requires '--sub-source marq' in the
|
||||
# Instance() call above. See <http://www.videolan.org/doc/play-howto/en/ch04.html>
|
||||
player.video_set_marquee_int(VideoMarqueeOption.Enable, 1)
|
||||
player.video_set_marquee_int(VideoMarqueeOption.Size, 24) # pixels
|
||||
player.video_set_marquee_int(VideoMarqueeOption.Position, Position.Bottom)
|
||||
if True: # only one marquee can be specified
|
||||
if False: # only one marquee can be specified
|
||||
player.video_set_marquee_int(VideoMarqueeOption.Timeout, 5000) # millisec, 0==forever
|
||||
t = media.get_mrl() # movie
|
||||
else: # update marquee text periodically
|
||||
|
|
|
@ -125,7 +125,6 @@ class VlcPlayer(MediaPlayer):
|
|||
if Settings().value(u'advanced/hide mouse') and display.controller.isLive:
|
||||
command_line_options += u' --mouse-hide-timeout=0'
|
||||
display.vlcInstance = vlc.Instance(command_line_options)
|
||||
display.vlcInstance.set_log_verbosity(2)
|
||||
# creating an empty vlc media player
|
||||
display.vlcMediaPlayer = display.vlcInstance.media_player_new()
|
||||
display.vlcWidget.resize(display.size())
|
||||
|
|
|
@ -142,8 +142,7 @@ class ServiceManagerDialog(object):
|
|||
self.service_manager_list.setHeaderHidden(True)
|
||||
self.service_manager_list.setExpandsOnDoubleClick(False)
|
||||
self.service_manager_list.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
|
||||
QtCore.QObject.connect(self.service_manager_list, QtCore.SIGNAL('customContextMenuRequested(QPoint)'),
|
||||
self.context_menu)
|
||||
self.service_manager_list.customContextMenuRequested.connect(self.context_menu)
|
||||
self.service_manager_list.setObjectName(u'service_manager_list')
|
||||
# enable drop
|
||||
self.service_manager_list.__class__.dragEnterEvent = self.drag_enter_event
|
||||
|
@ -153,67 +152,59 @@ class ServiceManagerDialog(object):
|
|||
# Add the bottom toolbar
|
||||
self.order_toolbar = OpenLPToolbar(self)
|
||||
action_list = ActionList.get_instance()
|
||||
action_list.add_category(UiStrings().Service, CategoryOrder.standardToolbar)
|
||||
action_list.add_category(UiStrings().Service, CategoryOrder.standard_toolbar)
|
||||
self.service_manager_list.moveTop = self.order_toolbar.addToolbarAction(u'moveTop',
|
||||
text=translate('OpenLP.ServiceManager', 'Move to &top'), icon=u':/services/service_top.png',
|
||||
tooltip=translate('OpenLP.ServiceManager', 'Move item to the top of the service.'),
|
||||
shortcuts=[QtCore.Qt.Key_Home], category=UiStrings().Service, triggers=self.onServiceTop)
|
||||
can_shortcuts=True, category=UiStrings().Service, triggers=self.onServiceTop)
|
||||
self.service_manager_list.moveUp = self.order_toolbar.addToolbarAction(u'moveUp',
|
||||
text=translate('OpenLP.ServiceManager', 'Move &up'), icon=u':/services/service_up.png',
|
||||
tooltip=translate('OpenLP.ServiceManager', 'Move item up one position in the service.'),
|
||||
shortcuts=[QtCore.Qt.Key_PageUp], category=UiStrings().Service, triggers=self.onServiceUp)
|
||||
can_shortcuts=True, category=UiStrings().Service, triggers=self.onServiceUp)
|
||||
self.service_manager_list.moveDown = self.order_toolbar.addToolbarAction(u'moveDown',
|
||||
text=translate('OpenLP.ServiceManager', 'Move &down'), icon=u':/services/service_down.png',
|
||||
tooltip=translate('OpenLP.ServiceManager', 'Move item down one position in the service.'),
|
||||
shortcuts=[QtCore.Qt.Key_PageDown], category=UiStrings().Service, triggers=self.onServiceDown)
|
||||
can_shortcuts=True, category=UiStrings().Service, triggers=self.onServiceDown)
|
||||
self.service_manager_list.moveBottom = self.order_toolbar.addToolbarAction(u'moveBottom',
|
||||
text=translate('OpenLP.ServiceManager', 'Move to &bottom'), icon=u':/services/service_bottom.png',
|
||||
tooltip=translate('OpenLP.ServiceManager', 'Move item to the end of the service.'),
|
||||
shortcuts=[QtCore.Qt.Key_End], category=UiStrings().Service, triggers=self.onServiceEnd)
|
||||
can_shortcuts=True, category=UiStrings().Service, triggers=self.onServiceEnd)
|
||||
self.service_manager_list.down = self.order_toolbar.addToolbarAction(u'down',
|
||||
text=translate('OpenLP.ServiceManager', 'Move &down'),
|
||||
text=translate('OpenLP.ServiceManager', 'Move &down'), can_shortcuts=True,
|
||||
tooltip=translate('OpenLP.ServiceManager', 'Moves the selection down the window.'), visible=False,
|
||||
shortcuts=[QtCore.Qt.Key_Down], triggers=self.on_move_selection_down)
|
||||
triggers=self.on_move_selection_down)
|
||||
action_list.add_action(self.service_manager_list.down)
|
||||
self.service_manager_list.up = self.order_toolbar.addToolbarAction(u'up',
|
||||
text=translate('OpenLP.ServiceManager', 'Move up'), tooltip=translate('OpenLP.ServiceManager',
|
||||
'Moves the selection up the window.'), visible=False, shortcuts=[QtCore.Qt.Key_Up],
|
||||
text=translate('OpenLP.ServiceManager', 'Move up'), can_shortcuts=True,
|
||||
tooltip=translate('OpenLP.ServiceManager', 'Moves the selection up the window.'), visible=False,
|
||||
triggers=self.on_move_selection_up)
|
||||
action_list.add_action(self.service_manager_list.up)
|
||||
self.order_toolbar.addSeparator()
|
||||
self.service_manager_list.delete = self.order_toolbar.addToolbarAction(u'delete',
|
||||
self.service_manager_list.delete = self.order_toolbar.addToolbarAction(u'delete', can_shortcuts=True,
|
||||
text=translate('OpenLP.ServiceManager', '&Delete From Service'), icon=u':/general/general_delete.png',
|
||||
tooltip=translate('OpenLP.ServiceManager', 'Delete the selected item from the service.'),
|
||||
shortcuts=[QtCore.Qt.Key_Delete], triggers=self.onDeleteFromService)
|
||||
triggers=self.onDeleteFromService)
|
||||
self.order_toolbar.addSeparator()
|
||||
self.service_manager_list.expand = self.order_toolbar.addToolbarAction(u'expand',
|
||||
self.service_manager_list.expand = self.order_toolbar.addToolbarAction(u'expand', can_shortcuts=True,
|
||||
text=translate('OpenLP.ServiceManager', '&Expand all'), icon=u':/services/service_expand_all.png',
|
||||
tooltip=translate('OpenLP.ServiceManager', 'Expand all the service items.'),
|
||||
shortcuts=[QtCore.Qt.Key_Plus], category=UiStrings().Service, triggers=self.onExpandAll)
|
||||
self.service_manager_list.collapse = self.order_toolbar.addToolbarAction(u'collapse',
|
||||
category=UiStrings().Service, triggers=self.onExpandAll)
|
||||
self.service_manager_list.collapse = self.order_toolbar.addToolbarAction(u'collapse', can_shortcuts=True,
|
||||
text=translate('OpenLP.ServiceManager', '&Collapse all'), icon=u':/services/service_collapse_all.png',
|
||||
tooltip=translate('OpenLP.ServiceManager', 'Collapse all the service items.'),
|
||||
shortcuts=[QtCore.Qt.Key_Minus], category=UiStrings().Service, triggers=self.onCollapseAll)
|
||||
category=UiStrings().Service, triggers=self.onCollapseAll)
|
||||
self.order_toolbar.addSeparator()
|
||||
self.service_manager_list.make_live = self.order_toolbar.addToolbarAction(u'make_live',
|
||||
self.service_manager_list.make_live = self.order_toolbar.addToolbarAction(u'make_live', can_shortcuts=True,
|
||||
text=translate('OpenLP.ServiceManager', 'Go Live'), icon=u':/general/general_live.png',
|
||||
tooltip=translate('OpenLP.ServiceManager', 'Send the selected item to Live.'),
|
||||
shortcuts=[QtCore.Qt.Key_Enter, QtCore.Qt.Key_Return], category=UiStrings().Service,
|
||||
category=UiStrings().Service,
|
||||
triggers=self.make_live)
|
||||
self.layout.addWidget(self.order_toolbar)
|
||||
# Connect up our signals and slots
|
||||
QtCore.QObject.connect(self.theme_combo_box, QtCore.SIGNAL(u'activated(int)'),
|
||||
self.on_theme_combo_box_selected)
|
||||
QtCore.QObject.connect(self.service_manager_list, QtCore.SIGNAL(u'doubleClicked(QModelIndex)'),
|
||||
self.on_make_live)
|
||||
QtCore.QObject.connect(self.service_manager_list, QtCore.SIGNAL(u'itemCollapsed(QTreeWidgetItem*)'),
|
||||
self.collapsed)
|
||||
QtCore.QObject.connect(self.service_manager_list, QtCore.SIGNAL(u'itemExpanded(QTreeWidgetItem*)'),
|
||||
self.expanded)
|
||||
Registry().register_function(u'theme_update_list', self.update_theme_list)
|
||||
Registry().register_function(u'config_updated', self.config_updated)
|
||||
Registry().register_function(u'config_screen_changed', self.regenerate_service_Items)
|
||||
Registry().register_function(u'theme_update_global', self.theme_change)
|
||||
self.theme_combo_box.activated.connect(self.on_theme_combo_box_selected)
|
||||
self.service_manager_list.doubleClicked.connect(self.on_make_live)
|
||||
self.service_manager_list.itemCollapsed.connect(self.collapsed)
|
||||
self.service_manager_list.itemExpanded.connect(self.expanded)
|
||||
# Last little bits of setting up
|
||||
self.service_theme = Settings().value(self.main_window.serviceManagerSettingsSection + u'/service theme')
|
||||
self.servicePath = AppLocation.get_section_data_path(u'servicemanager')
|
||||
|
@ -273,6 +264,10 @@ class ServiceManagerDialog(object):
|
|||
self.service_manager_list.expand,
|
||||
self.service_manager_list.collapse
|
||||
])
|
||||
Registry().register_function(u'theme_update_list', self.update_theme_list)
|
||||
Registry().register_function(u'config_updated', self.config_updated)
|
||||
Registry().register_function(u'config_screen_changed', self.regenerate_service_Items)
|
||||
Registry().register_function(u'theme_update_global', self.theme_change)
|
||||
|
||||
def drag_enter_event(self, event):
|
||||
"""
|
||||
|
|
|
@ -56,8 +56,8 @@ class ShortcutListForm(QtGui.QDialog, Ui_ShortcutListDialog):
|
|||
self.setupUi(self)
|
||||
self.changedActions = {}
|
||||
self.action_list = ActionList.get_instance()
|
||||
QtCore.QObject.connect(self.primaryPushButton, QtCore.SIGNAL(u'toggled(bool)'),
|
||||
self.onPrimaryPushButtonClicked)
|
||||
self.dialog_was_shown = False
|
||||
QtCore.QObject.connect(self.primaryPushButton, QtCore.SIGNAL(u'toggled(bool)'), self.onPrimaryPushButtonClicked)
|
||||
QtCore.QObject.connect(self.alternatePushButton, QtCore.SIGNAL(u'toggled(bool)'),
|
||||
self.onAlternatePushButtonClicked)
|
||||
QtCore.QObject.connect(self.treeWidget,
|
||||
|
@ -72,8 +72,7 @@ class ShortcutListForm(QtGui.QDialog, Ui_ShortcutListDialog):
|
|||
self.onRestoreDefaultsClicked)
|
||||
QtCore.QObject.connect(self.defaultRadioButton, QtCore.SIGNAL(u'clicked(bool)'),
|
||||
self.onDefaultRadioButtonClicked)
|
||||
QtCore.QObject.connect(self.customRadioButton, QtCore.SIGNAL(u'clicked(bool)'),
|
||||
self.onCustomRadioButtonClicked)
|
||||
QtCore.QObject.connect(self.customRadioButton, QtCore.SIGNAL(u'clicked(bool)'), self.onCustomRadioButtonClicked)
|
||||
|
||||
def keyPressEvent(self, event):
|
||||
"""
|
||||
|
@ -93,9 +92,12 @@ class ShortcutListForm(QtGui.QDialog, Ui_ShortcutListDialog):
|
|||
"""
|
||||
if not self.primaryPushButton.isChecked() and not self.alternatePushButton.isChecked():
|
||||
return
|
||||
# Do not continue, as the event is for the dialog (close it).
|
||||
if self.dialog_was_shown and event.key() in (QtCore.Qt.Key_Escape, QtCore.Qt.Key_Enter, QtCore.Qt.Key_Return):
|
||||
self.dialog_was_shown = False
|
||||
return
|
||||
key = event.key()
|
||||
if key == QtCore.Qt.Key_Shift or key == QtCore.Qt.Key_Control or \
|
||||
key == QtCore.Qt.Key_Meta or key == QtCore.Qt.Key_Alt:
|
||||
if key in (QtCore.Qt.Key_Shift, QtCore.Qt.Key_Control, QtCore.Qt.Key_Meta, QtCore.Qt.Key_Alt):
|
||||
return
|
||||
key_string = QtGui.QKeySequence(key).toString()
|
||||
if event.modifiers() & QtCore.Qt.ControlModifier == QtCore.Qt.ControlModifier:
|
||||
|
@ -109,11 +111,9 @@ class ShortcutListForm(QtGui.QDialog, Ui_ShortcutListDialog):
|
|||
key_sequence = QtGui.QKeySequence(key_string)
|
||||
if self._validiate_shortcut(self._currentItemAction(), key_sequence):
|
||||
if self.primaryPushButton.isChecked():
|
||||
self._adjustButton(self.primaryPushButton,
|
||||
False, text=key_sequence.toString())
|
||||
self._adjustButton(self.primaryPushButton, False, text=key_sequence.toString())
|
||||
elif self.alternatePushButton.isChecked():
|
||||
self._adjustButton(self.alternatePushButton,
|
||||
False, text=key_sequence.toString())
|
||||
self._adjustButton(self.alternatePushButton, False, text=key_sequence.toString())
|
||||
|
||||
def exec_(self):
|
||||
"""
|
||||
|
@ -147,8 +147,8 @@ class ShortcutListForm(QtGui.QDialog, Ui_ShortcutListDialog):
|
|||
|
||||
def refreshShortcutList(self):
|
||||
"""
|
||||
This refreshes the item's shortcuts shown in the list. Note, this
|
||||
neither adds new actions nor removes old actions.
|
||||
This refreshes the item's shortcuts shown in the list. Note, this neither adds new actions nor removes old
|
||||
actions.
|
||||
"""
|
||||
iterator = QtGui.QTreeWidgetItemIterator(self.treeWidget)
|
||||
while iterator.value():
|
||||
|
@ -204,21 +204,19 @@ class ShortcutListForm(QtGui.QDialog, Ui_ShortcutListDialog):
|
|||
new_shortcuts = []
|
||||
if shortcuts:
|
||||
new_shortcuts.append(shortcuts[0])
|
||||
new_shortcuts.append(
|
||||
QtGui.QKeySequence(self.alternatePushButton.text()))
|
||||
new_shortcuts.append(QtGui.QKeySequence(self.alternatePushButton.text()))
|
||||
self.changedActions[action] = new_shortcuts
|
||||
if not self.primaryPushButton.text():
|
||||
# When we do not have a primary shortcut, the just entered alternate
|
||||
# shortcut will automatically become the primary shortcut. That is
|
||||
# why we have to adjust the primary button's text.
|
||||
# When we do not have a primary shortcut, the just entered alternate shortcut will automatically become the
|
||||
# primary shortcut. That is why we have to adjust the primary button's text.
|
||||
self.primaryPushButton.setText(self.alternatePushButton.text())
|
||||
self.alternatePushButton.setText(u'')
|
||||
self.refreshShortcutList()
|
||||
|
||||
def onItemDoubleClicked(self, item, column):
|
||||
"""
|
||||
A item has been double clicked. The ``primaryPushButton`` will be
|
||||
checked and the item's shortcut will be displayed.
|
||||
A item has been double clicked. The ``primaryPushButton`` will be checked and the item's shortcut will be
|
||||
displayed.
|
||||
"""
|
||||
action = self._currentItemAction(item)
|
||||
if action is None:
|
||||
|
@ -234,8 +232,7 @@ class ShortcutListForm(QtGui.QDialog, Ui_ShortcutListDialog):
|
|||
|
||||
def onCurrentItemChanged(self, item=None, previousItem=None):
|
||||
"""
|
||||
A item has been pressed. We adjust the button's text to the action's
|
||||
shortcut which is encapsulate in the item.
|
||||
A item has been pressed. We adjust the button's text to the action's shortcut which is encapsulate in the item.
|
||||
"""
|
||||
action = self._currentItemAction(item)
|
||||
self.primaryPushButton.setEnabled(action is not None)
|
||||
|
@ -253,9 +250,8 @@ class ShortcutListForm(QtGui.QDialog, Ui_ShortcutListDialog):
|
|||
if len(action.defaultShortcuts) == 2:
|
||||
alternate_label_text = action.defaultShortcuts[1].toString()
|
||||
shortcuts = self._actionShortcuts(action)
|
||||
# We do not want to loose pending changes, that is why we have to
|
||||
# keep the text when, this function has not been triggered by a
|
||||
# signal.
|
||||
# We do not want to loose pending changes, that is why we have to keep the text when, this function has not
|
||||
# been triggered by a signal.
|
||||
if item is None:
|
||||
primary_text = self.primaryPushButton.text()
|
||||
alternate_text = self.alternatePushButton.text()
|
||||
|
@ -264,8 +260,7 @@ class ShortcutListForm(QtGui.QDialog, Ui_ShortcutListDialog):
|
|||
elif len(shortcuts) == 2:
|
||||
primary_text = shortcuts[0].toString()
|
||||
alternate_text = shortcuts[1].toString()
|
||||
# When we are capturing a new shortcut, we do not want, the buttons to
|
||||
# display the current shortcut.
|
||||
# When we are capturing a new shortcut, we do not want, the buttons to display the current shortcut.
|
||||
if self.primaryPushButton.isChecked():
|
||||
primary_text = u''
|
||||
if self.alternatePushButton.isChecked():
|
||||
|
@ -274,8 +269,7 @@ class ShortcutListForm(QtGui.QDialog, Ui_ShortcutListDialog):
|
|||
self.alternatePushButton.setText(alternate_text)
|
||||
self.primaryLabel.setText(primary_label_text)
|
||||
self.alternateLabel.setText(alternate_label_text)
|
||||
# We do not want to toggle and radio button, as the function has not
|
||||
# been triggered by a signal.
|
||||
# We do not want to toggle and radio button, as the function has not been triggered by a signal.
|
||||
if item is None:
|
||||
return
|
||||
if primary_label_text == primary_text and alternate_label_text == alternate_text:
|
||||
|
@ -303,8 +297,8 @@ class ShortcutListForm(QtGui.QDialog, Ui_ShortcutListDialog):
|
|||
|
||||
def onDefaultRadioButtonClicked(self, toggled):
|
||||
"""
|
||||
The default radio button has been clicked, which means we have to make
|
||||
sure, that we use the default shortcuts for the action.
|
||||
The default radio button has been clicked, which means we have to make sure, that we use the default shortcuts
|
||||
for the action.
|
||||
"""
|
||||
if not toggled:
|
||||
return
|
||||
|
@ -325,9 +319,8 @@ class ShortcutListForm(QtGui.QDialog, Ui_ShortcutListDialog):
|
|||
|
||||
def onCustomRadioButtonClicked(self, toggled):
|
||||
"""
|
||||
The custom shortcut radio button was clicked, thus we have to restore
|
||||
the custom shortcuts by calling those functions triggered by button
|
||||
clicks.
|
||||
The custom shortcut radio button was clicked, thus we have to restore the custom shortcuts by calling those
|
||||
functions triggered by button clicks.
|
||||
"""
|
||||
if not toggled:
|
||||
return
|
||||
|
@ -337,8 +330,8 @@ class ShortcutListForm(QtGui.QDialog, Ui_ShortcutListDialog):
|
|||
|
||||
def save(self):
|
||||
"""
|
||||
Save the shortcuts. **Note**, that we do not have to load the shortcuts,
|
||||
as they are loaded in :class:`~openlp.core.utils.ActionList`.
|
||||
Save the shortcuts. **Note**, that we do not have to load the shortcuts, as they are loaded in
|
||||
:class:`~openlp.core.utils.ActionList`.
|
||||
"""
|
||||
settings = Settings()
|
||||
settings.beginGroup(u'shortcuts')
|
||||
|
@ -348,8 +341,7 @@ class ShortcutListForm(QtGui.QDialog, Ui_ShortcutListDialog):
|
|||
continue
|
||||
for action in category.actions:
|
||||
if action in self.changedActions:
|
||||
old_shortcuts = map(unicode,
|
||||
map(QtGui.QKeySequence.toString, action.shortcuts()))
|
||||
old_shortcuts = map(QtGui.QKeySequence.toString, action.shortcuts())
|
||||
action.setShortcuts(self.changedActions[action])
|
||||
self.action_list.update_shortcut_map(action, old_shortcuts)
|
||||
settings.setValue(action.objectName(), action.shortcuts())
|
||||
|
@ -367,13 +359,10 @@ class ShortcutListForm(QtGui.QDialog, Ui_ShortcutListDialog):
|
|||
new_shortcuts = []
|
||||
if action.defaultShortcuts:
|
||||
new_shortcuts.append(action.defaultShortcuts[0])
|
||||
# We have to check if the primary default shortcut is available. But
|
||||
# we only have to check, if the action has a default primary
|
||||
# shortcut (an "empty" shortcut is always valid and if the action
|
||||
# does not have a default primary shortcut, then the alternative
|
||||
# shortcut (not the default one) will become primary shortcut, thus
|
||||
# the check will assume that an action were going to have the same
|
||||
# shortcut twice.
|
||||
# We have to check if the primary default shortcut is available. But we only have to check, if the action
|
||||
# has a default primary shortcut (an "empty" shortcut is always valid and if the action does not have a
|
||||
# default primary shortcut, then the alternative shortcut (not the default one) will become primary
|
||||
# shortcut, thus the check will assume that an action were going to have the same shortcut twice.
|
||||
if not self._validiate_shortcut(action, new_shortcuts[0]) and new_shortcuts[0] != shortcuts[0]:
|
||||
return
|
||||
if len(shortcuts) == 2:
|
||||
|
@ -405,9 +394,8 @@ class ShortcutListForm(QtGui.QDialog, Ui_ShortcutListDialog):
|
|||
|
||||
def _validiate_shortcut(self, changing_action, key_sequence):
|
||||
"""
|
||||
Checks if the given ``changing_action `` can use the given
|
||||
``key_sequence``. Returns ``True`` if the ``key_sequence`` can be used
|
||||
by the action, otherwise displays a dialog and returns ``False``.
|
||||
Checks if the given ``changing_action `` can use the given ``key_sequence``. Returns ``True`` if the
|
||||
``key_sequence`` can be used by the action, otherwise displays a dialog and returns ``False``.
|
||||
|
||||
``changing_action``
|
||||
The action which wants to use the ``key_sequence``.
|
||||
|
@ -429,27 +417,25 @@ class ShortcutListForm(QtGui.QDialog, Ui_ShortcutListDialog):
|
|||
# Have the same parent, thus they cannot have the same shortcut.
|
||||
if action.parent() is changing_action.parent():
|
||||
is_valid = False
|
||||
# The new shortcut is already assigned, but if both shortcuts
|
||||
# are only valid in a different widget the new shortcut is
|
||||
# vaild, because they will not interfere.
|
||||
if action.shortcutContext() in [QtCore.Qt.WindowShortcut,
|
||||
QtCore.Qt.ApplicationShortcut]:
|
||||
# The new shortcut is already assigned, but if both shortcuts are only valid in a different widget the
|
||||
# new shortcut is vaild, because they will not interfere.
|
||||
if action.shortcutContext() in [QtCore.Qt.WindowShortcut, QtCore.Qt.ApplicationShortcut]:
|
||||
is_valid = False
|
||||
if changing_action.shortcutContext() in [QtCore.Qt.WindowShortcut, QtCore.Qt.ApplicationShortcut]:
|
||||
is_valid = False
|
||||
if not is_valid:
|
||||
self.main_window.warning_message( translate('OpenLP.ShortcutListDialog', 'Duplicate Shortcut'),
|
||||
self.main_window.warning_message(translate('OpenLP.ShortcutListDialog', 'Duplicate Shortcut'),
|
||||
translate('OpenLP.ShortcutListDialog',
|
||||
'The shortcut "%s" is already assigned to another action, please use a different shortcut.') %
|
||||
key_sequence.toString()
|
||||
)
|
||||
self.dialog_was_shown = True
|
||||
return is_valid
|
||||
|
||||
def _actionShortcuts(self, action):
|
||||
"""
|
||||
This returns the shortcuts for the given ``action``, which also includes
|
||||
those shortcuts which are not saved yet but already assigned (as changes
|
||||
are applied when closing the dialog).
|
||||
This returns the shortcuts for the given ``action``, which also includes those shortcuts which are not saved
|
||||
yet but already assigned (as changes yre applied when closing the dialog).
|
||||
"""
|
||||
if action in self.changedActions:
|
||||
return self.changedActions[action]
|
||||
|
@ -457,8 +443,8 @@ class ShortcutListForm(QtGui.QDialog, Ui_ShortcutListDialog):
|
|||
|
||||
def _currentItemAction(self, item=None):
|
||||
"""
|
||||
Returns the action of the given ``item``. If no item is given, we return
|
||||
the action of the current item of the ``treeWidget``.
|
||||
Returns the action of the given ``item``. If no item is given, we return the action of the current item of
|
||||
the ``treeWidget``.
|
||||
"""
|
||||
if item is None:
|
||||
item = self.treeWidget.currentItem()
|
||||
|
@ -486,4 +472,5 @@ class ShortcutListForm(QtGui.QDialog, Ui_ShortcutListDialog):
|
|||
self._main_window = Registry().get(u'main_window')
|
||||
return self._main_window
|
||||
|
||||
main_window = property(_get_main_window)
|
||||
main_window = property(_get_main_window)
|
||||
|
||||
|
|
|
@ -44,6 +44,14 @@ from openlp.core.utils.actions import ActionList, CategoryOrder
|
|||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
AUDIO_TIME_LABEL_STYLESHEET = u'background-color: palette(background); ' \
|
||||
u'border-top-color: palette(shadow); ' \
|
||||
u'border-left-color: palette(shadow); ' \
|
||||
u'border-bottom-color: palette(light); ' \
|
||||
u'border-right-color: palette(light); ' \
|
||||
u'border-radius: 3px; border-style: inset; ' \
|
||||
u'border-width: 1; font-family: monospace; margin: 2px;'
|
||||
|
||||
|
||||
class DisplayController(QtGui.QWidget):
|
||||
"""
|
||||
|
@ -90,7 +98,6 @@ class SlideController(DisplayController):
|
|||
u'delaySpinBox'
|
||||
]
|
||||
self.audioList = [
|
||||
u'songMenu',
|
||||
u'audioPauseItem',
|
||||
u'audioTimeLabel'
|
||||
]
|
||||
|
@ -124,7 +131,7 @@ class SlideController(DisplayController):
|
|||
self.keypress_queue = deque()
|
||||
self.keypress_loop = False
|
||||
self.category = UiStrings().LiveToolbar
|
||||
ActionList.get_instance().add_category(unicode(self.category), CategoryOrder.standardToolbar)
|
||||
ActionList.get_instance().add_category(unicode(self.category), CategoryOrder.standard_toolbar)
|
||||
else:
|
||||
Registry().register(u'preview_controller', self)
|
||||
self.typeLabel.setText(UiStrings().Preview)
|
||||
|
@ -168,13 +175,13 @@ class SlideController(DisplayController):
|
|||
self.previousItem = create_action(self, u'previousItem_' + self.typePrefix,
|
||||
text=translate('OpenLP.SlideController', 'Previous Slide'), icon=u':/slides/slide_previous.png',
|
||||
tooltip=translate('OpenLP.SlideController', 'Move to previous.'),
|
||||
shortcuts=[QtCore.Qt.Key_Up, QtCore.Qt.Key_PageUp], context=QtCore.Qt.WidgetWithChildrenShortcut,
|
||||
can_shortcuts=True, context=QtCore.Qt.WidgetWithChildrenShortcut,
|
||||
category=self.category, triggers=self.on_slide_selected_previous)
|
||||
self.toolbar.addAction(self.previousItem)
|
||||
self.nextItem = create_action(self, u'nextItem_' + self.typePrefix,
|
||||
text=translate('OpenLP.SlideController', 'Next Slide'), icon=u':/slides/slide_next.png',
|
||||
tooltip=translate('OpenLP.SlideController', 'Move to next.'),
|
||||
shortcuts=[QtCore.Qt.Key_Down, QtCore.Qt.Key_PageDown], context=QtCore.Qt.WidgetWithChildrenShortcut,
|
||||
can_shortcuts=True, context=QtCore.Qt.WidgetWithChildrenShortcut,
|
||||
category=self.category, triggers=self.on_slide_selected_next_action)
|
||||
self.toolbar.addAction(self.nextItem)
|
||||
self.toolbar.addSeparator()
|
||||
|
@ -190,14 +197,14 @@ class SlideController(DisplayController):
|
|||
self.toolbar.addToolbarWidget(self.hideMenu)
|
||||
self.blankScreen = create_action(self, u'blankScreen',
|
||||
text=translate('OpenLP.SlideController', 'Blank Screen'), icon=u':/slides/slide_blank.png',
|
||||
checked=False, shortcuts=[QtCore.Qt.Key_Period], category=self.category, triggers=self.onBlankDisplay)
|
||||
checked=False, can_shortcuts=True, category=self.category, triggers=self.onBlankDisplay)
|
||||
self.themeScreen = create_action(self, u'themeScreen',
|
||||
text=translate('OpenLP.SlideController', 'Blank to Theme'), icon=u':/slides/slide_theme.png',
|
||||
checked=False, shortcuts=[QtGui.QKeySequence(u'T')], category=self.category,
|
||||
checked=False, can_shortcuts=True, category=self.category,
|
||||
triggers=self.onThemeDisplay)
|
||||
self.desktopScreen = create_action(self, u'desktopScreen',
|
||||
text=translate('OpenLP.SlideController', 'Show Desktop'), icon=u':/slides/slide_desktop.png',
|
||||
checked=False, shortcuts=[QtGui.QKeySequence(u'D')], category=self.category,
|
||||
checked=False, can_shortcuts=True, category=self.category,
|
||||
triggers=self.onHideDisplay)
|
||||
self.hideMenu.setDefaultAction(self.blankScreen)
|
||||
self.hideMenu.menu().addAction(self.blankScreen)
|
||||
|
@ -225,12 +232,12 @@ class SlideController(DisplayController):
|
|||
self.playSlidesMenu.setMenu(QtGui.QMenu(translate('OpenLP.SlideController', 'Play Slides'), self.toolbar))
|
||||
self.toolbar.addToolbarWidget(self.playSlidesMenu)
|
||||
self.playSlidesLoop = create_action(self, u'playSlidesLoop', text=UiStrings().PlaySlidesInLoop,
|
||||
icon=u':/media/media_time.png', checked=False, shortcuts=[],
|
||||
icon=u':/media/media_time.png', checked=False, can_shortcuts=True,
|
||||
category=self.category, triggers=self.onPlaySlidesLoop)
|
||||
self.playSlidesOnce = create_action(self, u'playSlidesOnce', text=UiStrings().PlaySlidesToEnd,
|
||||
icon=u':/media/media_time.png', checked=False, shortcuts=[],
|
||||
icon=u':/media/media_time.png', checked=False, can_shortcuts=True,
|
||||
category=self.category, triggers=self.onPlaySlidesOnce)
|
||||
if Settings().value(self.parent().advancedSettingsSection + u'/slide limits') == SlideLimits.Wrap:
|
||||
if Settings().value(self.main_window.advancedSettingsSection + u'/slide limits') == SlideLimits.Wrap:
|
||||
self.playSlidesMenu.setDefaultAction(self.playSlidesLoop)
|
||||
else:
|
||||
self.playSlidesMenu.setDefaultAction(self.playSlidesOnce)
|
||||
|
@ -267,7 +274,7 @@ class SlideController(DisplayController):
|
|||
icon=u':/slides/media_playback_pause.png', text=translate('OpenLP.SlideController', 'Pause Audio'),
|
||||
tooltip=translate('OpenLP.SlideController', 'Pause audio.'),
|
||||
checked=False, visible=False, category=self.category, context=QtCore.Qt.WindowShortcut,
|
||||
shortcuts=[], triggers=self.onAudioPauseClicked)
|
||||
can_shortcuts=True, triggers=self.onAudioPauseClicked)
|
||||
self.audioMenu = QtGui.QMenu(translate('OpenLP.SlideController', 'Background Audio'), self.toolbar)
|
||||
self.audioPauseItem.setMenu(self.audioMenu)
|
||||
self.audioPauseItem.setParent(self.toolbar)
|
||||
|
@ -276,23 +283,16 @@ class SlideController(DisplayController):
|
|||
self.nextTrackItem = create_action(self, u'nextTrackItem', text=UiStrings().NextTrack,
|
||||
icon=u':/slides/media_playback_next.png',
|
||||
tooltip=translate('OpenLP.SlideController', 'Go to next audio track.'),
|
||||
category=self.category, shortcuts=[], triggers=self.onNextTrackClicked)
|
||||
category=self.category, can_shortcuts=True, triggers=self.onNextTrackClicked)
|
||||
self.audioMenu.addAction(self.nextTrackItem)
|
||||
self.trackMenu = self.audioMenu.addMenu(translate('OpenLP.SlideController', 'Tracks'))
|
||||
self.audioTimeLabel = QtGui.QLabel(u' 00:00 ', self.toolbar)
|
||||
self.audioTimeLabel.setAlignment(QtCore.Qt.AlignCenter | QtCore.Qt.AlignHCenter)
|
||||
self.audioTimeLabel.setStyleSheet(
|
||||
u'background-color: palette(background); '
|
||||
u'border-top-color: palette(shadow); '
|
||||
u'border-left-color: palette(shadow); '
|
||||
u'border-bottom-color: palette(light); '
|
||||
u'border-right-color: palette(light); '
|
||||
u'border-radius: 3px; border-style: inset; '
|
||||
u'border-width: 1; font-family: monospace; margin: 2px;'
|
||||
)
|
||||
self.audioTimeLabel.setStyleSheet(AUDIO_TIME_LABEL_STYLESHEET)
|
||||
self.audioTimeLabel.setObjectName(u'audioTimeLabel')
|
||||
self.toolbar.addToolbarWidget(self.audioTimeLabel)
|
||||
self.toolbar.setWidgetVisible(self.audioList, False)
|
||||
self.toolbar.setWidgetVisible([u'songMenu'], False)
|
||||
# Screen preview area
|
||||
self.previewFrame = QtGui.QFrame(self.splitter)
|
||||
self.previewFrame.setGeometry(QtCore.QRect(0, 0, 300, 300 * self.ratio))
|
||||
|
@ -334,25 +334,20 @@ class SlideController(DisplayController):
|
|||
self.shortcutTimer = QtCore.QTimer()
|
||||
self.shortcutTimer.setObjectName(u'shortcutTimer')
|
||||
self.shortcutTimer.setSingleShot(True)
|
||||
shortcuts = [{u'key': u'V', u'configurable': True,
|
||||
u'text': translate('OpenLP.SlideController', 'Go to "Verse"')},
|
||||
{u'key': u'C', u'configurable': True,
|
||||
u'text': translate('OpenLP.SlideController', 'Go to "Chorus"')},
|
||||
{u'key': u'B', u'configurable': True,
|
||||
u'text': translate('OpenLP.SlideController', 'Go to "Bridge"')},
|
||||
shortcuts = [
|
||||
{u'key': u'V', u'configurable': True, u'text': translate('OpenLP.SlideController', 'Go to "Verse"')},
|
||||
{u'key': u'C', u'configurable': True, u'text': translate('OpenLP.SlideController', 'Go to "Chorus"')},
|
||||
{u'key': u'B', u'configurable': True, u'text': translate('OpenLP.SlideController', 'Go to "Bridge"')},
|
||||
{u'key': u'P', u'configurable': True,
|
||||
u'text': translate('OpenLP.SlideController',
|
||||
'Go to "Pre-Chorus"')},
|
||||
{u'key': u'I', u'configurable': True,
|
||||
u'text': translate('OpenLP.SlideController', 'Go to "Intro"')},
|
||||
{u'key': u'E', u'configurable': True,
|
||||
u'text': translate('OpenLP.SlideController', 'Go to "Ending"')},
|
||||
{u'key': u'O', u'configurable': True,
|
||||
u'text': translate('OpenLP.SlideController', 'Go to "Other"')}]
|
||||
shortcuts += [{u'key': unicode(number)} for number in range(10)]
|
||||
u'text': translate('OpenLP.SlideController', 'Go to "Pre-Chorus"')},
|
||||
{u'key': u'I', u'configurable': True, u'text': translate('OpenLP.SlideController', 'Go to "Intro"')},
|
||||
{u'key': u'E', u'configurable': True, u'text': translate('OpenLP.SlideController', 'Go to "Ending"')},
|
||||
{u'key': u'O', u'configurable': True, u'text': translate('OpenLP.SlideController', 'Go to "Other"')}
|
||||
]
|
||||
shortcuts.extend([{u'key': unicode(number)} for number in range(10)])
|
||||
self.previewListWidget.addActions([create_action(self,
|
||||
u'shortcutAction_%s' % s[u'key'], text=s.get(u'text'),
|
||||
shortcuts=[QtGui.QKeySequence(s[u'key'])],
|
||||
can_shortcuts=True,
|
||||
context=QtCore.Qt.WidgetWithChildrenShortcut,
|
||||
category=self.category if s.get(u'configurable') else None,
|
||||
triggers=self._slideShortcutActivated) for s in shortcuts])
|
||||
|
@ -404,19 +399,19 @@ class SlideController(DisplayController):
|
|||
verse_type = sender_name[15:] if sender_name[:15] == u'shortcutAction_' else u''
|
||||
if SONGS_PLUGIN_AVAILABLE:
|
||||
if verse_type == u'V':
|
||||
self.current_shortcut = VerseType.TranslatedTags[VerseType.Verse]
|
||||
self.current_shortcut = VerseType.translated_tags[VerseType.Verse]
|
||||
elif verse_type == u'C':
|
||||
self.current_shortcut = VerseType.TranslatedTags[VerseType.Chorus]
|
||||
self.current_shortcut = VerseType.translated_tags[VerseType.Chorus]
|
||||
elif verse_type == u'B':
|
||||
self.current_shortcut = VerseType.TranslatedTags[VerseType.Bridge]
|
||||
self.current_shortcut = VerseType.translated_tags[VerseType.Bridge]
|
||||
elif verse_type == u'P':
|
||||
self.current_shortcut = VerseType.TranslatedTags[VerseType.PreChorus]
|
||||
self.current_shortcut = VerseType.translated_tags[VerseType.PreChorus]
|
||||
elif verse_type == u'I':
|
||||
self.current_shortcut = VerseType.TranslatedTags[VerseType.Intro]
|
||||
self.current_shortcut = VerseType.translated_tags[VerseType.Intro]
|
||||
elif verse_type == u'E':
|
||||
self.current_shortcut = VerseType.TranslatedTags[VerseType.Ending]
|
||||
self.current_shortcut = VerseType.translated_tags[VerseType.Ending]
|
||||
elif verse_type == u'O':
|
||||
self.current_shortcut = VerseType.TranslatedTags[VerseType.Other]
|
||||
self.current_shortcut = VerseType.translated_tags[VerseType.Other]
|
||||
elif verse_type.isnumeric():
|
||||
self.current_shortcut += verse_type
|
||||
self.current_shortcut = self.current_shortcut.upper()
|
||||
|
@ -451,15 +446,15 @@ class SlideController(DisplayController):
|
|||
"""
|
||||
self.previousService = create_action(parent, u'previousService',
|
||||
text=translate('OpenLP.SlideController', 'Previous Service'),
|
||||
shortcuts=[QtCore.Qt.Key_Left], context=QtCore.Qt.WidgetWithChildrenShortcut, category=self.category,
|
||||
can_shortcuts=True, context=QtCore.Qt.WidgetWithChildrenShortcut, category=self.category,
|
||||
triggers=self.servicePrevious)
|
||||
self.nextService = create_action(parent, 'nextService',
|
||||
text=translate('OpenLP.SlideController', 'Next Service'),
|
||||
shortcuts=[QtCore.Qt.Key_Right], context=QtCore.Qt.WidgetWithChildrenShortcut, category=self.category,
|
||||
can_shortcuts=True, context=QtCore.Qt.WidgetWithChildrenShortcut, category=self.category,
|
||||
triggers=self.serviceNext)
|
||||
self.escapeItem = create_action(parent, 'escapeItem',
|
||||
text=translate('OpenLP.SlideController', 'Escape Item'),
|
||||
shortcuts=[QtCore.Qt.Key_Escape], context=QtCore.Qt.WidgetWithChildrenShortcut, category=self.category,
|
||||
can_shortcuts=True, context=QtCore.Qt.WidgetWithChildrenShortcut, category=self.category,
|
||||
triggers=self.liveEscape)
|
||||
|
||||
def liveEscape(self):
|
||||
|
@ -582,7 +577,7 @@ class SlideController(DisplayController):
|
|||
self.previewListWidget.resizeRowsToContents()
|
||||
else:
|
||||
# Sort out image heights.
|
||||
width = self.parent().controlSplitter.sizes()[self.split]
|
||||
width = self.main_window.controlSplitter.sizes()[self.split]
|
||||
for framenumber in range(len(self.serviceItem.get_frames())):
|
||||
self.previewListWidget.setRowHeight(framenumber, width / self.ratio)
|
||||
self.onControllerSizeChanged(self.controller.width(), self.controller.height())
|
||||
|
@ -592,10 +587,14 @@ class SlideController(DisplayController):
|
|||
Change layout of display control buttons on controller size change
|
||||
"""
|
||||
if self.isLive:
|
||||
if width > 300 and self.hideMenu.isVisible():
|
||||
# Space used by the toolbar.
|
||||
used_space = self.toolbar.size().width() + self.hideMenu.size().width()
|
||||
# The + 40 is needed to prevent flickering. This can be considered a "buffer".
|
||||
if width > used_space + 40 and self.hideMenu.isVisible():
|
||||
self.toolbar.setWidgetVisible(self.hideMenuList, False)
|
||||
self.toolbar.setWidgetVisible(self.wideMenu)
|
||||
elif width < 300 and not self.hideMenu.isVisible():
|
||||
# The - 40 is needed to prevent flickering. This can be considered a "buffer".
|
||||
elif width < used_space - 40 and not self.hideMenu.isVisible():
|
||||
self.toolbar.setWidgetVisible(self.wideMenu, False)
|
||||
self.toolbar.setWidgetVisible(self.hideMenuList)
|
||||
|
||||
|
@ -618,7 +617,7 @@ class SlideController(DisplayController):
|
|||
"""
|
||||
Updates the Slide Limits variable from the settings.
|
||||
"""
|
||||
self.slide_limits = Settings().value(self.parent().advancedSettingsSection + u'/slide limits')
|
||||
self.slide_limits = Settings().value(self.main_window.advancedSettingsSection + u'/slide limits')
|
||||
|
||||
def enableToolBar(self, item):
|
||||
"""
|
||||
|
@ -640,14 +639,15 @@ class SlideController(DisplayController):
|
|||
self.mediabar.hide()
|
||||
self.songMenu.hide()
|
||||
self.toolbar.setWidgetVisible(self.loopList, False)
|
||||
self.toolbar.setWidgetVisible([u'songMenu'], False)
|
||||
# Reset the button
|
||||
self.playSlidesOnce.setChecked(False)
|
||||
self.playSlidesOnce.setIcon(build_icon(u':/media/media_time.png'))
|
||||
self.playSlidesLoop.setChecked(False)
|
||||
self.playSlidesLoop.setIcon(build_icon(u':/media/media_time.png'))
|
||||
if item.is_text():
|
||||
if Settings().value(self.parent().songsSettingsSection + u'/display songbar') and self.slideList:
|
||||
self.songMenu.show()
|
||||
if Settings().value(self.main_window.songsSettingsSection + u'/display songbar') and self.slideList:
|
||||
self.toolbar.setWidgetVisible([u'songMenu'], True)
|
||||
if item.is_capable(ItemCapabilities.CanLoop) and len(item.get_frames()) > 1:
|
||||
self.toolbar.setWidgetVisible(self.loopList)
|
||||
if item.is_media():
|
||||
|
@ -748,7 +748,7 @@ class SlideController(DisplayController):
|
|||
self._resetBlank()
|
||||
Registry().execute(u'%s_start' % serviceItem.name.lower(), [serviceItem, self.isLive, self.hideMode(), slideno])
|
||||
self.slideList = {}
|
||||
width = self.parent().controlSplitter.sizes()[self.split]
|
||||
width = self.main_window.controlSplitter.sizes()[self.split]
|
||||
self.previewListWidget.clear()
|
||||
self.previewListWidget.setRowCount(0)
|
||||
self.previewListWidget.setColumnWidth(0, width)
|
||||
|
@ -767,8 +767,8 @@ class SlideController(DisplayController):
|
|||
action.setData(counter)
|
||||
QtCore.QObject.connect(action, QtCore.SIGNAL(u'triggered(bool)'), self.onTrackTriggered)
|
||||
self.display.audioPlayer.repeat = Settings().value(
|
||||
self.parent().generalSettingsSection + u'/audio repeat list')
|
||||
if Settings().value(self.parent().generalSettingsSection + u'/audio start paused'):
|
||||
self.main_window.generalSettingsSection + u'/audio repeat list')
|
||||
if Settings().value(self.main_window.generalSettingsSection + u'/audio start paused'):
|
||||
self.audioPauseItem.setChecked(True)
|
||||
self.display.audioPlayer.pause()
|
||||
else:
|
||||
|
@ -877,7 +877,7 @@ class SlideController(DisplayController):
|
|||
Allow the main display to blank the main display at startup time
|
||||
"""
|
||||
log.debug(u'mainDisplaySetBackground live = %s' % self.isLive)
|
||||
display_type = Settings().value(self.parent().generalSettingsSection + u'/screen blank')
|
||||
display_type = Settings().value(self.main_window.generalSettingsSection + u'/screen blank')
|
||||
if self.screens.which_screen(self.window()) != self.screens.which_screen(self.display):
|
||||
# Order done to handle initial conversion
|
||||
if display_type == u'themed':
|
||||
|
@ -915,9 +915,9 @@ class SlideController(DisplayController):
|
|||
self.themeScreen.setChecked(False)
|
||||
self.desktopScreen.setChecked(False)
|
||||
if checked:
|
||||
Settings().setValue(self.parent().generalSettingsSection + u'/screen blank', u'blanked')
|
||||
Settings().setValue(self.main_window.generalSettingsSection + u'/screen blank', u'blanked')
|
||||
else:
|
||||
Settings().remove(self.parent().generalSettingsSection + u'/screen blank')
|
||||
Settings().remove(self.main_window.generalSettingsSection + u'/screen blank')
|
||||
self.blankPlugin()
|
||||
self.updatePreview()
|
||||
self.onToggleLoop()
|
||||
|
@ -934,9 +934,9 @@ class SlideController(DisplayController):
|
|||
self.themeScreen.setChecked(checked)
|
||||
self.desktopScreen.setChecked(False)
|
||||
if checked:
|
||||
Settings().setValue(self.parent().generalSettingsSection + u'/screen blank', u'themed')
|
||||
Settings().setValue(self.main_window.generalSettingsSection + u'/screen blank', u'themed')
|
||||
else:
|
||||
Settings().remove(self.parent().generalSettingsSection + u'/screen blank')
|
||||
Settings().remove(self.main_window.generalSettingsSection + u'/screen blank')
|
||||
self.blankPlugin()
|
||||
self.updatePreview()
|
||||
self.onToggleLoop()
|
||||
|
@ -953,9 +953,9 @@ class SlideController(DisplayController):
|
|||
self.themeScreen.setChecked(False)
|
||||
self.desktopScreen.setChecked(checked)
|
||||
if checked:
|
||||
Settings().setValue(self.parent().generalSettingsSection + u'/screen blank', u'hidden')
|
||||
Settings().setValue(self.main_window.generalSettingsSection + u'/screen blank', u'hidden')
|
||||
else:
|
||||
Settings().remove(self.parent().generalSettingsSection + u'/screen blank')
|
||||
Settings().remove(self.main_window.generalSettingsSection + u'/screen blank')
|
||||
self.hidePlugin(checked)
|
||||
self.updatePreview()
|
||||
self.onToggleLoop()
|
||||
|
@ -1255,7 +1255,7 @@ class SlideController(DisplayController):
|
|||
|
||||
def onGoLive(self):
|
||||
"""
|
||||
If preview copy slide item to live
|
||||
If preview copy slide item to live controller from Preview Controller
|
||||
"""
|
||||
row = self.previewListWidget.currentRow()
|
||||
if -1 < row < self.previewListWidget.rowCount():
|
||||
|
@ -1384,3 +1384,14 @@ class SlideController(DisplayController):
|
|||
return self._live_controller
|
||||
|
||||
live_controller = property(_get_live_controller)
|
||||
|
||||
def _get_main_window(self):
|
||||
"""
|
||||
Adds the main window to the class dynamically
|
||||
"""
|
||||
if not hasattr(self, u'_main_window'):
|
||||
self._main_window = Registry().get(u'main_window')
|
||||
return self._main_window
|
||||
|
||||
main_window = property(_get_main_window)
|
||||
|
||||
|
|
|
@ -38,9 +38,8 @@ import re
|
|||
from xml.etree.ElementTree import ElementTree, XML
|
||||
from PyQt4 import QtCore, QtGui
|
||||
|
||||
from openlp.core.lib import ImageSource, OpenLPToolbar, Registry, SettingsManager, Settings, UiStrings, \
|
||||
get_text_file_string, build_icon, translate, check_item_selected, check_directory_exists, create_thumb, \
|
||||
validate_thumb
|
||||
from openlp.core.lib import ImageSource, OpenLPToolbar, Registry, Settings, UiStrings, get_text_file_string, \
|
||||
build_icon, translate, check_item_selected, check_directory_exists, create_thumb, validate_thumb
|
||||
from openlp.core.lib.theme import ThemeXML, BackgroundType, VerticalType, BackgroundGradientType
|
||||
from openlp.core.lib.ui import critical_error_message_box, create_widget_action
|
||||
from openlp.core.theme import Theme
|
||||
|
@ -105,8 +104,7 @@ class ThemeManager(QtGui.QWidget):
|
|||
self.theme_list_widget.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
|
||||
self.theme_list_widget.setObjectName(u'theme_list_widget')
|
||||
self.layout.addWidget(self.theme_list_widget)
|
||||
QtCore.QObject.connect(self.theme_list_widget, QtCore.SIGNAL('customContextMenuRequested(QPoint)'),
|
||||
self.context_menu)
|
||||
self.theme_list_widget.customContextMenuRequested.connect(self.context_menu)
|
||||
# build the context menu
|
||||
self.menu = QtGui.QMenu()
|
||||
self.edit_action = create_widget_action(self.menu,
|
||||
|
@ -130,10 +128,8 @@ class ThemeManager(QtGui.QWidget):
|
|||
text=translate('OpenLP.ThemeManager', '&Export Theme'),
|
||||
icon=u':/general/general_export.png', triggers=self.on_export_theme)
|
||||
# Signals
|
||||
QtCore.QObject.connect(self.theme_list_widget,
|
||||
QtCore.SIGNAL(u'doubleClicked(QModelIndex)'), self.change_global_from_screen)
|
||||
QtCore.QObject.connect(self.theme_list_widget,
|
||||
QtCore.SIGNAL(u'currentItemChanged(QListWidgetItem *, QListWidgetItem *)'), self.check_list_state)
|
||||
self.theme_list_widget.doubleClicked.connect(self.change_global_from_screen)
|
||||
self.theme_list_widget.currentItemChanged.connect(self.check_list_state)
|
||||
Registry().register_function(u'theme_update_global', self.change_global_from_tab)
|
||||
Registry().register_function(u'config_updated', self.config_updated)
|
||||
# Variables
|
||||
|
@ -153,14 +149,13 @@ class ThemeManager(QtGui.QWidget):
|
|||
Import new themes downloaded by the first time wizard
|
||||
"""
|
||||
self.application.set_busy_cursor()
|
||||
files = SettingsManager.get_files(self.settingsSection, u'.otz')
|
||||
files = AppLocation.get_files(self.settingsSection, u'.otz')
|
||||
for theme_file in files:
|
||||
theme_file = os.path.join(self.path, theme_file)
|
||||
self.unzip_theme(theme_file, self.path)
|
||||
delete_file(theme_file)
|
||||
self.application.set_normal_cursor()
|
||||
|
||||
|
||||
def config_updated(self):
|
||||
"""
|
||||
Triggered when Config dialog is updated.
|
||||
|
@ -423,10 +418,10 @@ class ThemeManager(QtGui.QWidget):
|
|||
log.debug(u'Load themes from dir')
|
||||
self.theme_list = []
|
||||
self.theme_list_widget.clear()
|
||||
files = SettingsManager.get_files(self.settingsSection, u'.png')
|
||||
files = AppLocation.get_files(self.settingsSection, u'.png')
|
||||
if first_time:
|
||||
self.first_time()
|
||||
files = SettingsManager.get_files(self.settingsSection, u'.png')
|
||||
files = AppLocation.get_files(self.settingsSection, u'.png')
|
||||
# No themes have been found so create one
|
||||
if not files:
|
||||
theme = ThemeXML()
|
||||
|
@ -434,7 +429,7 @@ class ThemeManager(QtGui.QWidget):
|
|||
self._write_theme(theme, None, None)
|
||||
Settings().setValue(self.settingsSection + u'/global theme', theme.theme_name)
|
||||
self.config_updated()
|
||||
files = SettingsManager.get_files(self.settingsSection, u'.png')
|
||||
files = AppLocation.get_files(self.settingsSection, u'.png')
|
||||
# Sort the themes by its name considering language specific
|
||||
files.sort(key=lambda file_name: unicode(file_name), cmp=locale_compare)
|
||||
# now process the file list of png files
|
||||
|
|
|
@ -39,9 +39,10 @@ from subprocess import Popen, PIPE
|
|||
import sys
|
||||
import urllib2
|
||||
|
||||
from PyQt4 import QtGui, QtCore
|
||||
|
||||
from openlp.core.lib import Registry, Settings
|
||||
|
||||
from PyQt4 import QtGui, QtCore
|
||||
|
||||
if sys.platform != u'win32' and sys.platform != u'darwin':
|
||||
try:
|
||||
|
@ -50,8 +51,7 @@ if sys.platform != u'win32' and sys.platform != u'darwin':
|
|||
except ImportError:
|
||||
XDG_BASE_AVAILABLE = False
|
||||
|
||||
import openlp
|
||||
from openlp.core.lib import translate, check_directory_exists
|
||||
from openlp.core.lib import translate
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
APPLICATION_VERSION = {}
|
||||
|
@ -78,107 +78,6 @@ class VersionThread(QtCore.QThread):
|
|||
if LooseVersion(str(version)) > LooseVersion(str(app_version[u'full'])):
|
||||
Registry().execute(u'openlp_version_check', u'%s' % version)
|
||||
|
||||
class AppLocation(object):
|
||||
"""
|
||||
The :class:`AppLocation` class is a static class which retrieves a
|
||||
directory based on the directory type.
|
||||
"""
|
||||
AppDir = 1
|
||||
ConfigDir = 2
|
||||
DataDir = 3
|
||||
PluginsDir = 4
|
||||
VersionDir = 5
|
||||
CacheDir = 6
|
||||
LanguageDir = 7
|
||||
|
||||
# Base path where data/config/cache dir is located
|
||||
BaseDir = None
|
||||
|
||||
@staticmethod
|
||||
def get_directory(dir_type=1):
|
||||
"""
|
||||
Return the appropriate directory according to the directory type.
|
||||
|
||||
``dir_type``
|
||||
The directory type you want, for instance the data directory.
|
||||
"""
|
||||
if dir_type == AppLocation.AppDir:
|
||||
return _get_frozen_path(os.path.abspath(os.path.split(sys.argv[0])[0]), os.path.split(openlp.__file__)[0])
|
||||
elif dir_type == AppLocation.PluginsDir:
|
||||
app_path = os.path.abspath(os.path.split(sys.argv[0])[0])
|
||||
return _get_frozen_path(os.path.join(app_path, u'plugins'),
|
||||
os.path.join(os.path.split(openlp.__file__)[0], u'plugins'))
|
||||
elif dir_type == AppLocation.VersionDir:
|
||||
return _get_frozen_path(os.path.abspath(os.path.split(sys.argv[0])[0]), os.path.split(openlp.__file__)[0])
|
||||
elif dir_type == AppLocation.LanguageDir:
|
||||
app_path = _get_frozen_path(os.path.abspath(os.path.split(sys.argv[0])[0]), _get_os_dir_path(dir_type))
|
||||
return os.path.join(app_path, u'i18n')
|
||||
elif dir_type == AppLocation.DataDir and AppLocation.BaseDir:
|
||||
return os.path.join(AppLocation.BaseDir, 'data')
|
||||
else:
|
||||
return _get_os_dir_path(dir_type)
|
||||
|
||||
@staticmethod
|
||||
def get_data_path():
|
||||
"""
|
||||
Return the path OpenLP stores all its data under.
|
||||
"""
|
||||
# Check if we have a different data location.
|
||||
if Settings().contains(u'advanced/data path'):
|
||||
path = Settings().value(u'advanced/data path')
|
||||
else:
|
||||
path = AppLocation.get_directory(AppLocation.DataDir)
|
||||
check_directory_exists(path)
|
||||
return os.path.normpath(path)
|
||||
|
||||
@staticmethod
|
||||
def get_section_data_path(section):
|
||||
"""
|
||||
Return the path a particular module stores its data under.
|
||||
"""
|
||||
data_path = AppLocation.get_data_path()
|
||||
path = os.path.join(data_path, section)
|
||||
check_directory_exists(path)
|
||||
return path
|
||||
|
||||
|
||||
def _get_os_dir_path(dir_type):
|
||||
"""
|
||||
Return a path based on which OS and environment we are running in.
|
||||
"""
|
||||
encoding = sys.getfilesystemencoding()
|
||||
if sys.platform == u'win32':
|
||||
if dir_type == AppLocation.DataDir:
|
||||
return os.path.join(unicode(os.getenv(u'APPDATA'), encoding), u'openlp', u'data')
|
||||
elif dir_type == AppLocation.LanguageDir:
|
||||
return os.path.split(openlp.__file__)[0]
|
||||
return os.path.join(unicode(os.getenv(u'APPDATA'), encoding), u'openlp')
|
||||
elif sys.platform == u'darwin':
|
||||
if dir_type == AppLocation.DataDir:
|
||||
return os.path.join(unicode(os.getenv(u'HOME'), encoding),
|
||||
u'Library', u'Application Support', u'openlp', u'Data')
|
||||
elif dir_type == AppLocation.LanguageDir:
|
||||
return os.path.split(openlp.__file__)[0]
|
||||
return os.path.join(unicode(os.getenv(u'HOME'), encoding), u'Library', u'Application Support', u'openlp')
|
||||
else:
|
||||
if dir_type == AppLocation.LanguageDir:
|
||||
prefixes = [u'/usr/local', u'/usr']
|
||||
for prefix in prefixes:
|
||||
directory = os.path.join(prefix, u'share', u'openlp')
|
||||
if os.path.exists(directory):
|
||||
return directory
|
||||
return os.path.join(u'/usr', u'share', u'openlp')
|
||||
if XDG_BASE_AVAILABLE:
|
||||
if dir_type == AppLocation.ConfigDir:
|
||||
return os.path.join(unicode(BaseDirectory.xdg_config_home, encoding), u'openlp')
|
||||
elif dir_type == AppLocation.DataDir:
|
||||
return os.path.join(unicode(BaseDirectory.xdg_data_home, encoding), u'openlp')
|
||||
elif dir_type == AppLocation.CacheDir:
|
||||
return os.path.join(unicode(BaseDirectory.xdg_cache_home, encoding), u'openlp')
|
||||
if dir_type == AppLocation.DataDir:
|
||||
return os.path.join(unicode(os.getenv(u'HOME'), encoding), u'.openlp', u'data')
|
||||
return os.path.join(unicode(os.getenv(u'HOME'), encoding), u'.openlp')
|
||||
|
||||
|
||||
def _get_frozen_path(frozen_option, non_frozen_option):
|
||||
"""
|
||||
|
@ -497,9 +396,11 @@ def locale_compare(string1, string2):
|
|||
locale_direct_compare = locale.strcoll
|
||||
|
||||
|
||||
from applocation import AppLocation
|
||||
from languagemanager import LanguageManager
|
||||
from actions import ActionList
|
||||
|
||||
|
||||
__all__ = [u'AppLocation', u'ActionList', u'LanguageManager', u'get_application_version', u'check_latest_version',
|
||||
u'add_actions', u'get_filesystem_encoding', u'get_web_page', u'get_uno_command', u'get_uno_instance',
|
||||
u'delete_file', u'clean_filename', u'format_time', u'locale_compare', u'locale_direct_compare']
|
||||
|
|
|
@ -37,8 +37,8 @@ from openlp.core.lib import Settings
|
|||
|
||||
class ActionCategory(object):
|
||||
"""
|
||||
The :class:`~openlp.core.utils.ActionCategory` class encapsulates a
|
||||
category for the :class:`~openlp.core.utils.CategoryList` class.
|
||||
The :class:`~openlp.core.utils.ActionCategory` class encapsulates a category for the
|
||||
:class:`~openlp.core.utils.CategoryList` class.
|
||||
"""
|
||||
def __init__(self, name, weight=0):
|
||||
"""
|
||||
|
@ -51,8 +51,7 @@ class ActionCategory(object):
|
|||
|
||||
class CategoryActionList(object):
|
||||
"""
|
||||
The :class:`~openlp.core.utils.CategoryActionList` class provides a sorted
|
||||
list of actions within a category.
|
||||
The :class:`~openlp.core.utils.CategoryActionList` class provides a sorted list of actions within a category.
|
||||
"""
|
||||
def __init__(self):
|
||||
"""
|
||||
|
@ -142,9 +141,9 @@ class CategoryActionList(object):
|
|||
|
||||
class CategoryList(object):
|
||||
"""
|
||||
The :class:`~openlp.core.utils.CategoryList` class encapsulates a category
|
||||
list for the :class:`~openlp.core.utils.ActionList` class and provides an
|
||||
iterator interface for walking through the list of actions in this category.
|
||||
The :class:`~openlp.core.utils.CategoryList` class encapsulates a category list for the
|
||||
:class:`~openlp.core.utils.ActionList` class and provides an iterator interface for walking through the list of
|
||||
actions in this category.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
|
@ -244,10 +243,9 @@ class CategoryList(object):
|
|||
|
||||
class ActionList(object):
|
||||
"""
|
||||
The :class:`~openlp.core.utils.ActionList` class contains a list of menu
|
||||
actions and categories associated with those actions. Each category also
|
||||
has a weight by which it is sorted when iterating through the list of
|
||||
actions or categories.
|
||||
The :class:`~openlp.core.utils.ActionList` class contains a list of menu actions and categories associated with
|
||||
those actions. Each category also has a weight by which it is sorted when iterating through the list of actions or
|
||||
categories.
|
||||
"""
|
||||
instance = None
|
||||
shortcut_map = {}
|
||||
|
@ -271,48 +269,44 @@ class ActionList(object):
|
|||
"""
|
||||
Add an action to the list of actions.
|
||||
|
||||
**Note**: The action's objectName must be set when you want to add it!
|
||||
|
||||
``action``
|
||||
The action to add (QAction). **Note**, the action must not have an
|
||||
empty ``objectName``.
|
||||
The action to add (QAction). **Note**, the action must not have an empty ``objectName``.
|
||||
|
||||
``category``
|
||||
The category this action belongs to. The category has to be a python
|
||||
string. . **Note**, if the category is ``None``, the category and
|
||||
its actions are being hidden in the shortcut dialog. However, if
|
||||
they are added, it is possible to avoid assigning shortcuts twice,
|
||||
which is important.
|
||||
The category this action belongs to. The category has to be a python string. . **Note**, if the category
|
||||
is ``None``, the category and its actions are being hidden in the shortcut dialog. However, if they are
|
||||
added, it is possible to avoid assigning shortcuts twice, which is important.
|
||||
|
||||
``weight``
|
||||
The weight specifies how important a category is. However, this only
|
||||
has an impact on the order the categories are displayed.
|
||||
The weight specifies how important a category is. However, this only has an impact on the order the
|
||||
categories are displayed.
|
||||
"""
|
||||
if category not in self.categories:
|
||||
self.categories.append(category)
|
||||
action.defaultShortcuts = action.shortcuts()
|
||||
settings = Settings()
|
||||
settings.beginGroup(u'shortcuts')
|
||||
# Get the default shortcut from the config.
|
||||
action.defaultShortcuts = settings.get_default_value(action.objectName())
|
||||
if weight is None:
|
||||
self.categories[category].actions.append(action)
|
||||
else:
|
||||
self.categories[category].actions.add(action, weight)
|
||||
# Load the shortcut from the config.
|
||||
settings = Settings()
|
||||
settings.beginGroup(u'shortcuts')
|
||||
shortcuts = settings.value(action.objectName())
|
||||
settings.endGroup()
|
||||
if not shortcuts:
|
||||
action.setShortcuts([])
|
||||
return
|
||||
# We have to do this to ensure that the loaded shortcut list e. g.
|
||||
# STRG+O (German) is converted to CTRL+O, which is only done when we
|
||||
# convert the strings in this way (QKeySequence -> QString -> unicode).
|
||||
shortcuts = map(QtGui.QKeySequence, shortcuts)
|
||||
shortcuts = map(unicode, map(QtGui.QKeySequence.toString, shortcuts))
|
||||
# Check the alternate shortcut first, to avoid problems when the
|
||||
# alternate shortcut becomes the primary shortcut after removing the
|
||||
# (initial) primary shortcut due to conflicts.
|
||||
# We have to do this to ensure that the loaded shortcut list e. g. STRG+O (German) is converted to CTRL+O,
|
||||
# which is only done when we convert the strings in this way (QKeySequencet -> uncode).
|
||||
shortcuts = map(QtGui.QKeySequence.toString, map(QtGui.QKeySequence, shortcuts))
|
||||
# Check the alternate shortcut first, to avoid problems when the alternate shortcut becomes the primary shortcut
|
||||
# after removing the (initial) primary shortcut due to conflicts.
|
||||
if len(shortcuts) == 2:
|
||||
existing_actions = ActionList.shortcut_map.get(shortcuts[1], [])
|
||||
# Check for conflicts with other actions considering the shortcut
|
||||
# context.
|
||||
# Check for conflicts with other actions considering the shortcut context.
|
||||
if self._is_shortcut_available(existing_actions, action):
|
||||
actions = ActionList.shortcut_map.get(shortcuts[1], [])
|
||||
actions.append(action)
|
||||
|
@ -321,28 +315,24 @@ class ActionList(object):
|
|||
shortcuts.remove(shortcuts[1])
|
||||
# Check the primary shortcut.
|
||||
existing_actions = ActionList.shortcut_map.get(shortcuts[0], [])
|
||||
# Check for conflicts with other actions considering the shortcut
|
||||
# context.
|
||||
# Check for conflicts with other actions considering the shortcut context.
|
||||
if self._is_shortcut_available(existing_actions, action):
|
||||
actions = ActionList.shortcut_map.get(shortcuts[0], [])
|
||||
actions.append(action)
|
||||
ActionList.shortcut_map[shortcuts[0]] = actions
|
||||
else:
|
||||
shortcuts.remove(shortcuts[0])
|
||||
action.setShortcuts(
|
||||
[QtGui.QKeySequence(shortcut) for shortcut in shortcuts])
|
||||
action.setShortcuts([QtGui.QKeySequence(shortcut) for shortcut in shortcuts])
|
||||
|
||||
def remove_action(self, action, category=None):
|
||||
"""
|
||||
This removes an action from its category. Empty categories are
|
||||
automatically removed.
|
||||
This removes an action from its category. Empty categories are automatically removed.
|
||||
|
||||
``action``
|
||||
The ``QAction`` object to be removed.
|
||||
|
||||
``category``
|
||||
The name (unicode string) of the category, which contains the
|
||||
action. Defaults to None.
|
||||
The name (unicode string) of the category, which contains the action. Defaults to None.
|
||||
"""
|
||||
if category not in self.categories:
|
||||
return
|
||||
|
@ -350,10 +340,9 @@ class ActionList(object):
|
|||
# Remove empty categories.
|
||||
if not self.categories[category].actions:
|
||||
self.categories.remove(category)
|
||||
shortcuts = map(unicode, map(QtGui.QKeySequence.toString, action.shortcuts()))
|
||||
shortcuts = map(QtGui.QKeySequence.toString, action.shortcuts())
|
||||
for shortcut in shortcuts:
|
||||
# Remove action from the list of actions which are using this
|
||||
# shortcut.
|
||||
# Remove action from the list of actions which are using this shortcut.
|
||||
ActionList.shortcut_map[shortcut].remove(action)
|
||||
# Remove empty entries.
|
||||
if not ActionList.shortcut_map[shortcut]:
|
||||
|
@ -361,8 +350,7 @@ class ActionList(object):
|
|||
|
||||
def add_category(self, name, weight):
|
||||
"""
|
||||
Add an empty category to the list of categories. This is ony convenient
|
||||
for categories with a given weight.
|
||||
Add an empty category to the list of categories. This is only convenient for categories with a given weight.
|
||||
|
||||
``name``
|
||||
The category's name.
|
||||
|
@ -381,27 +369,24 @@ class ActionList(object):
|
|||
|
||||
def update_shortcut_map(self, action, old_shortcuts):
|
||||
"""
|
||||
Remove the action for the given ``old_shortcuts`` from the
|
||||
``shortcut_map`` to ensure its up-to-dateness.
|
||||
Remove the action for the given ``old_shortcuts`` from the ``shortcut_map`` to ensure its up-to-dateness.
|
||||
|
||||
**Note**: The new action's shortcuts **must** be assigned to the given
|
||||
``action`` **before** calling this method.
|
||||
**Note**: The new action's shortcuts **must** be assigned to the given ``action`` **before** calling this
|
||||
method.
|
||||
|
||||
``action``
|
||||
The action whose shortcuts are supposed to be updated in the
|
||||
``shortcut_map``.
|
||||
The action whose shortcuts are supposed to be updated in the ``shortcut_map``.
|
||||
|
||||
``old_shortcuts``
|
||||
A list of unicode keysequences.
|
||||
"""
|
||||
for old_shortcut in old_shortcuts:
|
||||
# Remove action from the list of actions which are using this
|
||||
# shortcut.
|
||||
# Remove action from the list of actions which are using this shortcut.
|
||||
ActionList.shortcut_map[old_shortcut].remove(action)
|
||||
# Remove empty entries.
|
||||
if not ActionList.shortcut_map[old_shortcut]:
|
||||
del ActionList.shortcut_map[old_shortcut]
|
||||
new_shortcuts = map(unicode, map(QtGui.QKeySequence.toString, action.shortcuts()))
|
||||
new_shortcuts = map(QtGui.QKeySequence.toString, action.shortcuts())
|
||||
# Add the new shortcuts to the map.
|
||||
for new_shortcut in new_shortcuts:
|
||||
existing_actions = ActionList.shortcut_map.get(new_shortcut, [])
|
||||
|
@ -410,8 +395,7 @@ class ActionList(object):
|
|||
|
||||
def _is_shortcut_available(self, existing_actions, action):
|
||||
"""
|
||||
Checks if the given ``action`` may use its assigned shortcut(s) or not.
|
||||
Returns ``True`` or ``False.
|
||||
Checks if the given ``action`` may use its assigned shortcut(s) or not. Returns ``True`` or ``False.
|
||||
|
||||
``existing_actions``
|
||||
A list of actions which already use a particular shortcut.
|
||||
|
@ -419,28 +403,29 @@ class ActionList(object):
|
|||
``action``
|
||||
The action which wants to use a particular shortcut.
|
||||
"""
|
||||
local = action.shortcutContext() in [QtCore.Qt.WindowShortcut, QtCore.Qt.ApplicationShortcut]
|
||||
affected_actions = filter(lambda a: isinstance(a, QtGui.QAction),
|
||||
self.getAllChildObjects(action.parent())) if local else []
|
||||
global_context = action.shortcutContext() in [QtCore.Qt.WindowShortcut, QtCore.Qt.ApplicationShortcut]
|
||||
affected_actions = []
|
||||
if global_context:
|
||||
affected_actions = filter(
|
||||
lambda a: isinstance(a, QtGui.QAction), self.get_all_child_objects(action.parent()))
|
||||
for existing_action in existing_actions:
|
||||
if action is existing_action:
|
||||
continue
|
||||
if not local or existing_action in affected_actions:
|
||||
if existing_action in affected_actions:
|
||||
return False
|
||||
if existing_action.shortcutContext() in [QtCore.Qt.WindowShortcut, QtCore.Qt.ApplicationShortcut]:
|
||||
return False
|
||||
elif action in self.getAllChildObjects(existing_action.parent()):
|
||||
elif action in self.get_all_child_objects(existing_action.parent()):
|
||||
return False
|
||||
return True
|
||||
|
||||
def getAllChildObjects(self, qobject):
|
||||
def get_all_child_objects(self, qobject):
|
||||
"""
|
||||
Goes recursively through the children of ``qobject`` and returns a list
|
||||
of all child objects.
|
||||
Goes recursively through the children of ``qobject`` and returns a list of all child objects.
|
||||
"""
|
||||
children = [child for child in qobject.children()]
|
||||
for child in qobject.children():
|
||||
children.append(self.getAllChildObjects(child))
|
||||
children = qobject.children()
|
||||
# Append the children's children.
|
||||
children.extend(map(self.get_all_child_objects, children))
|
||||
return children
|
||||
|
||||
|
||||
|
@ -448,5 +433,5 @@ class CategoryOrder(object):
|
|||
"""
|
||||
An enumeration class for category weights.
|
||||
"""
|
||||
standardMenu = -20
|
||||
standardToolbar = -10
|
||||
standard_menu = -20
|
||||
standard_toolbar = -10
|
||||
|
|
|
@ -0,0 +1,180 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
|
||||
|
||||
###############################################################################
|
||||
# OpenLP - Open Source Lyrics Projection #
|
||||
# --------------------------------------------------------------------------- #
|
||||
# Copyright (c) 2008-2013 Raoul Snyman #
|
||||
# Portions copyright (c) 2008-2013 Tim Bentley, Gerald Britton, Jonathan #
|
||||
# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, #
|
||||
# Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer. #
|
||||
# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru, #
|
||||
# Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, #
|
||||
# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Dave Warnock, #
|
||||
# Frode Woldsund, Martin Zibricky, Patrick Zimmermann #
|
||||
# --------------------------------------------------------------------------- #
|
||||
# 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:`openlp.core.utils.applocation` module provides an utility for OpenLP receiving the data path etc.
|
||||
"""
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
|
||||
from openlp.core.lib import Settings
|
||||
from openlp.core.utils import _get_frozen_path
|
||||
|
||||
|
||||
if sys.platform != u'win32' and sys.platform != u'darwin':
|
||||
try:
|
||||
from xdg import BaseDirectory
|
||||
XDG_BASE_AVAILABLE = True
|
||||
except ImportError:
|
||||
XDG_BASE_AVAILABLE = False
|
||||
|
||||
import openlp
|
||||
from openlp.core.lib import check_directory_exists
|
||||
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class AppLocation(object):
|
||||
"""
|
||||
The :class:`AppLocation` class is a static class which retrieves a
|
||||
directory based on the directory type.
|
||||
"""
|
||||
AppDir = 1
|
||||
ConfigDir = 2
|
||||
DataDir = 3
|
||||
PluginsDir = 4
|
||||
VersionDir = 5
|
||||
CacheDir = 6
|
||||
LanguageDir = 7
|
||||
|
||||
# Base path where data/config/cache dir is located
|
||||
BaseDir = None
|
||||
|
||||
@staticmethod
|
||||
def get_directory(dir_type=1):
|
||||
"""
|
||||
Return the appropriate directory according to the directory type.
|
||||
|
||||
``dir_type``
|
||||
The directory type you want, for instance the data directory.
|
||||
"""
|
||||
if dir_type == AppLocation.AppDir:
|
||||
return _get_frozen_path(os.path.abspath(os.path.split(sys.argv[0])[0]), os.path.split(openlp.__file__)[0])
|
||||
elif dir_type == AppLocation.PluginsDir:
|
||||
app_path = os.path.abspath(os.path.split(sys.argv[0])[0])
|
||||
return _get_frozen_path(os.path.join(app_path, u'plugins'),
|
||||
os.path.join(os.path.split(openlp.__file__)[0], u'plugins'))
|
||||
elif dir_type == AppLocation.VersionDir:
|
||||
return _get_frozen_path(os.path.abspath(os.path.split(sys.argv[0])[0]), os.path.split(openlp.__file__)[0])
|
||||
elif dir_type == AppLocation.LanguageDir:
|
||||
app_path = _get_frozen_path(os.path.abspath(os.path.split(sys.argv[0])[0]), _get_os_dir_path(dir_type))
|
||||
return os.path.join(app_path, u'i18n')
|
||||
elif dir_type == AppLocation.DataDir and AppLocation.BaseDir:
|
||||
return os.path.join(AppLocation.BaseDir, 'data')
|
||||
else:
|
||||
return _get_os_dir_path(dir_type)
|
||||
|
||||
@staticmethod
|
||||
def get_data_path():
|
||||
"""
|
||||
Return the path OpenLP stores all its data under.
|
||||
"""
|
||||
# Check if we have a different data location.
|
||||
if Settings().contains(u'advanced/data path'):
|
||||
path = Settings().value(u'advanced/data path')
|
||||
else:
|
||||
path = AppLocation.get_directory(AppLocation.DataDir)
|
||||
check_directory_exists(path)
|
||||
return os.path.normpath(path)
|
||||
|
||||
@staticmethod
|
||||
def get_files(section=None, extension=None):
|
||||
"""
|
||||
Get a list of files from the data files path.
|
||||
|
||||
``section``
|
||||
Defaults to *None*. The section of code getting the files - used to load from a section's data subdirectory.
|
||||
|
||||
``extension``
|
||||
Defaults to *None*. The extension to search for. For example::
|
||||
|
||||
u'.png'
|
||||
"""
|
||||
path = AppLocation.get_data_path()
|
||||
if section:
|
||||
path = os.path.join(path, section)
|
||||
try:
|
||||
files = os.listdir(path)
|
||||
except OSError:
|
||||
return []
|
||||
if extension:
|
||||
return [filename for filename in files if extension == os.path.splitext(filename)[1]]
|
||||
else:
|
||||
# no filtering required
|
||||
return files
|
||||
|
||||
@staticmethod
|
||||
def get_section_data_path(section):
|
||||
"""
|
||||
Return the path a particular module stores its data under.
|
||||
"""
|
||||
data_path = AppLocation.get_data_path()
|
||||
path = os.path.join(data_path, section)
|
||||
check_directory_exists(path)
|
||||
return path
|
||||
|
||||
|
||||
def _get_os_dir_path(dir_type):
|
||||
"""
|
||||
Return a path based on which OS and environment we are running in.
|
||||
"""
|
||||
encoding = sys.getfilesystemencoding()
|
||||
if sys.platform == u'win32':
|
||||
if dir_type == AppLocation.DataDir:
|
||||
return os.path.join(unicode(os.getenv(u'APPDATA'), encoding), u'openlp', u'data')
|
||||
elif dir_type == AppLocation.LanguageDir:
|
||||
return os.path.split(openlp.__file__)[0]
|
||||
return os.path.join(unicode(os.getenv(u'APPDATA'), encoding), u'openlp')
|
||||
elif sys.platform == u'darwin':
|
||||
if dir_type == AppLocation.DataDir:
|
||||
return os.path.join(unicode(os.getenv(u'HOME'), encoding),
|
||||
u'Library', u'Application Support', u'openlp', u'Data')
|
||||
elif dir_type == AppLocation.LanguageDir:
|
||||
return os.path.split(openlp.__file__)[0]
|
||||
return os.path.join(unicode(os.getenv(u'HOME'), encoding), u'Library', u'Application Support', u'openlp')
|
||||
else:
|
||||
if dir_type == AppLocation.LanguageDir:
|
||||
prefixes = [u'/usr/local', u'/usr']
|
||||
for prefix in prefixes:
|
||||
directory = os.path.join(prefix, u'share', u'openlp')
|
||||
if os.path.exists(directory):
|
||||
return directory
|
||||
return os.path.join(u'/usr', u'share', u'openlp')
|
||||
if XDG_BASE_AVAILABLE:
|
||||
if dir_type == AppLocation.ConfigDir:
|
||||
return os.path.join(unicode(BaseDirectory.xdg_config_home, encoding), u'openlp')
|
||||
elif dir_type == AppLocation.DataDir:
|
||||
return os.path.join(unicode(BaseDirectory.xdg_data_home, encoding), u'openlp')
|
||||
elif dir_type == AppLocation.CacheDir:
|
||||
return os.path.join(unicode(BaseDirectory.xdg_cache_home, encoding), u'openlp')
|
||||
if dir_type == AppLocation.DataDir:
|
||||
return os.path.join(unicode(os.getenv(u'HOME'), encoding), u'.openlp', u'data')
|
||||
return os.path.join(unicode(os.getenv(u'HOME'), encoding), u'.openlp')
|
||||
|
|
@ -122,7 +122,7 @@ __default_settings__ = {
|
|||
u'alerts/background color': u'#660000',
|
||||
u'alerts/font color': u'#ffffff',
|
||||
u'alerts/timeout': 5
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class AlertsPlugin(Plugin):
|
||||
|
@ -133,7 +133,7 @@ class AlertsPlugin(Plugin):
|
|||
self.weight = -3
|
||||
self.iconPath = u':/plugins/plugin_alerts.png'
|
||||
self.icon = build_icon(self.iconPath)
|
||||
self.alertsmanager = AlertsManager(self)
|
||||
self.alerts_manager = AlertsManager(self)
|
||||
self.manager = Manager(u'alerts', init_schema)
|
||||
self.alertForm = AlertForm(self)
|
||||
|
||||
|
@ -150,7 +150,7 @@ class AlertsPlugin(Plugin):
|
|||
self.toolsAlertItem = create_action(tools_menu, u'toolsAlertItem',
|
||||
text=translate('AlertsPlugin', '&Alert'), icon=u':/plugins/plugin_alerts.png',
|
||||
statustip=translate('AlertsPlugin', 'Show an alert message.'),
|
||||
visible=False, shortcuts=[u'F7'], triggers=self.onAlertsTrigger)
|
||||
visible=False, can_shortcuts=True, triggers=self.onAlertsTrigger)
|
||||
self.main_window.toolsMenu.addAction(self.toolsAlertItem)
|
||||
|
||||
def initialise(self):
|
||||
|
@ -176,7 +176,7 @@ class AlertsPlugin(Plugin):
|
|||
Settings().setValue(self.settingsSection + u'/active', self.alertsActive)
|
||||
|
||||
def onAlertsTrigger(self):
|
||||
self.alertForm.loadList()
|
||||
self.alertForm.load_list()
|
||||
self.alertForm.exec_()
|
||||
|
||||
def about(self):
|
||||
|
@ -194,7 +194,8 @@ class AlertsPlugin(Plugin):
|
|||
u'plural': translate('AlertsPlugin', 'Alerts', 'name plural')
|
||||
}
|
||||
## Name for MediaDockManager, SettingsManager ##
|
||||
self.textStrings[StringContent.VisibleName] = {u'title': translate('AlertsPlugin', 'Alerts', 'container title')
|
||||
self.textStrings[StringContent.VisibleName] = {
|
||||
u'title': translate('AlertsPlugin', 'Alerts', 'container title')
|
||||
}
|
||||
|
||||
def getDisplayJavaScript(self):
|
||||
|
|
|
@ -32,61 +32,63 @@ from PyQt4 import QtGui
|
|||
from openlp.core.lib import build_icon, translate
|
||||
from openlp.core.lib.ui import create_button, create_button_box
|
||||
|
||||
class Ui_AlertDialog(object):
|
||||
def setupUi(self, alertDialog):
|
||||
alertDialog.setObjectName(u'alertDialog')
|
||||
alertDialog.resize(400, 300)
|
||||
alertDialog.setWindowIcon(build_icon(u':/icon/openlp-logo-16x16.png'))
|
||||
self.alertDialogLayout = QtGui.QGridLayout(alertDialog)
|
||||
self.alertDialogLayout.setObjectName(u'alertDialogLayout')
|
||||
self.alertTextLayout = QtGui.QFormLayout()
|
||||
self.alertTextLayout.setObjectName(u'alertTextLayout')
|
||||
self.alertEntryLabel = QtGui.QLabel(alertDialog)
|
||||
self.alertEntryLabel.setObjectName(u'alertEntryLabel')
|
||||
self.alertTextEdit = QtGui.QLineEdit(alertDialog)
|
||||
self.alertTextEdit.setObjectName(u'alertTextEdit')
|
||||
self.alertEntryLabel.setBuddy(self.alertTextEdit)
|
||||
self.alertTextLayout.addRow(self.alertEntryLabel, self.alertTextEdit)
|
||||
self.alertParameter = QtGui.QLabel(alertDialog)
|
||||
self.alertParameter.setObjectName(u'alertParameter')
|
||||
self.parameterEdit = QtGui.QLineEdit(alertDialog)
|
||||
self.parameterEdit.setObjectName(u'parameterEdit')
|
||||
self.alertParameter.setBuddy(self.parameterEdit)
|
||||
self.alertTextLayout.addRow(self.alertParameter, self.parameterEdit)
|
||||
self.alertDialogLayout.addLayout(self.alertTextLayout, 0, 0, 1, 2)
|
||||
self.alertListWidget = QtGui.QListWidget(alertDialog)
|
||||
self.alertListWidget.setAlternatingRowColors(True)
|
||||
self.alertListWidget.setObjectName(u'alertListWidget')
|
||||
self.alertDialogLayout.addWidget(self.alertListWidget, 1, 0)
|
||||
self.manageButtonLayout = QtGui.QVBoxLayout()
|
||||
self.manageButtonLayout.setObjectName(u'manageButtonLayout')
|
||||
self.newButton = QtGui.QPushButton(alertDialog)
|
||||
self.newButton.setIcon(build_icon(u':/general/general_new.png'))
|
||||
self.newButton.setObjectName(u'newButton')
|
||||
self.manageButtonLayout.addWidget(self.newButton)
|
||||
self.saveButton = QtGui.QPushButton(alertDialog)
|
||||
self.saveButton.setEnabled(False)
|
||||
self.saveButton.setIcon(build_icon(u':/general/general_save.png'))
|
||||
self.saveButton.setObjectName(u'saveButton')
|
||||
self.manageButtonLayout.addWidget(self.saveButton)
|
||||
self.deleteButton = create_button(alertDialog, u'deleteButton', role=u'delete', enabled=False,
|
||||
click=alertDialog.onDeleteButtonClicked)
|
||||
self.manageButtonLayout.addWidget(self.deleteButton)
|
||||
self.manageButtonLayout.addStretch()
|
||||
self.alertDialogLayout.addLayout(self.manageButtonLayout, 1, 1)
|
||||
displayIcon = build_icon(u':/general/general_live.png')
|
||||
self.displayButton = create_button(alertDialog, u'displayButton', icon=displayIcon, enabled=False)
|
||||
self.displayCloseButton = create_button(alertDialog, u'displayCloseButton', icon=displayIcon, enabled=False)
|
||||
self.button_box = create_button_box(alertDialog, u'button_box', [u'close'],
|
||||
[self.displayButton, self.displayCloseButton])
|
||||
self.alertDialogLayout.addWidget(self.button_box, 2, 0, 1, 2)
|
||||
self.retranslateUi(alertDialog)
|
||||
|
||||
def retranslateUi(self, alertDialog):
|
||||
alertDialog.setWindowTitle(translate('AlertsPlugin.AlertForm', 'Alert Message'))
|
||||
self.alertEntryLabel.setText(translate('AlertsPlugin.AlertForm', 'Alert &text:'))
|
||||
self.alertParameter.setText(translate('AlertsPlugin.AlertForm', '&Parameter:'))
|
||||
self.newButton.setText(translate('AlertsPlugin.AlertForm', '&New'))
|
||||
self.saveButton.setText(translate('AlertsPlugin.AlertForm', '&Save'))
|
||||
self.displayButton.setText(translate('AlertsPlugin.AlertForm', 'Displ&ay'))
|
||||
self.displayCloseButton.setText(translate('AlertsPlugin.AlertForm', 'Display && Cl&ose'))
|
||||
class Ui_AlertDialog(object):
|
||||
def setupUi(self, alert_dialog):
|
||||
alert_dialog.setObjectName(u'alert_dialog')
|
||||
alert_dialog.resize(400, 300)
|
||||
alert_dialog.setWindowIcon(build_icon(u':/icon/openlp-logo-16x16.png'))
|
||||
self.alert_dialog_layout = QtGui.QGridLayout(alert_dialog)
|
||||
self.alert_dialog_layout.setObjectName(u'alert_dialog_layout')
|
||||
self.alert_text_layout = QtGui.QFormLayout()
|
||||
self.alert_text_layout.setObjectName(u'alert_text_layout')
|
||||
self.alert_entry_label = QtGui.QLabel(alert_dialog)
|
||||
self.alert_entry_label.setObjectName(u'alert_entry_label')
|
||||
self.alert_text_edit = QtGui.QLineEdit(alert_dialog)
|
||||
self.alert_text_edit.setObjectName(u'alert_text_edit')
|
||||
self.alert_entry_label.setBuddy(self.alert_text_edit)
|
||||
self.alert_text_layout.addRow(self.alert_entry_label, self.alert_text_edit)
|
||||
self.alert_parameter = QtGui.QLabel(alert_dialog)
|
||||
self.alert_parameter.setObjectName(u'alert_parameter')
|
||||
self.parameter_edit = QtGui.QLineEdit(alert_dialog)
|
||||
self.parameter_edit.setObjectName(u'parameter_edit')
|
||||
self.alert_parameter.setBuddy(self.parameter_edit)
|
||||
self.alert_text_layout.addRow(self.alert_parameter, self.parameter_edit)
|
||||
self.alert_dialog_layout.addLayout(self.alert_text_layout, 0, 0, 1, 2)
|
||||
self.alert_list_widget = QtGui.QListWidget(alert_dialog)
|
||||
self.alert_list_widget.setAlternatingRowColors(True)
|
||||
self.alert_list_widget.setObjectName(u'alert_list_widget')
|
||||
self.alert_dialog_layout.addWidget(self.alert_list_widget, 1, 0)
|
||||
self.manage_button_layout = QtGui.QVBoxLayout()
|
||||
self.manage_button_layout.setObjectName(u'manage_button_layout')
|
||||
self.new_button = QtGui.QPushButton(alert_dialog)
|
||||
self.new_button.setIcon(build_icon(u':/general/general_new.png'))
|
||||
self.new_button.setObjectName(u'new_button')
|
||||
self.manage_button_layout.addWidget(self.new_button)
|
||||
self.save_button = QtGui.QPushButton(alert_dialog)
|
||||
self.save_button.setEnabled(False)
|
||||
self.save_button.setIcon(build_icon(u':/general/general_save.png'))
|
||||
self.save_button.setObjectName(u'save_button')
|
||||
self.manage_button_layout.addWidget(self.save_button)
|
||||
self.delete_button = create_button(alert_dialog, u'delete_button', role=u'delete', enabled=False,
|
||||
click=alert_dialog.onDeleteButtonClicked)
|
||||
self.manage_button_layout.addWidget(self.delete_button)
|
||||
self.manage_button_layout.addStretch()
|
||||
self.alert_dialog_layout.addLayout(self.manage_button_layout, 1, 1)
|
||||
displayIcon = build_icon(u':/general/general_live.png')
|
||||
self.display_button = create_button(alert_dialog, u'display_button', icon=displayIcon, enabled=False)
|
||||
self.display_close_button = create_button(alert_dialog, u'display_close_button', icon=displayIcon,
|
||||
enabled=False)
|
||||
self.button_box = create_button_box(alert_dialog, u'button_box', [u'close'],
|
||||
[self.display_button, self.display_close_button])
|
||||
self.alert_dialog_layout.addWidget(self.button_box, 2, 0, 1, 2)
|
||||
self.retranslateUi(alert_dialog)
|
||||
|
||||
def retranslateUi(self, alert_dialog):
|
||||
alert_dialog.setWindowTitle(translate('AlertsPlugin.AlertForm', 'Alert Message'))
|
||||
self.alert_entry_label.setText(translate('AlertsPlugin.AlertForm', 'Alert &text:'))
|
||||
self.alert_parameter.setText(translate('AlertsPlugin.AlertForm', '&Parameter:'))
|
||||
self.new_button.setText(translate('AlertsPlugin.AlertForm', '&New'))
|
||||
self.save_button.setText(translate('AlertsPlugin.AlertForm', '&Save'))
|
||||
self.display_button.setText(translate('AlertsPlugin.AlertForm', 'Displ&ay'))
|
||||
self.display_close_button.setText(translate('AlertsPlugin.AlertForm', 'Display && Cl&ose'))
|
||||
|
|
|
@ -48,131 +48,131 @@ class AlertForm(QtGui.QDialog, Ui_AlertDialog):
|
|||
self.item_id = None
|
||||
super(AlertForm, self).__init__(self.plugin.main_window)
|
||||
self.setupUi(self)
|
||||
QtCore.QObject.connect(self.displayButton, QtCore.SIGNAL(u'clicked()'), self.onDisplayClicked)
|
||||
QtCore.QObject.connect(self.displayCloseButton, QtCore.SIGNAL(u'clicked()'), self.onDisplayCloseClicked)
|
||||
QtCore.QObject.connect(self.alertTextEdit, QtCore.SIGNAL(u'textChanged(const QString&)'), self.onTextChanged)
|
||||
QtCore.QObject.connect(self.newButton, QtCore.SIGNAL(u'clicked()'), self.onNewClick)
|
||||
QtCore.QObject.connect(self.saveButton, QtCore.SIGNAL(u'clicked()'), self.onSaveClick)
|
||||
QtCore.QObject.connect(self.alertListWidget, QtCore.SIGNAL(u'doubleClicked(QModelIndex)'), self.onDoubleClick)
|
||||
QtCore.QObject.connect(self.alertListWidget, QtCore.SIGNAL(u'clicked(QModelIndex)'), self.onSingleClick)
|
||||
QtCore.QObject.connect(self.alertListWidget, QtCore.SIGNAL(u'currentRowChanged(int)'), self.onCurrentRowChanged)
|
||||
self.display_button.clicked.connect(self.on_display_clicked)
|
||||
self.display_close_button.clicked.connect(self.on_display_close_clicked)
|
||||
self.alert_text_edit.textChanged.connect(self.on_text_changed)
|
||||
self.new_button.clicked.connect(self.on_new_click)
|
||||
self.save_button.clicked.connect(self.on_save_all)
|
||||
self.alert_list_widget.doubleClicked.connect(self.on_double_click)
|
||||
self.alert_list_widget.clicked.connect(self.on_single_click)
|
||||
self.alert_list_widget.currentRowChanged.connect(self.on_current_row_changed)
|
||||
|
||||
def exec_(self):
|
||||
"""
|
||||
Execute the dialog and return the exit code.
|
||||
"""
|
||||
self.displayButton.setEnabled(False)
|
||||
self.displayCloseButton.setEnabled(False)
|
||||
self.alertTextEdit.setText(u'')
|
||||
self.display_button.setEnabled(False)
|
||||
self.display_close_button.setEnabled(False)
|
||||
self.alert_text_edit.setText(u'')
|
||||
return QtGui.QDialog.exec_(self)
|
||||
|
||||
def loadList(self):
|
||||
def load_list(self):
|
||||
"""
|
||||
Loads the list with alerts.
|
||||
"""
|
||||
self.alertListWidget.clear()
|
||||
self.alert_list_widget.clear()
|
||||
alerts = self.manager.get_all_objects(AlertItem, order_by_ref=AlertItem.text)
|
||||
for alert in alerts:
|
||||
item_name = QtGui.QListWidgetItem(alert.text)
|
||||
item_name.setData(QtCore.Qt.UserRole, alert.id)
|
||||
self.alertListWidget.addItem(item_name)
|
||||
if alert.text == unicode(self.alertTextEdit.text()):
|
||||
self.alert_list_widget.addItem(item_name)
|
||||
if alert.text == unicode(self.alert_text_edit.text()):
|
||||
self.item_id = alert.id
|
||||
self.alertListWidget.setCurrentRow(self.alertListWidget.row(item_name))
|
||||
self.alert_list_widget.setCurrentRow(self.alert_list_widget.row(item_name))
|
||||
|
||||
def onDisplayClicked(self):
|
||||
def on_display_clicked(self):
|
||||
"""
|
||||
Display the current alert text.
|
||||
"""
|
||||
self.triggerAlert(self.alertTextEdit.text())
|
||||
self.trigger_alert(self.alert_text_edit.text())
|
||||
|
||||
def onDisplayCloseClicked(self):
|
||||
def on_display_close_clicked(self):
|
||||
"""
|
||||
Close the alert preview.
|
||||
"""
|
||||
if self.triggerAlert(self.alertTextEdit.text()):
|
||||
if self.trigger_alert(self.alert_text_edit.text()):
|
||||
self.close()
|
||||
|
||||
def onDeleteButtonClicked(self):
|
||||
"""
|
||||
Deletes the selected item.
|
||||
"""
|
||||
item = self.alertListWidget.currentItem()
|
||||
item = self.alert_list_widget.currentItem()
|
||||
if item:
|
||||
item_id = item.data(QtCore.Qt.UserRole)
|
||||
self.manager.delete_object(AlertItem, item_id)
|
||||
row = self.alertListWidget.row(item)
|
||||
self.alertListWidget.takeItem(row)
|
||||
row = self.alert_list_widget.row(item)
|
||||
self.alert_list_widget.takeItem(row)
|
||||
self.item_id = None
|
||||
self.alertTextEdit.setText(u'')
|
||||
self.alert_text_edit.setText(u'')
|
||||
|
||||
def onNewClick(self):
|
||||
def on_new_click(self):
|
||||
"""
|
||||
Create a new alert.
|
||||
"""
|
||||
if not self.alertTextEdit.text():
|
||||
if not self.alert_text_edit.text():
|
||||
QtGui.QMessageBox.information(self,
|
||||
translate('AlertsPlugin.AlertForm', 'New Alert'),
|
||||
translate('AlertsPlugin.AlertForm', 'You haven\'t specified any text for your alert. \n'
|
||||
'Please type in some text before clicking New.'))
|
||||
else:
|
||||
alert = AlertItem()
|
||||
alert.text = self.alertTextEdit.text()
|
||||
alert.text = self.alert_text_edit.text()
|
||||
self.manager.save_object(alert)
|
||||
self.loadList()
|
||||
self.load_list()
|
||||
|
||||
def onSaveClick(self):
|
||||
def on_save_all(self):
|
||||
"""
|
||||
Save the alert, we are editing.
|
||||
"""
|
||||
if self.item_id:
|
||||
alert = self.manager.get_object(AlertItem, self.item_id)
|
||||
alert.text = self.alertTextEdit.text()
|
||||
alert.text = self.alert_text_edit.text()
|
||||
self.manager.save_object(alert)
|
||||
self.item_id = None
|
||||
self.loadList()
|
||||
self.saveButton.setEnabled(False)
|
||||
self.load_list()
|
||||
self.save_button.setEnabled(False)
|
||||
|
||||
def onTextChanged(self):
|
||||
def on_text_changed(self):
|
||||
"""
|
||||
Enable save button when data has been changed by editing the form.
|
||||
"""
|
||||
# Only enable the button, if we are editing an item.
|
||||
if self.item_id:
|
||||
self.saveButton.setEnabled(True)
|
||||
if self.alertTextEdit.text():
|
||||
self.displayButton.setEnabled(True)
|
||||
self.displayCloseButton.setEnabled(True)
|
||||
self.save_button.setEnabled(True)
|
||||
if self.alert_text_edit.text():
|
||||
self.display_button.setEnabled(True)
|
||||
self.display_close_button.setEnabled(True)
|
||||
else:
|
||||
self.displayButton.setEnabled(False)
|
||||
self.displayCloseButton.setEnabled(False)
|
||||
self.display_button.setEnabled(False)
|
||||
self.display_close_button.setEnabled(False)
|
||||
|
||||
def onDoubleClick(self):
|
||||
def on_double_click(self):
|
||||
"""
|
||||
List item has been double clicked to display it.
|
||||
"""
|
||||
item = self.alertListWidget.selectedIndexes()[0]
|
||||
bitem = self.alertListWidget.item(item.row())
|
||||
self.triggerAlert(bitem.text())
|
||||
self.alertTextEdit.setText(bitem.text())
|
||||
item = self.alert_list_widget.selectedIndexes()[0]
|
||||
bitem = self.alert_list_widget.item(item.row())
|
||||
self.trigger_alert(bitem.text())
|
||||
self.alert_text_edit.setText(bitem.text())
|
||||
self.item_id = bitem.data(QtCore.Qt.UserRole)
|
||||
self.saveButton.setEnabled(False)
|
||||
self.save_button.setEnabled(False)
|
||||
|
||||
def onSingleClick(self):
|
||||
def on_single_click(self):
|
||||
"""
|
||||
List item has been single clicked to add it to the edit field so it can
|
||||
be changed.
|
||||
"""
|
||||
item = self.alertListWidget.selectedIndexes()[0]
|
||||
bitem = self.alertListWidget.item(item.row())
|
||||
self.alertTextEdit.setText(bitem.text())
|
||||
item = self.alert_list_widget.selectedIndexes()[0]
|
||||
bitem = self.alert_list_widget.item(item.row())
|
||||
self.alert_text_edit.setText(bitem.text())
|
||||
self.item_id = bitem.data(QtCore.Qt.UserRole)
|
||||
# If the alert does not contain '<>' we clear the ParameterEdit field.
|
||||
if self.alertTextEdit.text().find(u'<>') == -1:
|
||||
self.parameterEdit.setText(u'')
|
||||
self.saveButton.setEnabled(False)
|
||||
if self.alert_text_edit.text().find(u'<>') == -1:
|
||||
self.parameter_edit.setText(u'')
|
||||
self.save_button.setEnabled(False)
|
||||
|
||||
def triggerAlert(self, text):
|
||||
def trigger_alert(self, text):
|
||||
"""
|
||||
Prepares the alert text for displaying.
|
||||
|
||||
|
@ -182,42 +182,44 @@ class AlertForm(QtGui.QDialog, Ui_AlertDialog):
|
|||
if not text:
|
||||
return False
|
||||
# We found '<>' in the alert text, but the ParameterEdit field is empty.
|
||||
if text.find(u'<>') != -1 and not self.parameterEdit.text() and QtGui.QMessageBox.question(self,
|
||||
if text.find(u'<>') != -1 and not self.parameter_edit.text() and QtGui.QMessageBox.question(self,
|
||||
translate('AlertsPlugin.AlertForm', 'No Parameter Found'),
|
||||
translate('AlertsPlugin.AlertForm', 'You have not entered a parameter to be replaced.\n'
|
||||
'Do you want to continue anyway?'),
|
||||
QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.No | QtGui.QMessageBox.Yes)) == QtGui.QMessageBox.No:
|
||||
self.parameterEdit.setFocus()
|
||||
self.parameter_edit.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,
|
||||
elif text.find(u'<>') == -1 and self.parameter_edit.text() and QtGui.QMessageBox.question(self,
|
||||
translate('AlertsPlugin.AlertForm', 'No Placeholder Found'),
|
||||
translate('AlertsPlugin.AlertForm', 'The alert text does not contain \'<>\'.\n'
|
||||
'Do you want to continue anyway?'),
|
||||
QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.No | QtGui.QMessageBox.Yes)) == QtGui.QMessageBox.No:
|
||||
self.parameterEdit.setFocus()
|
||||
self.parameter_edit.setFocus()
|
||||
return False
|
||||
text = text.replace(u'<>', self.parameterEdit.text())
|
||||
|
||||
text = text.replace(u'<>', self.parameter_edit.text())
|
||||
self.plugin.alerts_manager.display_alert(text)
|
||||
self.plugin.alertsmanager.display_alert(text)
|
||||
return True
|
||||
|
||||
def onCurrentRowChanged(self, row):
|
||||
def on_current_row_changed(self, row):
|
||||
"""
|
||||
Called when the *alertListWidget*'s current row has been changed. This
|
||||
Called when the *alert_list_widget*'s current row has been changed. This
|
||||
enables or disables buttons which require an item to act on.
|
||||
|
||||
``row``
|
||||
The row (int). If there is no current row, the value is -1.
|
||||
"""
|
||||
if row == -1:
|
||||
self.displayButton.setEnabled(False)
|
||||
self.displayCloseButton.setEnabled(False)
|
||||
self.saveButton.setEnabled(False)
|
||||
self.deleteButton.setEnabled(False)
|
||||
self.display_button.setEnabled(False)
|
||||
self.display_close_button.setEnabled(False)
|
||||
self.save_button.setEnabled(False)
|
||||
self.delete_button.setEnabled(False)
|
||||
else:
|
||||
self.displayButton.setEnabled(True)
|
||||
self.displayCloseButton.setEnabled(True)
|
||||
self.deleteButton.setEnabled(True)
|
||||
self.display_button.setEnabled(True)
|
||||
self.display_close_button.setEnabled(True)
|
||||
self.delete_button.setEnabled(True)
|
||||
# We do not need to enable the save button, as it is only enabled
|
||||
# when typing text in the "alertTextEdit".
|
||||
# when typing text in the "alert_text_edit".
|
||||
|
|
|
@ -49,7 +49,6 @@ class AlertsManager(QtCore.QObject):
|
|||
|
||||
def __init__(self, parent):
|
||||
QtCore.QObject.__init__(self, parent)
|
||||
self.screen = None
|
||||
self.timer_id = 0
|
||||
self.alert_list = []
|
||||
Registry().register_function(u'live_display_active', self.generate_alert)
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
import logging
|
||||
import os
|
||||
|
||||
from openlp.core.lib import Registry, SettingsManager, Settings, translate
|
||||
from openlp.core.lib import Registry, Settings, translate
|
||||
from openlp.core.utils import AppLocation, delete_file
|
||||
from openlp.plugins.bibles.lib import parse_reference, get_reference_separator, LanguageSelection
|
||||
from openlp.plugins.bibles.lib.db import BibleDB, BibleMeta
|
||||
|
@ -137,7 +137,7 @@ class BibleManager(object):
|
|||
BibleDB class.
|
||||
"""
|
||||
log.debug(u'Reload bibles')
|
||||
files = SettingsManager.get_files(self.settingsSection, self.suffix)
|
||||
files = AppLocation.get_files(self.settingsSection, self.suffix)
|
||||
if u'alternative_book_names.sqlite' in files:
|
||||
files.remove(u'alternative_book_names.sqlite')
|
||||
log.debug(u'Bible Files %s', files)
|
||||
|
|
|
@ -32,9 +32,8 @@ import os
|
|||
|
||||
from PyQt4 import QtCore, QtGui
|
||||
|
||||
from openlp.core.lib import MediaManagerItem, ItemCapabilities, Registry, SettingsManager, ServiceItemContext, \
|
||||
Settings, UiStrings, build_icon, check_item_selected, check_directory_exists, create_thumb, translate, \
|
||||
validate_thumb
|
||||
from openlp.core.lib import MediaManagerItem, ItemCapabilities, Registry, ServiceItemContext, Settings, UiStrings, \
|
||||
build_icon, check_item_selected, check_directory_exists, create_thumb, translate, validate_thumb
|
||||
from openlp.core.lib.ui import critical_error_message_box
|
||||
from openlp.core.utils import AppLocation, delete_file, locale_compare, get_images_filter
|
||||
|
||||
|
@ -107,7 +106,7 @@ class ImageMediaItem(MediaManagerItem):
|
|||
delete_file(os.path.join(self.servicePath, text.text()))
|
||||
self.listView.takeItem(row)
|
||||
self.main_window.incrementProgressBar()
|
||||
SettingsManager.setValue(self.settingsSection + u'/images files', self.getFileList())
|
||||
Settings.setValue(self.settingsSection + u'/images files', self.getFileList())
|
||||
self.main_window.finishedProgressBar()
|
||||
self.application.set_normal_cursor()
|
||||
self.listView.blockSignals(False)
|
||||
|
|
|
@ -291,7 +291,7 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
|
|||
verse_tags_translated = True
|
||||
if index is None:
|
||||
index = VerseType.from_tag(verse_tag)
|
||||
verse[0][u'type'] = VerseType.Tags[index]
|
||||
verse[0][u'type'] = VerseType.tags[index]
|
||||
if verse[0][u'label'] == u'':
|
||||
verse[0][u'label'] = u'1'
|
||||
verse_def = u'%s%s' % (verse[0][u'type'], verse[0][u'label'])
|
||||
|
@ -303,7 +303,7 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
|
|||
for count, verse in enumerate(verses):
|
||||
self.verseListWidget.setRowCount(self.verseListWidget.rowCount() + 1)
|
||||
item = QtGui.QTableWidgetItem(verse)
|
||||
verse_def = u'%s%s' % (VerseType.Tags[VerseType.Verse], unicode(count + 1))
|
||||
verse_def = u'%s%s' % (VerseType.tags[VerseType.Verse], unicode(count + 1))
|
||||
item.setData(QtCore.Qt.UserRole, verse_def)
|
||||
self.verseListWidget.setItem(count, 0, item)
|
||||
if self.song.verse_order:
|
||||
|
@ -315,7 +315,7 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
|
|||
verse_index = VerseType.from_translated_tag(verse_def[0], None)
|
||||
if verse_index is None:
|
||||
verse_index = VerseType.from_tag(verse_def[0])
|
||||
verse_tag = VerseType.TranslatedTags[verse_index].upper()
|
||||
verse_tag = VerseType.translated_tags[verse_index].upper()
|
||||
translated.append(u'%s%s' % (verse_tag, verse_def[1:]))
|
||||
self.verseOrderEdit.setText(u' '.join(translated))
|
||||
else:
|
||||
|
@ -547,7 +547,7 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
|
|||
verse_name = parts
|
||||
verse_num = u'1'
|
||||
verse_index = VerseType.from_loose_input(verse_name)
|
||||
verse_tag = VerseType.Tags[verse_index]
|
||||
verse_tag = VerseType.tags[verse_index]
|
||||
# Later we need to handle v1a as well.
|
||||
#regex = re.compile(r'(\d+\w.)')
|
||||
regex = re.compile(r'\D*(\d+)\D*')
|
||||
|
@ -599,7 +599,7 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
|
|||
if len(item) == 1:
|
||||
verse_index = VerseType.from_translated_tag(item, None)
|
||||
if verse_index is not None:
|
||||
order.append(VerseType.Tags[verse_index] + u'1')
|
||||
order.append(VerseType.tags[verse_index] + u'1')
|
||||
else:
|
||||
# it matches no verses anyway
|
||||
order.append(u'')
|
||||
|
@ -609,7 +609,7 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
|
|||
# it matches no verses anyway
|
||||
order.append(u'')
|
||||
else:
|
||||
verse_tag = VerseType.Tags[verse_index]
|
||||
verse_tag = VerseType.tags[verse_index]
|
||||
verse_num = item[1:].lower()
|
||||
order.append(verse_tag + verse_num)
|
||||
return order
|
||||
|
@ -831,7 +831,7 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
|
|||
ordertext = self.verseOrderEdit.text()
|
||||
order = []
|
||||
for item in ordertext.split():
|
||||
verse_tag = VerseType.Tags[VerseType.from_translated_tag(item[0])]
|
||||
verse_tag = VerseType.tags[VerseType.from_translated_tag(item[0])]
|
||||
verse_num = item[1:].lower()
|
||||
order.append(u'%s%s' % (verse_tag, verse_num))
|
||||
self.song.verse_order = u' '.join(order)
|
||||
|
|
|
@ -74,13 +74,13 @@ class Ui_EditVerseDialog(object):
|
|||
def retranslateUi(self, editVerseDialog):
|
||||
editVerseDialog.setWindowTitle(translate('SongsPlugin.EditVerseForm', 'Edit Verse'))
|
||||
self.verseTypeLabel.setText(translate('SongsPlugin.EditVerseForm', '&Verse type:'))
|
||||
self.verseTypeComboBox.setItemText(VerseType.Verse, VerseType.TranslatedNames[VerseType.Verse])
|
||||
self.verseTypeComboBox.setItemText(VerseType.Chorus, VerseType.TranslatedNames[VerseType.Chorus])
|
||||
self.verseTypeComboBox.setItemText(VerseType.Bridge, VerseType.TranslatedNames[VerseType.Bridge])
|
||||
self.verseTypeComboBox.setItemText(VerseType.PreChorus, VerseType.TranslatedNames[VerseType.PreChorus])
|
||||
self.verseTypeComboBox.setItemText(VerseType.Intro, VerseType.TranslatedNames[VerseType.Intro])
|
||||
self.verseTypeComboBox.setItemText(VerseType.Ending, VerseType.TranslatedNames[VerseType.Ending])
|
||||
self.verseTypeComboBox.setItemText(VerseType.Other, VerseType.TranslatedNames[VerseType.Other])
|
||||
self.verseTypeComboBox.setItemText(VerseType.Verse, VerseType.translated_names[VerseType.Verse])
|
||||
self.verseTypeComboBox.setItemText(VerseType.Chorus, VerseType.translated_names[VerseType.Chorus])
|
||||
self.verseTypeComboBox.setItemText(VerseType.Bridge, VerseType.translated_names[VerseType.Bridge])
|
||||
self.verseTypeComboBox.setItemText(VerseType.PreChorus, VerseType.translated_names[VerseType.PreChorus])
|
||||
self.verseTypeComboBox.setItemText(VerseType.Intro, VerseType.translated_names[VerseType.Intro])
|
||||
self.verseTypeComboBox.setItemText(VerseType.Ending, VerseType.translated_names[VerseType.Ending])
|
||||
self.verseTypeComboBox.setItemText(VerseType.Other, VerseType.translated_names[VerseType.Other])
|
||||
self.splitButton.setText(UiStrings().Split)
|
||||
self.splitButton.setToolTip(UiStrings().SplitToolTip)
|
||||
self.insertButton.setText(translate('SongsPlugin.EditVerseForm', '&Insert'))
|
||||
|
|
|
@ -82,8 +82,7 @@ class EditVerseForm(QtGui.QDialog, Ui_EditVerseDialog):
|
|||
|
||||
def onInsertButtonClicked(self):
|
||||
verse_type_index = self.verseTypeComboBox.currentIndex()
|
||||
self.insertVerse(VerseType.Tags[verse_type_index],
|
||||
self.verseNumberBox.value())
|
||||
self.insertVerse(VerseType.tags[verse_type_index], self.verseNumberBox.value())
|
||||
|
||||
def onVerseTypeComboBoxChanged(self):
|
||||
self.updateSuggestedVerseNumber()
|
||||
|
@ -93,12 +92,11 @@ class EditVerseForm(QtGui.QDialog, Ui_EditVerseDialog):
|
|||
|
||||
def updateSuggestedVerseNumber(self):
|
||||
"""
|
||||
Adjusts the verse number SpinBox in regard to the selected verse type
|
||||
and the cursor's position.
|
||||
Adjusts the verse number SpinBox in regard to the selected verse type and the cursor's position.
|
||||
"""
|
||||
position = self.verseTextEdit.textCursor().position()
|
||||
text = self.verseTextEdit.toPlainText()
|
||||
verse_name = VerseType.TranslatedNames[
|
||||
verse_name = VerseType.translated_names[
|
||||
self.verseTypeComboBox.currentIndex()]
|
||||
if not text:
|
||||
return
|
||||
|
@ -120,8 +118,7 @@ class EditVerseForm(QtGui.QDialog, Ui_EditVerseDialog):
|
|||
verse_num = 1
|
||||
self.verseNumberBox.setValue(verse_num)
|
||||
|
||||
def setVerse(self, text, single=False,
|
||||
tag=u'%s1' % VerseType.Tags[VerseType.Verse]):
|
||||
def setVerse(self, text, single=False, tag=u'%s1' % VerseType.tags[VerseType.Verse]):
|
||||
self.hasSingleVerse = single
|
||||
if single:
|
||||
verse_type_index = VerseType.from_tag(tag[0], None)
|
||||
|
@ -132,7 +129,7 @@ class EditVerseForm(QtGui.QDialog, Ui_EditVerseDialog):
|
|||
self.insertButton.setVisible(False)
|
||||
else:
|
||||
if not text:
|
||||
text = u'---[%s:1]---\n' % VerseType.TranslatedNames[VerseType.Verse]
|
||||
text = u'---[%s:1]---\n' % VerseType.translated_names[VerseType.Verse]
|
||||
self.verseTypeComboBox.setCurrentIndex(0)
|
||||
self.verseNumberBox.setValue(1)
|
||||
self.insertButton.setVisible(True)
|
||||
|
@ -141,12 +138,12 @@ class EditVerseForm(QtGui.QDialog, Ui_EditVerseDialog):
|
|||
self.verseTextEdit.moveCursor(QtGui.QTextCursor.End)
|
||||
|
||||
def getVerse(self):
|
||||
return self.verseTextEdit.toPlainText(), VerseType.Tags[self.verseTypeComboBox.currentIndex()], \
|
||||
return self.verseTextEdit.toPlainText(), VerseType.tags[self.verseTypeComboBox.currentIndex()], \
|
||||
unicode(self.verseNumberBox.value())
|
||||
|
||||
def getVerseAll(self):
|
||||
text = self.verseTextEdit.toPlainText()
|
||||
if not text.startswith(u'---['):
|
||||
text = u'---[%s:1]---\n%s' % (VerseType.TranslatedNames[VerseType.Verse], text)
|
||||
text = u'---[%s:1]---\n%s' % (VerseType.translated_names[VerseType.Verse], text)
|
||||
return text
|
||||
|
||||
|
|
|
@ -37,8 +37,7 @@ from ui import SongStrings
|
|||
|
||||
WHITESPACE = re.compile(r'[\W_]+', re.UNICODE)
|
||||
APOSTROPHE = re.compile(u'[\'`’ʻ′]', re.UNICODE)
|
||||
PATTERN = re.compile(r"\\([a-z]{1,32})(-?\d{1,10})?[ ]?|\\'"
|
||||
r"([0-9a-f]{2})|\\([^a-z])|([{}])|[\r\n]+|(.)", re.I)
|
||||
PATTERN = re.compile(r"\\([a-z]{1,32})(-?\d{1,10})?[ ]?|\\'([0-9a-f]{2})|\\([^a-z])|([{}])|[\r\n]+|(.)", re.I)
|
||||
# RTF control words which specify a "destination" to be ignored.
|
||||
DESTINATIONS = frozenset((
|
||||
u'aftncn', u'aftnsep', u'aftnsepc', u'annotation', u'atnauthor',
|
||||
|
@ -138,8 +137,7 @@ CHARSET_MAPPING = {
|
|||
|
||||
class VerseType(object):
|
||||
"""
|
||||
VerseType provides an enumeration for the tags that may be associated
|
||||
with verses in songs.
|
||||
VerseType provides an enumeration for the tags that may be associated with verses in songs.
|
||||
"""
|
||||
Verse = 0
|
||||
Chorus = 1
|
||||
|
@ -149,7 +147,7 @@ class VerseType(object):
|
|||
Ending = 5
|
||||
Other = 6
|
||||
|
||||
Names = [
|
||||
names = [
|
||||
u'Verse',
|
||||
u'Chorus',
|
||||
u'Bridge',
|
||||
|
@ -157,9 +155,9 @@ class VerseType(object):
|
|||
u'Intro',
|
||||
u'Ending',
|
||||
u'Other']
|
||||
Tags = [name[0].lower() for name in Names]
|
||||
tags = [name[0].lower() for name in names]
|
||||
|
||||
TranslatedNames = [
|
||||
translated_names = [
|
||||
translate('SongsPlugin.VerseType', 'Verse'),
|
||||
translate('SongsPlugin.VerseType', 'Chorus'),
|
||||
translate('SongsPlugin.VerseType', 'Bridge'),
|
||||
|
@ -167,13 +165,12 @@ class VerseType(object):
|
|||
translate('SongsPlugin.VerseType', 'Intro'),
|
||||
translate('SongsPlugin.VerseType', 'Ending'),
|
||||
translate('SongsPlugin.VerseType', 'Other')]
|
||||
TranslatedTags = [name[0].lower() for name in TranslatedNames]
|
||||
translated_tags = [name[0].lower() for name in translated_names]
|
||||
|
||||
@staticmethod
|
||||
def translated_tag(verse_tag, default=Other):
|
||||
"""
|
||||
Return the translated UPPERCASE tag for a given tag,
|
||||
used to show translated verse tags in UI
|
||||
Return the translated UPPERCASE tag for a given tag, used to show translated verse tags in UI
|
||||
|
||||
``verse_tag``
|
||||
The string to return a VerseType for
|
||||
|
@ -182,11 +179,11 @@ class VerseType(object):
|
|||
Default return value if no matching tag is found
|
||||
"""
|
||||
verse_tag = verse_tag[0].lower()
|
||||
for num, tag in enumerate(VerseType.Tags):
|
||||
for num, tag in enumerate(VerseType.tags):
|
||||
if verse_tag == tag:
|
||||
return VerseType.TranslatedTags[num].upper()
|
||||
if default in VerseType.TranslatedTags:
|
||||
return VerseType.TranslatedTags[default].upper()
|
||||
return VerseType.translated_tags[num].upper()
|
||||
if default in VerseType.translated_tags:
|
||||
return VerseType.translated_tags[default].upper()
|
||||
|
||||
@staticmethod
|
||||
def translated_name(verse_tag, default=Other):
|
||||
|
@ -200,11 +197,11 @@ class VerseType(object):
|
|||
Default return value if no matching tag is found
|
||||
"""
|
||||
verse_tag = verse_tag[0].lower()
|
||||
for num, tag in enumerate(VerseType.Tags):
|
||||
for num, tag in enumerate(VerseType.tags):
|
||||
if verse_tag == tag:
|
||||
return VerseType.TranslatedNames[num]
|
||||
if default in VerseType.TranslatedNames:
|
||||
return VerseType.TranslatedNames[default]
|
||||
return VerseType.translated_names[num]
|
||||
if default in VerseType.translated_names:
|
||||
return VerseType.translated_names[default]
|
||||
|
||||
@staticmethod
|
||||
def from_tag(verse_tag, default=Other):
|
||||
|
@ -218,7 +215,7 @@ class VerseType(object):
|
|||
Default return value if no matching tag is found
|
||||
"""
|
||||
verse_tag = verse_tag[0].lower()
|
||||
for num, tag in enumerate(VerseType.Tags):
|
||||
for num, tag in enumerate(VerseType.tags):
|
||||
if verse_tag == tag:
|
||||
return num
|
||||
return default
|
||||
|
@ -235,7 +232,7 @@ class VerseType(object):
|
|||
Default return value if no matching tag is found
|
||||
"""
|
||||
verse_tag = verse_tag[0].lower()
|
||||
for num, tag in enumerate(VerseType.TranslatedTags):
|
||||
for num, tag in enumerate(VerseType.translated_tags):
|
||||
if verse_tag == tag:
|
||||
return num
|
||||
return default
|
||||
|
@ -252,7 +249,7 @@ class VerseType(object):
|
|||
Default return value if no matching tag is found
|
||||
"""
|
||||
verse_name = verse_name.lower()
|
||||
for num, name in enumerate(VerseType.Names):
|
||||
for num, name in enumerate(VerseType.names):
|
||||
if verse_name == name.lower():
|
||||
return num
|
||||
return default
|
||||
|
@ -266,7 +263,7 @@ class VerseType(object):
|
|||
The string to return a VerseType for
|
||||
"""
|
||||
verse_name = verse_name.lower()
|
||||
for num, translation in enumerate(VerseType.TranslatedNames):
|
||||
for num, translation in enumerate(VerseType.translated_names):
|
||||
if verse_name == translation.lower():
|
||||
return num
|
||||
|
||||
|
@ -296,13 +293,11 @@ class VerseType(object):
|
|||
|
||||
def retrieve_windows_encoding(recommendation=None):
|
||||
"""
|
||||
Determines which encoding to use on an information source. The process uses
|
||||
both automated detection, which is passed to this method as a
|
||||
recommendation, and user confirmation to return an encoding.
|
||||
Determines which encoding to use on an information source. The process uses both automated detection, which is
|
||||
passed to this method as a recommendation, and user confirmation to return an encoding.
|
||||
|
||||
``recommendation``
|
||||
A recommended encoding discovered programmatically for the user to
|
||||
confirm.
|
||||
A recommended encoding discovered programmatically for the user to confirm.
|
||||
"""
|
||||
# map chardet result to compatible windows standard code page
|
||||
codepage_mapping = {'IBM866': u'cp866', 'TIS-620': u'cp874',
|
||||
|
@ -355,24 +350,22 @@ def retrieve_windows_encoding(recommendation=None):
|
|||
|
||||
def clean_string(string):
|
||||
"""
|
||||
Strips punctuation from the passed string to assist searching
|
||||
Strips punctuation from the passed string to assist searching.
|
||||
"""
|
||||
return WHITESPACE.sub(u' ', APOSTROPHE.sub(u'', string)).lower()
|
||||
|
||||
|
||||
def clean_title(title):
|
||||
"""
|
||||
Cleans the song title by removing Unicode control chars groups C0 & C1,
|
||||
as well as any trailing spaces
|
||||
Cleans the song title by removing Unicode control chars groups C0 & C1, as well as any trailing spaces.
|
||||
"""
|
||||
return CONTROL_CHARS.sub(u'', title).rstrip()
|
||||
|
||||
|
||||
def clean_song(manager, song):
|
||||
"""
|
||||
Cleans the search title, rebuilds the search lyrics, adds a default author
|
||||
if the song does not have one and other clean ups. This should always
|
||||
called when a new song is added or changed.
|
||||
Cleans the search title, rebuilds the search lyrics, adds a default author if the song does not have one and other
|
||||
clean ups. This should always called when a new song is added or changed.
|
||||
|
||||
``manager``
|
||||
The song's manager.
|
||||
|
@ -397,21 +390,20 @@ def clean_song(manager, song):
|
|||
song.search_title = clean_string(song.title) + u'@' + clean_string(song.alternate_title)
|
||||
# Only do this, if we the song is a 1.9.4 song (or older).
|
||||
if song.lyrics.find(u'<lyrics language="en">') != -1:
|
||||
# Remove the old "language" attribute from lyrics tag (prior to 1.9.5).
|
||||
# This is not very important, but this keeps the database clean. This
|
||||
# can be removed when everybody has cleaned his songs.
|
||||
# Remove the old "language" attribute from lyrics tag (prior to 1.9.5). This is not very important, but this
|
||||
# keeps the database clean. This can be removed when everybody has cleaned his songs.
|
||||
song.lyrics = song.lyrics.replace(u'<lyrics language="en">', u'<lyrics>')
|
||||
verses = SongXML().get_verses(song.lyrics)
|
||||
song.search_lyrics = u' '.join([clean_string(verse[1])
|
||||
for verse in verses])
|
||||
# We need a new and clean SongXML instance.
|
||||
sxml = SongXML()
|
||||
# Rebuild the song's verses, to remove any wrong verse names (for
|
||||
# example translated ones), which might have been added prior to 1.9.5.
|
||||
# Rebuild the song's verses, to remove any wrong verse names (for example translated ones), which might have
|
||||
# been added prior to 1.9.5.
|
||||
# List for later comparison.
|
||||
compare_order = []
|
||||
for verse in verses:
|
||||
verse_type = VerseType.Tags[VerseType.from_loose_input(verse[0][u'type'])]
|
||||
verse_type = VerseType.tags[VerseType.from_loose_input(verse[0][u'type'])]
|
||||
sxml.add_verse_to_lyrics(
|
||||
verse_type,
|
||||
verse[0][u'label'],
|
||||
|
@ -422,15 +414,14 @@ def clean_song(manager, song):
|
|||
if verse[0][u'label'] == u'1':
|
||||
compare_order.append(verse_type.upper())
|
||||
song.lyrics = unicode(sxml.extract_xml(), u'utf-8')
|
||||
# Rebuild the verse order, to convert translated verse tags, which might
|
||||
# have been added prior to 1.9.5.
|
||||
# Rebuild the verse order, to convert translated verse tags, which might have been added prior to 1.9.5.
|
||||
if song.verse_order:
|
||||
order = CONTROL_CHARS.sub(u'', song.verse_order).strip().split()
|
||||
else:
|
||||
order = []
|
||||
new_order = []
|
||||
for verse_def in order:
|
||||
verse_type = VerseType.Tags[
|
||||
verse_type = VerseType.tags[
|
||||
VerseType.from_loose_input(verse_def[0])]
|
||||
if len(verse_def) > 1:
|
||||
new_order.append((u'%s%s' % (verse_type, verse_def[1:])).upper())
|
||||
|
@ -463,16 +454,16 @@ def get_encoding(font, font_table, default_encoding, failed=False):
|
|||
Finds an encoding to use. Asks user, if necessary.
|
||||
|
||||
``font``
|
||||
The number of currently active font.
|
||||
The number of currently active font.
|
||||
|
||||
``font_table``
|
||||
Dictionary of fonts and respective encodings.
|
||||
Dictionary of fonts and respective encodings.
|
||||
|
||||
``default_encoding``
|
||||
The default encoding to use when font_table is empty or no font is used.
|
||||
The default encoding to use when font_table is empty or no font is used.
|
||||
|
||||
``failed``
|
||||
A boolean indicating whether the previous encoding didn't work.
|
||||
A boolean indicating whether the previous encoding didn't work.
|
||||
"""
|
||||
encoding = None
|
||||
if font in font_table:
|
||||
|
@ -494,10 +485,10 @@ def strip_rtf(text, default_encoding=None):
|
|||
http://stackoverflow.com/questions/188545
|
||||
|
||||
``text``
|
||||
RTF-encoded text, a string.
|
||||
RTF-encoded text, a string.
|
||||
|
||||
``default_encoding``
|
||||
Default encoding to use when no encoding is specified.
|
||||
Default encoding to use when no encoding is specified.
|
||||
"""
|
||||
# Current font is the font tag we last met.
|
||||
font = u''
|
||||
|
@ -589,8 +580,7 @@ def strip_rtf(text, default_encoding=None):
|
|||
|
||||
def natcmp(a, b):
|
||||
"""
|
||||
Natural string comparison which mimics the behaviour of Python's internal
|
||||
cmp function.
|
||||
Natural string comparison which mimics the behaviour of Python's internal cmp function.
|
||||
"""
|
||||
if len(a) <= len(b):
|
||||
for i, key in enumerate(a):
|
||||
|
|
|
@ -188,13 +188,13 @@ class CCLIFileImport(SongImport):
|
|||
words_list = song_words.split(u'/t')
|
||||
for counter in range(len(field_list)):
|
||||
if field_list[counter].startswith(u'Ver'):
|
||||
verse_type = VerseType.Tags[VerseType.Verse]
|
||||
verse_type = VerseType.tags[VerseType.Verse]
|
||||
elif field_list[counter].startswith(u'Ch'):
|
||||
verse_type = VerseType.Tags[VerseType.Chorus]
|
||||
verse_type = VerseType.tags[VerseType.Chorus]
|
||||
elif field_list[counter].startswith(u'Br'):
|
||||
verse_type = VerseType.Tags[VerseType.Bridge]
|
||||
verse_type = VerseType.tags[VerseType.Bridge]
|
||||
else:
|
||||
verse_type = VerseType.Tags[VerseType.Other]
|
||||
verse_type = VerseType.tags[VerseType.Other]
|
||||
check_first_verse_line = True
|
||||
verse_text = unicode(words_list[counter])
|
||||
verse_text = verse_text.replace(u'/n', u'\n')
|
||||
|
@ -202,15 +202,15 @@ class CCLIFileImport(SongImport):
|
|||
verse_lines = verse_text.split(u'\n', 1)
|
||||
if check_first_verse_line:
|
||||
if verse_lines[0].startswith(u'(PRE-CHORUS'):
|
||||
verse_type = VerseType.Tags[VerseType.PreChorus]
|
||||
verse_type = VerseType.tags[VerseType.PreChorus]
|
||||
log.debug(u'USR verse PRE-CHORUS: %s', verse_lines[0])
|
||||
verse_text = verse_lines[1]
|
||||
elif verse_lines[0].startswith(u'(BRIDGE'):
|
||||
verse_type = VerseType.Tags[VerseType.Bridge]
|
||||
verse_type = VerseType.tags[VerseType.Bridge]
|
||||
log.debug(u'USR verse BRIDGE')
|
||||
verse_text = verse_lines[1]
|
||||
elif verse_lines[0].startswith(u'('):
|
||||
verse_type = VerseType.Tags[VerseType.Other]
|
||||
verse_type = VerseType.tags[VerseType.Other]
|
||||
verse_text = verse_lines[1]
|
||||
if verse_text:
|
||||
self.addVerse(verse_text, verse_type)
|
||||
|
@ -292,31 +292,31 @@ class CCLIFileImport(SongImport):
|
|||
verse_desc_parts = clean_line.split(u' ')
|
||||
if len(verse_desc_parts) == 2:
|
||||
if verse_desc_parts[0].startswith(u'Ver'):
|
||||
verse_type = VerseType.Tags[VerseType.Verse]
|
||||
verse_type = VerseType.tags[VerseType.Verse]
|
||||
elif verse_desc_parts[0].startswith(u'Ch'):
|
||||
verse_type = VerseType.Tags[VerseType.Chorus]
|
||||
verse_type = VerseType.tags[VerseType.Chorus]
|
||||
elif verse_desc_parts[0].startswith(u'Br'):
|
||||
verse_type = VerseType.Tags[VerseType.Bridge]
|
||||
verse_type = VerseType.tags[VerseType.Bridge]
|
||||
else:
|
||||
# we need to analyse the next line for
|
||||
# verse type, so set flag
|
||||
verse_type = VerseType.Tags[VerseType.Other]
|
||||
verse_type = VerseType.tags[VerseType.Other]
|
||||
check_first_verse_line = True
|
||||
verse_number = verse_desc_parts[1]
|
||||
else:
|
||||
verse_type = VerseType.Tags[VerseType.Other]
|
||||
verse_type = VerseType.tags[VerseType.Other]
|
||||
verse_number = 1
|
||||
verse_start = True
|
||||
else:
|
||||
# check first line for verse type
|
||||
if check_first_verse_line:
|
||||
if line.startswith(u'(PRE-CHORUS'):
|
||||
verse_type = VerseType.Tags[VerseType.PreChorus]
|
||||
verse_type = VerseType.tags[VerseType.PreChorus]
|
||||
elif line.startswith(u'(BRIDGE'):
|
||||
verse_type = VerseType.Tags[VerseType.Bridge]
|
||||
verse_type = VerseType.tags[VerseType.Bridge]
|
||||
# Handle all other misc types
|
||||
elif line.startswith(u'('):
|
||||
verse_type = VerseType.Tags[VerseType.Other]
|
||||
verse_type = VerseType.tags[VerseType.Other]
|
||||
else:
|
||||
verse_text = verse_text + line
|
||||
check_first_verse_line = False
|
||||
|
|
|
@ -175,12 +175,12 @@ class EasySlidesImport(SongImport):
|
|||
# if the regions are inside verses
|
||||
regionsInVerses = (regions and regionlines[regionlines.keys()[0]] > 1)
|
||||
MarkTypes = {
|
||||
u'CHORUS': VerseType.Tags[VerseType.Chorus],
|
||||
u'VERSE': VerseType.Tags[VerseType.Verse],
|
||||
u'INTRO': VerseType.Tags[VerseType.Intro],
|
||||
u'ENDING': VerseType.Tags[VerseType.Ending],
|
||||
u'BRIDGE': VerseType.Tags[VerseType.Bridge],
|
||||
u'PRECHORUS': VerseType.Tags[VerseType.PreChorus]
|
||||
u'CHORUS': VerseType.tags[VerseType.Chorus],
|
||||
u'VERSE': VerseType.tags[VerseType.Verse],
|
||||
u'INTRO': VerseType.tags[VerseType.Intro],
|
||||
u'ENDING': VerseType.tags[VerseType.Ending],
|
||||
u'BRIDGE': VerseType.tags[VerseType.Bridge],
|
||||
u'PRECHORUS': VerseType.tags[VerseType.PreChorus]
|
||||
}
|
||||
verses = {}
|
||||
# list as [region, versetype, versenum, instance]
|
||||
|
|
|
@ -178,7 +178,7 @@ class EasyWorshipSongImport(SongImport):
|
|||
if result is None:
|
||||
return
|
||||
words, self.encoding = result
|
||||
verse_type = VerseType.Tags[VerseType.Verse]
|
||||
verse_type = VerseType.tags[VerseType.Verse]
|
||||
for verse in SLIDE_BREAK_REGEX.split(words):
|
||||
verse = verse.strip()
|
||||
if not verse:
|
||||
|
@ -187,17 +187,17 @@ class EasyWorshipSongImport(SongImport):
|
|||
first_line_is_tag = False
|
||||
# EW tags: verse, chorus, pre-chorus, bridge, tag,
|
||||
# intro, ending, slide
|
||||
for type in VerseType.Names+[u'tag', u'slide']:
|
||||
type = type.lower()
|
||||
for tag in VerseType.tags + [u'tag', u'slide']:
|
||||
tag = tag.lower()
|
||||
ew_tag = verse_split[0].strip().lower()
|
||||
if ew_tag.startswith(type):
|
||||
verse_type = type[0]
|
||||
if type == u'tag' or type == u'slide':
|
||||
verse_type = VerseType.Tags[VerseType.Other]
|
||||
if ew_tag.startswith(tag):
|
||||
verse_type = tag[0]
|
||||
if tag == u'tag' or tag == u'slide':
|
||||
verse_type = VerseType.tags[VerseType.Other]
|
||||
first_line_is_tag = True
|
||||
number_found = False
|
||||
# check if tag is followed by number and/or note
|
||||
if len(ew_tag) > len(type):
|
||||
if len(ew_tag) > len(tag):
|
||||
match = NUMBER_REGEX.search(ew_tag)
|
||||
if match:
|
||||
number = match.group()
|
||||
|
@ -209,10 +209,7 @@ class EasyWorshipSongImport(SongImport):
|
|||
if not number_found:
|
||||
verse_type += u'1'
|
||||
break
|
||||
self.addVerse(
|
||||
verse_split[-1].strip() \
|
||||
if first_line_is_tag else verse,
|
||||
verse_type)
|
||||
self.addVerse(verse_split[-1].strip() if first_line_is_tag else verse, verse_type)
|
||||
if len(self.comments) > 5:
|
||||
self.comments += unicode(translate('SongsPlugin.EasyWorshipSongImport',
|
||||
'\n[above are Song Tags with notes imported from EasyWorship]'))
|
||||
|
@ -224,8 +221,7 @@ class EasyWorshipSongImport(SongImport):
|
|||
self.memoFile.close()
|
||||
|
||||
def findField(self, field_name):
|
||||
return [i for i, x in enumerate(self.fieldDescs)
|
||||
if x.name == field_name][0]
|
||||
return [i for i, x in enumerate(self.fieldDescs) if x.name == field_name][0]
|
||||
|
||||
def setRecordStruct(self, field_descs):
|
||||
# Begin with empty field struct list
|
||||
|
|
|
@ -412,13 +412,13 @@ class FoilPresenter(object):
|
|||
temp_sortnr_backup = 1
|
||||
temp_sortnr_liste = []
|
||||
verse_count = {
|
||||
VerseType.Tags[VerseType.Verse]: 1,
|
||||
VerseType.Tags[VerseType.Chorus]: 1,
|
||||
VerseType.Tags[VerseType.Bridge]: 1,
|
||||
VerseType.Tags[VerseType.Ending]: 1,
|
||||
VerseType.Tags[VerseType.Other]: 1,
|
||||
VerseType.Tags[VerseType.Intro]: 1,
|
||||
VerseType.Tags[VerseType.PreChorus]: 1
|
||||
VerseType.tags[VerseType.Verse]: 1,
|
||||
VerseType.tags[VerseType.Chorus]: 1,
|
||||
VerseType.tags[VerseType.Bridge]: 1,
|
||||
VerseType.tags[VerseType.Ending]: 1,
|
||||
VerseType.tags[VerseType.Other]: 1,
|
||||
VerseType.tags[VerseType.Intro]: 1,
|
||||
VerseType.tags[VerseType.PreChorus]: 1
|
||||
}
|
||||
for strophe in foilpresenterfolie.strophen.strophe:
|
||||
text = self._child(strophe.text_) if hasattr(strophe, u'text_') else u''
|
||||
|
@ -438,25 +438,25 @@ class FoilPresenter(object):
|
|||
temp_verse_name = re.compile(u'[0-9].*').sub(u'', verse_name)
|
||||
temp_verse_name = temp_verse_name[:3].lower()
|
||||
if temp_verse_name == u'ref':
|
||||
verse_type = VerseType.Tags[VerseType.Chorus]
|
||||
verse_type = VerseType.tags[VerseType.Chorus]
|
||||
elif temp_verse_name == u'r':
|
||||
verse_type = VerseType.Tags[VerseType.Chorus]
|
||||
verse_type = VerseType.tags[VerseType.Chorus]
|
||||
elif temp_verse_name == u'':
|
||||
verse_type = VerseType.Tags[VerseType.Verse]
|
||||
verse_type = VerseType.tags[VerseType.Verse]
|
||||
elif temp_verse_name == u'v':
|
||||
verse_type = VerseType.Tags[VerseType.Verse]
|
||||
verse_type = VerseType.tags[VerseType.Verse]
|
||||
elif temp_verse_name == u'bri':
|
||||
verse_type = VerseType.Tags[VerseType.Bridge]
|
||||
verse_type = VerseType.tags[VerseType.Bridge]
|
||||
elif temp_verse_name == u'cod':
|
||||
verse_type = VerseType.Tags[VerseType.Ending]
|
||||
verse_type = VerseType.tags[VerseType.Ending]
|
||||
elif temp_verse_name == u'sch':
|
||||
verse_type = VerseType.Tags[VerseType.Ending]
|
||||
verse_type = VerseType.tags[VerseType.Ending]
|
||||
elif temp_verse_name == u'pre':
|
||||
verse_type = VerseType.Tags[VerseType.PreChorus]
|
||||
verse_type = VerseType.tags[VerseType.PreChorus]
|
||||
elif temp_verse_name == u'int':
|
||||
verse_type = VerseType.Tags[VerseType.Intro]
|
||||
verse_type = VerseType.tags[VerseType.Intro]
|
||||
else:
|
||||
verse_type = VerseType.Tags[VerseType.Other]
|
||||
verse_type = VerseType.tags[VerseType.Other]
|
||||
verse_number = re.compile(u'[a-zA-Z.+-_ ]*').sub(u'', verse_name)
|
||||
# Foilpresenter allows e. g. "C", but we need "C1".
|
||||
if not verse_number:
|
||||
|
@ -469,7 +469,7 @@ class FoilPresenter(object):
|
|||
if value == u''.join((verse_type, verse_number)):
|
||||
verse_number = unicode(int(verse_number) + 1)
|
||||
verse_type_index = VerseType.from_tag(verse_type[0])
|
||||
verse_type = VerseType.Names[verse_type_index]
|
||||
verse_type = VerseType.tags[verse_type_index]
|
||||
temp_verse_order[verse_sortnr] = u''.join((verse_type[0],
|
||||
verse_number))
|
||||
temp_verse_order_backup.append(u''.join((verse_type[0],
|
||||
|
|
|
@ -430,7 +430,7 @@ class SongMediaItem(MediaManagerItem):
|
|||
verse_index = VerseType.from_string(verse_tag, None)
|
||||
if verse_index is None:
|
||||
verse_index = VerseType.from_tag(verse_tag)
|
||||
verse_tag = VerseType.TranslatedTags[verse_index].upper()
|
||||
verse_tag = VerseType.translated_tags[verse_index].upper()
|
||||
verse_def = u'%s%s' % (verse_tag, verse[0][u'label'])
|
||||
service_item.add_from_text(unicode(verse[1]), verse_def)
|
||||
else:
|
||||
|
@ -445,7 +445,7 @@ class SongMediaItem(MediaManagerItem):
|
|||
verse_index = VerseType.from_translated_tag(verse[0][u'type'])
|
||||
else:
|
||||
verse_index = VerseType.from_tag(verse[0][u'type'])
|
||||
verse_tag = VerseType.TranslatedTags[verse_index]
|
||||
verse_tag = VerseType.translated_tags[verse_index]
|
||||
verse_def = u'%s%s' % (verse_tag, verse[0][u'label'])
|
||||
service_item.add_from_text(verse[1], verse_def)
|
||||
else:
|
||||
|
|
|
@ -160,7 +160,7 @@ class OpenSongImport(SongImport):
|
|||
# keep track of verses appearance order
|
||||
our_verse_order = []
|
||||
# default verse
|
||||
verse_tag = VerseType.Tags[VerseType.Verse]
|
||||
verse_tag = VerseType.tags[VerseType.Verse]
|
||||
verse_num = u'1'
|
||||
# for the case where song has several sections with same marker
|
||||
inst = 1
|
||||
|
@ -184,21 +184,18 @@ class OpenSongImport(SongImport):
|
|||
# drop the square brackets
|
||||
right_bracket = this_line.find(u']')
|
||||
content = this_line[1:right_bracket].lower()
|
||||
# have we got any digits?
|
||||
# If so, verse number is everything from the digits
|
||||
# to the end (openlp does not have concept of part verses, so
|
||||
# just ignore any non integers on the end (including floats))
|
||||
# have we got any digits? If so, verse number is everything from the digits to the end (openlp does not
|
||||
# have concept of part verses, so just ignore any non integers on the end (including floats))
|
||||
match = re.match(u'(\D*)(\d+)', content)
|
||||
if match is not None:
|
||||
verse_tag = match.group(1)
|
||||
verse_num = match.group(2)
|
||||
else:
|
||||
# otherwise we assume number 1 and take the whole prefix as
|
||||
# the verse tag
|
||||
# otherwise we assume number 1 and take the whole prefix as the verse tag
|
||||
verse_tag = content
|
||||
verse_num = u'1'
|
||||
verse_index = VerseType.from_loose_input(verse_tag) if verse_tag else 0
|
||||
verse_tag = VerseType.Tags[verse_index]
|
||||
verse_tag = VerseType.tags[verse_index]
|
||||
inst = 1
|
||||
if [verse_tag, verse_num, inst] in our_verse_order and verse_num in verses.get(verse_tag, {}):
|
||||
inst = len(verses[verse_tag][verse_num]) + 1
|
||||
|
@ -236,8 +233,8 @@ class OpenSongImport(SongImport):
|
|||
# figure out the presentation order, if present
|
||||
if u'presentation' in fields and root.presentation:
|
||||
order = unicode(root.presentation)
|
||||
# We make all the tags in the lyrics lower case, so match that here
|
||||
# and then split into a list on the whitespace
|
||||
# We make all the tags in the lyrics lower case, so match that here and then split into a list on the
|
||||
# whitespace.
|
||||
order = order.lower().split()
|
||||
for verse_def in order:
|
||||
match = re.match(u'(\D*)(\d+.*)', verse_def)
|
||||
|
@ -245,7 +242,7 @@ class OpenSongImport(SongImport):
|
|||
verse_tag = match.group(1)
|
||||
verse_num = match.group(2)
|
||||
if not verse_tag:
|
||||
verse_tag = VerseType.Tags[VerseType.Verse]
|
||||
verse_tag = VerseType.tags[VerseType.Verse]
|
||||
else:
|
||||
# Assume it's no.1 if there are no digits
|
||||
verse_tag = verse_def
|
||||
|
|
|
@ -27,8 +27,7 @@
|
|||
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
||||
###############################################################################
|
||||
"""
|
||||
The :mod:`songbeamerimport` module provides the functionality for importing
|
||||
SongBeamer songs into the OpenLP database.
|
||||
The :mod:`songbeamerimport` module provides the functionality for importing SongBeamer songs into the OpenLP database.
|
||||
"""
|
||||
import chardet
|
||||
import codecs
|
||||
|
@ -43,32 +42,31 @@ log = logging.getLogger(__name__)
|
|||
|
||||
class SongBeamerTypes(object):
|
||||
MarkTypes = {
|
||||
u'Refrain': VerseType.Tags[VerseType.Chorus],
|
||||
u'Chorus': VerseType.Tags[VerseType.Chorus],
|
||||
u'Vers': VerseType.Tags[VerseType.Verse],
|
||||
u'Verse': VerseType.Tags[VerseType.Verse],
|
||||
u'Strophe': VerseType.Tags[VerseType.Verse],
|
||||
u'Intro': VerseType.Tags[VerseType.Intro],
|
||||
u'Coda': VerseType.Tags[VerseType.Ending],
|
||||
u'Ending': VerseType.Tags[VerseType.Ending],
|
||||
u'Bridge': VerseType.Tags[VerseType.Bridge],
|
||||
u'Interlude': VerseType.Tags[VerseType.Bridge],
|
||||
u'Zwischenspiel': VerseType.Tags[VerseType.Bridge],
|
||||
u'Pre-Chorus': VerseType.Tags[VerseType.PreChorus],
|
||||
u'Pre-Refrain': VerseType.Tags[VerseType.PreChorus],
|
||||
u'Pre-Bridge': VerseType.Tags[VerseType.Other],
|
||||
u'Pre-Coda': VerseType.Tags[VerseType.Other],
|
||||
u'Unbekannt': VerseType.Tags[VerseType.Other],
|
||||
u'Unknown': VerseType.Tags[VerseType.Other],
|
||||
u'Unbenannt': VerseType.Tags[VerseType.Other]
|
||||
u'Refrain': VerseType.tags[VerseType.Chorus],
|
||||
u'Chorus': VerseType.tags[VerseType.Chorus],
|
||||
u'Vers': VerseType.tags[VerseType.Verse],
|
||||
u'Verse': VerseType.tags[VerseType.Verse],
|
||||
u'Strophe': VerseType.tags[VerseType.Verse],
|
||||
u'Intro': VerseType.tags[VerseType.Intro],
|
||||
u'Coda': VerseType.tags[VerseType.Ending],
|
||||
u'Ending': VerseType.tags[VerseType.Ending],
|
||||
u'Bridge': VerseType.tags[VerseType.Bridge],
|
||||
u'Interlude': VerseType.tags[VerseType.Bridge],
|
||||
u'Zwischenspiel': VerseType.tags[VerseType.Bridge],
|
||||
u'Pre-Chorus': VerseType.tags[VerseType.PreChorus],
|
||||
u'Pre-Refrain': VerseType.tags[VerseType.PreChorus],
|
||||
u'Pre-Bridge': VerseType.tags[VerseType.Other],
|
||||
u'Pre-Coda': VerseType.tags[VerseType.Other],
|
||||
u'Unbekannt': VerseType.tags[VerseType.Other],
|
||||
u'Unknown': VerseType.tags[VerseType.Other],
|
||||
u'Unbenannt': VerseType.tags[VerseType.Other]
|
||||
}
|
||||
|
||||
|
||||
class SongBeamerImport(SongImport):
|
||||
"""
|
||||
Import Song Beamer files(s)
|
||||
Song Beamer file format is text based
|
||||
in the beginning are one or more control tags written
|
||||
Import Song Beamer files(s). Song Beamer file format is text based in the beginning are one or more control tags
|
||||
written.
|
||||
"""
|
||||
HTML_TAG_PAIRS = [
|
||||
(re.compile(u'<b>'), u'{st}'),
|
||||
|
@ -113,7 +111,7 @@ class SongBeamerImport(SongImport):
|
|||
return
|
||||
self.setDefaults()
|
||||
self.currentVerse = u''
|
||||
self.currentVerseType = VerseType.Tags[VerseType.Verse]
|
||||
self.currentVerseType = VerseType.tags[VerseType.Verse]
|
||||
read_verses = False
|
||||
file_name = os.path.split(file)[1]
|
||||
if os.path.isfile(file):
|
||||
|
@ -137,7 +135,7 @@ class SongBeamerImport(SongImport):
|
|||
self.replaceHtmlTags()
|
||||
self.addVerse(self.currentVerse, self.currentVerseType)
|
||||
self.currentVerse = u''
|
||||
self.currentVerseType = VerseType.Tags[VerseType.Verse]
|
||||
self.currentVerseType = VerseType.tags[VerseType.Verse]
|
||||
read_verses = True
|
||||
verse_start = True
|
||||
elif read_verses:
|
||||
|
@ -155,8 +153,7 @@ class SongBeamerImport(SongImport):
|
|||
|
||||
def replaceHtmlTags(self):
|
||||
"""
|
||||
This can be called to replace SongBeamer's specific (html) tags with
|
||||
OpenLP's specific (html) tags.
|
||||
This can be called to replace SongBeamer's specific (html) tags with OpenLP's specific (html) tags.
|
||||
"""
|
||||
for pair in SongBeamerImport.HTML_TAG_PAIRS:
|
||||
self.currentVerse = pair[0].sub(pair[1], self.currentVerse)
|
||||
|
@ -166,8 +163,7 @@ class SongBeamerImport(SongImport):
|
|||
Parses a meta data line.
|
||||
|
||||
``line``
|
||||
The line in the file. It should consist of a tag and a value
|
||||
for this tag (unicode)::
|
||||
The line in the file. It should consist of a tag and a value for this tag (unicode)::
|
||||
|
||||
u'#Title=Nearer my God to Thee'
|
||||
"""
|
||||
|
@ -272,8 +268,8 @@ class SongBeamerImport(SongImport):
|
|||
|
||||
def checkVerseMarks(self, line):
|
||||
"""
|
||||
Check and add the verse's MarkType. Returns ``True`` if the given line
|
||||
contains a correct verse mark otherwise ``False``.
|
||||
Check and add the verse's MarkType. Returns ``True`` if the given linE contains a correct verse mark otherwise
|
||||
``False``.
|
||||
|
||||
``line``
|
||||
The line to check for marks (unicode).
|
||||
|
|
|
@ -303,13 +303,13 @@ class SongImport(QtCore.QObject):
|
|||
sxml = SongXML()
|
||||
other_count = 1
|
||||
for (verse_def, verse_text, lang) in self.verses:
|
||||
if verse_def[0].lower() in VerseType.Tags:
|
||||
if verse_def[0].lower() in VerseType.tags:
|
||||
verse_tag = verse_def[0].lower()
|
||||
else:
|
||||
new_verse_def = u'%s%d' % (VerseType.Tags[VerseType.Other], other_count)
|
||||
new_verse_def = u'%s%d' % (VerseType.tags[VerseType.Other], other_count)
|
||||
verses_changed_to_other[verse_def] = new_verse_def
|
||||
other_count += 1
|
||||
verse_tag = VerseType.Tags[VerseType.Other]
|
||||
verse_tag = VerseType.tags[VerseType.Other]
|
||||
log.info(u'Versetype %s changing to %s', verse_def, new_verse_def)
|
||||
verse_def = new_verse_def
|
||||
sxml.add_verse_to_lyrics(verse_tag, verse_def[1:], verse_text, lang)
|
||||
|
|
|
@ -152,11 +152,11 @@ class SongShowPlusImport(SongImport):
|
|||
elif block_key == CCLI_NO:
|
||||
self.ccliNumber = int(data)
|
||||
elif block_key == VERSE:
|
||||
self.addVerse(unicode(data, u'cp1252'), "%s%s" % (VerseType.Tags[VerseType.Verse], verse_no))
|
||||
self.addVerse(unicode(data, u'cp1252'), "%s%s" % (VerseType.tags[VerseType.Verse], verse_no))
|
||||
elif block_key == CHORUS:
|
||||
self.addVerse(unicode(data, u'cp1252'), "%s%s" % (VerseType.Tags[VerseType.Chorus], verse_no))
|
||||
self.addVerse(unicode(data, u'cp1252'), "%s%s" % (VerseType.tags[VerseType.Chorus], verse_no))
|
||||
elif block_key == BRIDGE:
|
||||
self.addVerse(unicode(data, u'cp1252'), "%s%s" % (VerseType.Tags[VerseType.Bridge], verse_no))
|
||||
self.addVerse(unicode(data, u'cp1252'), "%s%s" % (VerseType.tags[VerseType.Bridge], verse_no))
|
||||
elif block_key == TOPIC:
|
||||
self.topics.append(unicode(data, u'cp1252'))
|
||||
elif block_key == COMMENTS:
|
||||
|
@ -192,19 +192,19 @@ class SongShowPlusImport(SongImport):
|
|||
verse_number = "1"
|
||||
verse_type = verse_type.lower()
|
||||
if verse_type == "verse":
|
||||
verse_tag = VerseType.Tags[VerseType.Verse]
|
||||
verse_tag = VerseType.tags[VerseType.Verse]
|
||||
elif verse_type == "chorus":
|
||||
verse_tag = VerseType.Tags[VerseType.Chorus]
|
||||
verse_tag = VerseType.tags[VerseType.Chorus]
|
||||
elif verse_type == "bridge":
|
||||
verse_tag = VerseType.Tags[VerseType.Bridge]
|
||||
verse_tag = VerseType.tags[VerseType.Bridge]
|
||||
elif verse_type == "pre-chorus":
|
||||
verse_tag = VerseType.Tags[VerseType.PreChorus]
|
||||
verse_tag = VerseType.tags[VerseType.PreChorus]
|
||||
else:
|
||||
if verse_name not in self.otherList:
|
||||
if ignore_unique:
|
||||
return None
|
||||
self.otherCount += 1
|
||||
self.otherList[verse_name] = str(self.otherCount)
|
||||
verse_tag = VerseType.Tags[VerseType.Other]
|
||||
verse_tag = VerseType.tags[VerseType.Other]
|
||||
verse_number = self.otherList[verse_name]
|
||||
return verse_tag + verse_number
|
||||
|
|
|
@ -52,8 +52,7 @@ class SundayPlusImport(SongImport):
|
|||
"""
|
||||
Import Sunday Plus songs
|
||||
|
||||
The format examples can be found attached to bug report at
|
||||
<http://support.openlp.org/issues/395>
|
||||
The format examples can be found attached to bug report at <http://support.openlp.org/issues/395>
|
||||
"""
|
||||
|
||||
def __init__(self, manager, **kwargs):
|
||||
|
@ -90,7 +89,7 @@ class SundayPlusImport(SongImport):
|
|||
self.logError(u'File is malformed')
|
||||
return False
|
||||
i = 1
|
||||
verse_type = VerseType.Tags[VerseType.Verse]
|
||||
verse_type = VerseType.tags[VerseType.Verse]
|
||||
while i < len(data):
|
||||
# Data is held as #name: value pairs inside groups marked as [].
|
||||
# Now we are looking for the name.
|
||||
|
@ -137,8 +136,7 @@ class SundayPlusImport(SongImport):
|
|||
if name == 'MARKER_NAME':
|
||||
value = value.strip()
|
||||
if len(value):
|
||||
verse_type = VerseType.Tags[
|
||||
VerseType.from_loose_input(value[0])]
|
||||
verse_type = VerseType.tags[VerseType.from_loose_input(value[0])]
|
||||
if len(value) >= 2 and value[-1] in ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']:
|
||||
verse_type = "%s%s" % (verse_type, value[-1])
|
||||
elif name == 'Hotkey':
|
||||
|
@ -168,8 +166,7 @@ class SundayPlusImport(SongImport):
|
|||
self.copyright = u'Public Domain'
|
||||
continue
|
||||
processed_lines.append(line)
|
||||
self.addVerse('\n'.join(processed_lines).strip(),
|
||||
verse_type)
|
||||
self.addVerse('\n'.join(processed_lines).strip(), verse_type)
|
||||
if end == -1:
|
||||
break
|
||||
i = end + 1
|
||||
|
|
|
@ -97,10 +97,8 @@ class SongXML(object):
|
|||
Add a verse to the ``<lyrics>`` tag.
|
||||
|
||||
``type``
|
||||
A string denoting the type of verse. Possible values are *v*,
|
||||
*c*, *b*, *p*, *i*, *e* and *o*.
|
||||
Any other type is **not** allowed, this also includes translated
|
||||
types.
|
||||
A string denoting the type of verse. Possible values are *v*, *c*, *b*, *p*, *i*, *e* and *o*. Any other
|
||||
type is **not** allowed, this also includes translated types.
|
||||
|
||||
``number``
|
||||
An integer denoting the number of the item, for example: verse 1.
|
||||
|
@ -109,8 +107,7 @@ class SongXML(object):
|
|||
The actual text of the verse to be stored.
|
||||
|
||||
``lang``
|
||||
The verse's language code (ISO-639). This is not required, but
|
||||
should be added if available.
|
||||
The verse's language code (ISO-639). This is not required, but should be added if available.
|
||||
"""
|
||||
verse = etree.Element(u'verse', type=unicode(type),
|
||||
label=unicode(number))
|
||||
|
@ -128,24 +125,21 @@ class SongXML(object):
|
|||
|
||||
def get_verses(self, xml):
|
||||
"""
|
||||
Iterates through the verses in the XML and returns a list of verses
|
||||
and their attributes.
|
||||
Iterates through the verses in the XML and returns a list of verses and their attributes.
|
||||
|
||||
``xml``
|
||||
The XML of the song to be parsed.
|
||||
|
||||
The returned list has the following format::
|
||||
|
||||
[[{'type': 'v', 'label': '1'},
|
||||
u"optional slide split 1[---]optional slide split 2"],
|
||||
[[{'type': 'v', 'label': '1'}, u"optional slide split 1[---]optional slide split 2"],
|
||||
[{'lang': 'en', 'type': 'c', 'label': '1'}, u"English chorus"]]
|
||||
"""
|
||||
self.song_xml = None
|
||||
verse_list = []
|
||||
if not xml.startswith(u'<?xml') and not xml.startswith(u'<song'):
|
||||
# This is an old style song, without XML. Let's handle it correctly
|
||||
# by iterating through the verses, and then recreating the internal
|
||||
# xml object as well.
|
||||
# This is an old style song, without XML. Let's handle it correctly by iterating through the verses, and
|
||||
# then recreating the internal xml object as well.
|
||||
self.song_xml = objectify.fromstring(u'<song version="1.0" />')
|
||||
self.lyrics = etree.SubElement(self.song_xml, u'lyrics')
|
||||
verses = xml.split(u'\n\n')
|
||||
|
@ -176,11 +170,10 @@ class SongXML(object):
|
|||
|
||||
class OpenLyrics(object):
|
||||
"""
|
||||
This class represents the converter for OpenLyrics XML (version 0.8)
|
||||
to/from a song.
|
||||
This class represents the converter for OpenLyrics XML (version 0.8) to/from a song.
|
||||
|
||||
As OpenLyrics has a rich set of different features, we cannot support them
|
||||
all. The following features are supported by the :class:`OpenLyrics` class:
|
||||
As OpenLyrics has a rich set of different features, we cannot support them all. The following features are
|
||||
supported by the :class:`OpenLyrics` class:
|
||||
|
||||
``<authors>``
|
||||
OpenLP does not support the attribute *type* and *lang*.
|
||||
|
@ -189,8 +182,7 @@ class OpenLyrics(object):
|
|||
This property is not supported.
|
||||
|
||||
``<comments>``
|
||||
The ``<comments>`` property is fully supported. But comments in lyrics
|
||||
are not supported.
|
||||
The ``<comments>`` property is fully supported. But comments in lyrics are not supported.
|
||||
|
||||
``<copyright>``
|
||||
This property is fully supported.
|
||||
|
@ -208,23 +200,20 @@ class OpenLyrics(object):
|
|||
This property is not supported.
|
||||
|
||||
``<lines>``
|
||||
The attribute *part* is not supported. The *break* attribute is
|
||||
supported.
|
||||
The attribute *part* is not supported. The *break* attribute is supported.
|
||||
|
||||
``<publisher>``
|
||||
This property is not supported.
|
||||
|
||||
``<songbooks>``
|
||||
As OpenLP does only support one songbook, we cannot consider more than
|
||||
one songbook.
|
||||
As OpenLP does only support one songbook, we cannot consider more than one songbook.
|
||||
|
||||
``<tempo>``
|
||||
This property is not supported.
|
||||
|
||||
``<themes>``
|
||||
Topics, as they are called in OpenLP, are fully supported, whereby only
|
||||
the topic text (e. g. Grace) is considered, but neither the *id* nor
|
||||
*lang*.
|
||||
Topics, as they are called in OpenLP, are fully supported, whereby only the topic text (e. g. Grace) is
|
||||
considered, but neither the *id* nor *lang*.
|
||||
|
||||
``<transposition>``
|
||||
This property is not supported.
|
||||
|
@ -233,9 +222,8 @@ class OpenLyrics(object):
|
|||
This property is not supported.
|
||||
|
||||
``<verse name="v1a" lang="he" translit="en">``
|
||||
The attribute *translit* is not supported. Note, the attribute *lang* is
|
||||
considered, but there is not further functionality implemented yet. The
|
||||
following verse "types" are supported by OpenLP:
|
||||
The attribute *translit* is not supported. Note, the attribute *lang* is considered, but there is not further
|
||||
functionality implemented yet. The following verse "types" are supported by OpenLP:
|
||||
|
||||
* v
|
||||
* c
|
||||
|
@ -245,13 +233,10 @@ class OpenLyrics(object):
|
|||
* e
|
||||
* o
|
||||
|
||||
The verse "types" stand for *Verse*, *Chorus*, *Bridge*, *Pre-Chorus*,
|
||||
*Intro*, *Ending* and *Other*. Any numeric value is allowed after the
|
||||
verse type. The complete verse name in OpenLP always consists of the
|
||||
verse type and the verse number. If not number is present *1* is
|
||||
assumed.
|
||||
OpenLP will merge verses which are split up by appending a letter to the
|
||||
verse name, such as *v1a*.
|
||||
The verse "types" stand for *Verse*, *Chorus*, *Bridge*, *Pre-Chorus*, *Intro*, *Ending* and *Other*. Any
|
||||
numeric value is allowed after the verse type. The complete verse name in OpenLP always consists of the verse
|
||||
type and the verse number. If not number is present *1* is assumed. OpenLP will merge verses which are split
|
||||
up by appending a letter to the verse name, such as *v1a*.
|
||||
|
||||
``<verseOrder>``
|
||||
OpenLP supports this property.
|
||||
|
@ -359,17 +344,14 @@ class OpenLyrics(object):
|
|||
|
||||
def _get_missing_tags(self, text):
|
||||
"""
|
||||
Tests the given text for not closed formatting tags and returns a tuple
|
||||
consisting of two unicode strings::
|
||||
Tests the given text for not closed formatting tags and returns a tuple consisting of two unicode strings::
|
||||
|
||||
(u'{st}{r}', u'{/r}{/st}')
|
||||
|
||||
The first unicode string are the start tags (for the next slide). The
|
||||
second unicode string are the end tags.
|
||||
The first unicode string are the start tags (for the next slide). The second unicode string are the end tags.
|
||||
|
||||
``text``
|
||||
The text to test. The text must **not** contain html tags, only
|
||||
OpenLP formatting tags are allowed::
|
||||
The text to test. The text must **not** contain html tags, only OpenLP formatting tags are allowed::
|
||||
|
||||
{st}{r}Text text text
|
||||
"""
|
||||
|
@ -379,9 +361,8 @@ class OpenLyrics(object):
|
|||
continue
|
||||
if text.count(tag[u'start tag']) != text.count(tag[u'end tag']):
|
||||
tags.append((text.find(tag[u'start tag']), tag[u'start tag'], tag[u'end tag']))
|
||||
# Sort the lists, so that the tags which were opened first on the first
|
||||
# slide (the text we are checking) will be opened first on the next
|
||||
# slide as well.
|
||||
# Sort the lists, so that the tags which were opened first on the first slide (the text we are checking) will
|
||||
# be opened first on the next slide as well.
|
||||
tags.sort(key=lambda tag: tag[0])
|
||||
end_tags = []
|
||||
start_tags = []
|
||||
|
@ -393,16 +374,15 @@ class OpenLyrics(object):
|
|||
|
||||
def xml_to_song(self, xml, parse_and_temporary_save=False):
|
||||
"""
|
||||
Create and save a song from OpenLyrics format xml to the database. Since
|
||||
we also export XML from external sources (e. g. OpenLyrics import), we
|
||||
cannot ensure, that it completely conforms to the OpenLyrics standard.
|
||||
Create and save a song from OpenLyrics format xml to the database. Since we also export XML from external
|
||||
sources (e. g. OpenLyrics import), we cannot ensure, that it completely conforms to the OpenLyrics standard.
|
||||
|
||||
``xml``
|
||||
The XML to parse (unicode).
|
||||
|
||||
``parse_and_temporary_save``
|
||||
Switch to skip processing the whole song and storing the songs in
|
||||
the database with a temporary flag. Defaults to ``False``.
|
||||
Switch to skip processing the whole song and storing the songs in the database with a temporary flag.
|
||||
Defaults to ``False``.
|
||||
"""
|
||||
# No xml get out of here.
|
||||
if not xml:
|
||||
|
@ -448,8 +428,7 @@ class OpenLyrics(object):
|
|||
|
||||
def _add_tag_to_formatting(self, tag_name, tags_element):
|
||||
"""
|
||||
Add new formatting tag to the element ``<format>`` if the tag is not
|
||||
present yet.
|
||||
Add new formatting tag to the element ``<format>`` if the tag is not present yet.
|
||||
"""
|
||||
available_tags = FormattingTags.get_html_tags()
|
||||
start_tag = '{%s}' % tag_name
|
||||
|
@ -469,8 +448,7 @@ class OpenLyrics(object):
|
|||
|
||||
def _add_text_with_tags_to_lines(self, verse_element, text, tags_element):
|
||||
"""
|
||||
Convert text with formatting tags from OpenLP format to OpenLyrics
|
||||
format and append it to element ``<lines>``.
|
||||
Convert text with formatting tags from OpenLP format to OpenLyrics format and append it to element ``<lines>``.
|
||||
"""
|
||||
start_tags = OpenLyrics.START_TAGS_REGEX.findall(text)
|
||||
end_tags = OpenLyrics.END_TAGS_REGEX.findall(text)
|
||||
|
@ -478,8 +456,7 @@ class OpenLyrics(object):
|
|||
for tag in start_tags:
|
||||
# Tags already converted to xml structure.
|
||||
xml_tags = tags_element.xpath(u'tag/attribute::name')
|
||||
# Some formatting tag has only starting part e.g. <br>.
|
||||
# Handle this case.
|
||||
# Some formatting tag has only starting part e.g. <br>. Handle this case.
|
||||
if tag in end_tags:
|
||||
text = text.replace(u'{%s}' % tag, u'<tag name="%s">' % tag)
|
||||
else:
|
||||
|
@ -586,8 +563,8 @@ class OpenLyrics(object):
|
|||
|
||||
def _process_formatting_tags(self, song_xml, temporary):
|
||||
"""
|
||||
Process the formatting tags from the song and either add missing tags
|
||||
temporary or permanently to the formatting tag list.
|
||||
Process the formatting tags from the song and either add missing tags temporary or permanently to the
|
||||
formatting tag list.
|
||||
"""
|
||||
if not hasattr(song_xml, u'format'):
|
||||
return
|
||||
|
@ -608,8 +585,8 @@ class OpenLyrics(object):
|
|||
u'end html': tag.close.text if hasattr(tag, 'close') else u'',
|
||||
u'protected': False,
|
||||
}
|
||||
# Add 'temporary' key in case the formatting tag should not be
|
||||
# saved otherwise it is supposed that formatting tag is permanent.
|
||||
# Add 'temporary' key in case the formatting tag should not be saved otherwise it is supposed that
|
||||
# formatting tag is permanent.
|
||||
if temporary:
|
||||
openlp_tag[u'temporary'] = temporary
|
||||
found_tags.append(openlp_tag)
|
||||
|
@ -620,15 +597,14 @@ class OpenLyrics(object):
|
|||
|
||||
def _process_lines_mixed_content(self, element, newlines=True):
|
||||
"""
|
||||
Converts the xml text with mixed content to OpenLP representation.
|
||||
Chords are skipped and formatting tags are converted.
|
||||
Converts the xml text with mixed content to OpenLP representation. Chords are skipped and formatting tags are
|
||||
converted.
|
||||
|
||||
``element``
|
||||
The property object (lxml.etree.Element).
|
||||
|
||||
``newlines``
|
||||
The switch to enable/disable processing of line breaks <br/>.
|
||||
The <br/> is used since OpenLyrics 0.8.
|
||||
The switch to enable/disable processing of line breaks <br/>. The <br/> is used since OpenLyrics 0.8.
|
||||
"""
|
||||
text = u''
|
||||
use_endtag = True
|
||||
|
@ -684,12 +660,10 @@ class OpenLyrics(object):
|
|||
lines = etree.tostring(lines)
|
||||
element = etree.XML(lines)
|
||||
|
||||
# OpenLyrics 0.8 uses <br/> for new lines.
|
||||
# Append text from "lines" element to verse text.
|
||||
# OpenLyrics 0.8 uses <br/> for new lines. Append text from "lines" element to verse text.
|
||||
if version > '0.7':
|
||||
text = self._process_lines_mixed_content(element)
|
||||
# OpenLyrics version <= 0.7 contais <line> elements to represent lines.
|
||||
# First child element is tested.
|
||||
# OpenLyrics version <= 0.7 contais <line> elements to represent lines. First child element is tested.
|
||||
else:
|
||||
# Loop over the "line" elements removing comments and chords.
|
||||
for line in element:
|
||||
|
@ -742,16 +716,15 @@ class OpenLyrics(object):
|
|||
text += u'\n[---]'
|
||||
verse_def = verse.get(u'name', u' ').lower()
|
||||
verse_tag, verse_number, verse_part = OpenLyrics.VERSE_TAG_SPLITTER.search(verse_def).groups()
|
||||
if verse_tag not in VerseType.Tags:
|
||||
verse_tag = VerseType.Tags[VerseType.Other]
|
||||
# OpenLyrics allows e. g. "c", but we need "c1". However, this does
|
||||
# not correct the verse order.
|
||||
if verse_tag not in VerseType.tags:
|
||||
verse_tag = VerseType.tags[VerseType.Other]
|
||||
# OpenLyrics allows e. g. "c", but we need "c1". However, this does not correct the verse order.
|
||||
if not verse_number:
|
||||
verse_number = u'1'
|
||||
lang = verse.get(u'lang')
|
||||
translit = verse.get(u'translit')
|
||||
# In OpenLP 1.9.6 we used v1a, v1b ... to represent visual slide
|
||||
# breaks. In OpenLyrics 0.7 an attribute has been added.
|
||||
# In OpenLP 1.9.6 we used v1a, v1b ... to represent visual slide breaks. In OpenLyrics 0.7 an attribute has
|
||||
# been added.
|
||||
if song_xml.get(u'modifiedIn') in (u'1.9.6', u'OpenLP 1.9.6') and \
|
||||
song_xml.get(u'version') == u'0.7' and (verse_tag, verse_number, lang, translit) in verses:
|
||||
verses[(verse_tag, verse_number, lang, translit, None)] += u'\n[---]\n' + text
|
||||
|
|
|
@ -32,29 +32,30 @@ from PyQt4 import QtCore, QtGui
|
|||
from openlp.core.lib import translate
|
||||
from openlp.core.lib.ui import create_button_box
|
||||
|
||||
class Ui_SongUsageDeleteDialog(object):
|
||||
def setupUi(self, songUsageDeleteDialog):
|
||||
songUsageDeleteDialog.setObjectName(u'songUsageDeleteDialog')
|
||||
songUsageDeleteDialog.resize(291, 243)
|
||||
self.verticalLayout = QtGui.QVBoxLayout(songUsageDeleteDialog)
|
||||
self.verticalLayout.setSpacing(8)
|
||||
self.verticalLayout.setContentsMargins(8, 8, 8, 8)
|
||||
self.verticalLayout.setObjectName(u'verticalLayout')
|
||||
self.deleteLabel = QtGui.QLabel(songUsageDeleteDialog)
|
||||
self.deleteLabel.setObjectName(u'deleteLabel')
|
||||
self.verticalLayout.addWidget(self.deleteLabel)
|
||||
self.deleteCalendar = QtGui.QCalendarWidget(songUsageDeleteDialog)
|
||||
self.deleteCalendar.setFirstDayOfWeek(QtCore.Qt.Sunday)
|
||||
self.deleteCalendar.setGridVisible(True)
|
||||
self.deleteCalendar.setVerticalHeaderFormat(QtGui.QCalendarWidget.NoVerticalHeader)
|
||||
self.deleteCalendar.setObjectName(u'deleteCalendar')
|
||||
self.verticalLayout.addWidget(self.deleteCalendar)
|
||||
self.button_box = create_button_box(songUsageDeleteDialog, u'button_box', [u'cancel', u'ok'])
|
||||
self.verticalLayout.addWidget(self.button_box)
|
||||
self.retranslateUi(songUsageDeleteDialog)
|
||||
|
||||
def retranslateUi(self, songUsageDeleteDialog):
|
||||
songUsageDeleteDialog.setWindowTitle(translate('SongUsagePlugin.SongUsageDeleteForm', 'Delete Song Usage Data'))
|
||||
self.deleteLabel.setText(
|
||||
class Ui_SongUsageDeleteDialog(object):
|
||||
def setupUi(self, song_usage_delete_dialog):
|
||||
song_usage_delete_dialog.setObjectName(u'song_usage_delete_dialog')
|
||||
song_usage_delete_dialog.resize(291, 243)
|
||||
self.vertical_layout = QtGui.QVBoxLayout(song_usage_delete_dialog)
|
||||
self.vertical_layout.setSpacing(8)
|
||||
self.vertical_layout.setContentsMargins(8, 8, 8, 8)
|
||||
self.vertical_layout.setObjectName(u'vertical_layout')
|
||||
self.delete_label = QtGui.QLabel(song_usage_delete_dialog)
|
||||
self.delete_label.setObjectName(u'delete_label')
|
||||
self.vertical_layout.addWidget(self.delete_label)
|
||||
self.delete_calendar = QtGui.QCalendarWidget(song_usage_delete_dialog)
|
||||
self.delete_calendar.setFirstDayOfWeek(QtCore.Qt.Sunday)
|
||||
self.delete_calendar.setGridVisible(True)
|
||||
self.delete_calendar.setVerticalHeaderFormat(QtGui.QCalendarWidget.NoVerticalHeader)
|
||||
self.delete_calendar.setObjectName(u'delete_calendar')
|
||||
self.vertical_layout.addWidget(self.delete_calendar)
|
||||
self.button_box = create_button_box(song_usage_delete_dialog, u'button_box', [u'cancel', u'ok'])
|
||||
self.vertical_layout.addWidget(self.button_box)
|
||||
self.retranslateUi(song_usage_delete_dialog)
|
||||
|
||||
def retranslateUi(self, song_usage_delete_dialog):
|
||||
song_usage_delete_dialog.setWindowTitle(translate('SongUsagePlugin.SongUsageDeleteForm', 'Delete Song Usage Data'))
|
||||
self.delete_label.setText(
|
||||
translate('SongUsagePlugin.SongUsageDeleteForm', 'Select the date up to which the song usage data '
|
||||
'should be deleted. All data recorded before this date will be permanently deleted.'))
|
||||
|
|
|
@ -45,10 +45,9 @@ class SongUsageDeleteForm(QtGui.QDialog, Ui_SongUsageDeleteDialog):
|
|||
self.manager = manager
|
||||
QtGui.QDialog.__init__(self, parent)
|
||||
self.setupUi(self)
|
||||
QtCore.QObject.connect(self.button_box, QtCore.SIGNAL(u'clicked(QAbstractButton*)'),
|
||||
self.onButtonBoxClicked)
|
||||
self.button_box.clicked.connect(self.on_button_box_clicked)
|
||||
|
||||
def onButtonBoxClicked(self, button):
|
||||
def on_button_box_clicked(self, button):
|
||||
if self.button_box.standardButton(button) == QtGui.QDialogButtonBox.Ok:
|
||||
ret = QtGui.QMessageBox.question(self,
|
||||
translate('SongUsagePlugin.SongUsageDeleteForm', 'Delete Selected Song Usage Events?'),
|
||||
|
@ -56,12 +55,12 @@ class SongUsageDeleteForm(QtGui.QDialog, Ui_SongUsageDeleteDialog):
|
|||
'Are you sure you want to delete selected Song Usage data?'),
|
||||
QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Yes | QtGui.QMessageBox.No), QtGui.QMessageBox.No)
|
||||
if ret == QtGui.QMessageBox.Yes:
|
||||
deleteDate = self.deleteCalendar.selectedDate().toPyDate()
|
||||
self.manager.delete_all_objects(SongUsageItem, SongUsageItem.usagedate <= deleteDate)
|
||||
delete_date = self.delete_calendar.selectedDate().toPyDate()
|
||||
self.manager.delete_all_objects(SongUsageItem, SongUsageItem.usagedate <= delete_date)
|
||||
self.main_window.information_message(
|
||||
translate('SongUsagePlugin.SongUsageDeleteForm', 'Deletion Successful'),
|
||||
translate(
|
||||
'SongUsagePlugin.SongUsageDeleteForm', 'All requested data has been deleted successfully. ')
|
||||
'SongUsagePlugin.SongUsageDeleteForm', 'All requested data has been deleted successfully.')
|
||||
)
|
||||
self.accept()
|
||||
else:
|
||||
|
@ -75,4 +74,4 @@ class SongUsageDeleteForm(QtGui.QDialog, Ui_SongUsageDeleteDialog):
|
|||
self._main_window = Registry().get(u'main_window')
|
||||
return self._main_window
|
||||
|
||||
main_window = property(_get_main_window)
|
||||
main_window = property(_get_main_window)
|
||||
|
|
|
@ -32,56 +32,56 @@ from PyQt4 import QtCore, QtGui
|
|||
from openlp.core.lib import build_icon, translate
|
||||
from openlp.core.lib.ui import create_button_box
|
||||
|
||||
class Ui_SongUsageDetailDialog(object):
|
||||
def setupUi(self, songUsageDetailDialog):
|
||||
songUsageDetailDialog.setObjectName(u'songUsageDetailDialog')
|
||||
songUsageDetailDialog.resize(609, 413)
|
||||
self.verticalLayout = QtGui.QVBoxLayout(songUsageDetailDialog)
|
||||
self.verticalLayout.setSpacing(8)
|
||||
self.verticalLayout.setContentsMargins(8, 8, 8, 8)
|
||||
self.verticalLayout.setObjectName(u'verticalLayout')
|
||||
self.dateRangeGroupBox = QtGui.QGroupBox(songUsageDetailDialog)
|
||||
self.dateRangeGroupBox.setObjectName(u'dateRangeGroupBox')
|
||||
self.dateHorizontalLayout = QtGui.QHBoxLayout(self.dateRangeGroupBox)
|
||||
self.dateHorizontalLayout.setSpacing(8)
|
||||
self.dateHorizontalLayout.setContentsMargins(8, 8, 8, 8)
|
||||
self.dateHorizontalLayout.setObjectName(u'dateHorizontalLayout')
|
||||
self.fromDate = QtGui.QCalendarWidget(self.dateRangeGroupBox)
|
||||
self.fromDate.setObjectName(u'fromDate')
|
||||
self.dateHorizontalLayout.addWidget(self.fromDate)
|
||||
self.toLabel = QtGui.QLabel(self.dateRangeGroupBox)
|
||||
self.toLabel.setScaledContents(False)
|
||||
self.toLabel.setAlignment(QtCore.Qt.AlignCenter)
|
||||
self.toLabel.setObjectName(u'toLabel')
|
||||
self.dateHorizontalLayout.addWidget(self.toLabel)
|
||||
self.toDate = QtGui.QCalendarWidget(self.dateRangeGroupBox)
|
||||
self.toDate.setObjectName(u'toDate')
|
||||
self.dateHorizontalLayout.addWidget(self.toDate)
|
||||
self.verticalLayout.addWidget(self.dateRangeGroupBox)
|
||||
self.fileGroupBox = QtGui.QGroupBox(self.dateRangeGroupBox)
|
||||
self.fileGroupBox.setObjectName(u'fileGroupBox')
|
||||
self.fileHorizontalLayout = QtGui.QHBoxLayout(self.fileGroupBox)
|
||||
self.fileHorizontalLayout.setSpacing(8)
|
||||
self.fileHorizontalLayout.setContentsMargins(8, 8, 8, 8)
|
||||
self.fileHorizontalLayout.setObjectName(u'fileHorizontalLayout')
|
||||
self.fileLineEdit = QtGui.QLineEdit(self.fileGroupBox)
|
||||
self.fileLineEdit.setObjectName(u'fileLineEdit')
|
||||
self.fileLineEdit.setReadOnly(True)
|
||||
self.fileHorizontalLayout.addWidget(self.fileLineEdit)
|
||||
self.saveFilePushButton = QtGui.QPushButton(self.fileGroupBox)
|
||||
self.saveFilePushButton.setMaximumWidth(self.saveFilePushButton.size().height())
|
||||
self.saveFilePushButton.setIcon(build_icon(u':/general/general_open.png'))
|
||||
self.saveFilePushButton.setObjectName(u'saveFilePushButton')
|
||||
self.fileHorizontalLayout.addWidget(self.saveFilePushButton)
|
||||
self.verticalLayout.addWidget(self.fileGroupBox)
|
||||
self.button_box = create_button_box(songUsageDetailDialog, u'button_box', [u'cancel', u'ok'])
|
||||
self.verticalLayout.addWidget(self.button_box)
|
||||
self.retranslateUi(songUsageDetailDialog)
|
||||
QtCore.QObject.connect(self.saveFilePushButton, QtCore.SIGNAL(u'clicked()'),
|
||||
songUsageDetailDialog.defineOutputLocation)
|
||||
|
||||
def retranslateUi(self, songUsageDetailDialog):
|
||||
songUsageDetailDialog.setWindowTitle(translate('SongUsagePlugin.SongUsageDetailForm', 'Song Usage Extraction'))
|
||||
self.dateRangeGroupBox.setTitle(translate('SongUsagePlugin.SongUsageDetailForm', 'Select Date Range'))
|
||||
self.toLabel.setText(translate('SongUsagePlugin.SongUsageDetailForm', 'to'))
|
||||
self.fileGroupBox.setTitle(translate('SongUsagePlugin.SongUsageDetailForm', 'Report Location'))
|
||||
class Ui_SongUsageDetailDialog(object):
|
||||
def setupUi(self, song_usage_detail_dialog):
|
||||
song_usage_detail_dialog.setObjectName(u'song_usage_detail_dialog')
|
||||
song_usage_detail_dialog.resize(609, 413)
|
||||
self.vertical_layout = QtGui.QVBoxLayout(song_usage_detail_dialog)
|
||||
self.vertical_layout.setSpacing(8)
|
||||
self.vertical_layout.setContentsMargins(8, 8, 8, 8)
|
||||
self.vertical_layout.setObjectName(u'vertical_layout')
|
||||
self.date_range_group_box = QtGui.QGroupBox(song_usage_detail_dialog)
|
||||
self.date_range_group_box.setObjectName(u'date_range_group_box')
|
||||
self.date_horizontal_layout = QtGui.QHBoxLayout(self.date_range_group_box)
|
||||
self.date_horizontal_layout.setSpacing(8)
|
||||
self.date_horizontal_layout.setContentsMargins(8, 8, 8, 8)
|
||||
self.date_horizontal_layout.setObjectName(u'date_horizontal_layout')
|
||||
self.from_date_calendar = QtGui.QCalendarWidget(self.date_range_group_box)
|
||||
self.from_date_calendar.setObjectName(u'from_date_calendar')
|
||||
self.date_horizontal_layout.addWidget(self.from_date_calendar)
|
||||
self.to_label = QtGui.QLabel(self.date_range_group_box)
|
||||
self.to_label.setScaledContents(False)
|
||||
self.to_label.setAlignment(QtCore.Qt.AlignCenter)
|
||||
self.to_label.setObjectName(u'to_label')
|
||||
self.date_horizontal_layout.addWidget(self.to_label)
|
||||
self.to_date_calendar = QtGui.QCalendarWidget(self.date_range_group_box)
|
||||
self.to_date_calendar.setObjectName(u'to_date_calendar')
|
||||
self.date_horizontal_layout.addWidget(self.to_date_calendar)
|
||||
self.vertical_layout.addWidget(self.date_range_group_box)
|
||||
self.file_group_box = QtGui.QGroupBox(self.date_range_group_box)
|
||||
self.file_group_box.setObjectName(u'file_group_box')
|
||||
self.file_horizontal_layout = QtGui.QHBoxLayout(self.file_group_box)
|
||||
self.file_horizontal_layout.setSpacing(8)
|
||||
self.file_horizontal_layout.setContentsMargins(8, 8, 8, 8)
|
||||
self.file_horizontal_layout.setObjectName(u'file_horizontal_layout')
|
||||
self.file_line_edit = QtGui.QLineEdit(self.file_group_box)
|
||||
self.file_line_edit.setObjectName(u'file_line_edit')
|
||||
self.file_line_edit.setReadOnly(True)
|
||||
self.file_horizontal_layout.addWidget(self.file_line_edit)
|
||||
self.save_file_push_button = QtGui.QPushButton(self.file_group_box)
|
||||
self.save_file_push_button.setMaximumWidth(self.save_file_push_button.size().height())
|
||||
self.save_file_push_button.setIcon(build_icon(u':/general/general_open.png'))
|
||||
self.save_file_push_button.setObjectName(u'save_file_push_button')
|
||||
self.file_horizontal_layout.addWidget(self.save_file_push_button)
|
||||
self.vertical_layout.addWidget(self.file_group_box)
|
||||
self.button_box = create_button_box(song_usage_detail_dialog, u'button_box', [u'cancel', u'ok'])
|
||||
self.vertical_layout.addWidget(self.button_box)
|
||||
self.retranslateUi(song_usage_detail_dialog)
|
||||
self.save_file_push_button.clicked.connect(song_usage_detail_dialog.define_output_location)
|
||||
|
||||
def retranslateUi(self, song_usage_detail_dialog):
|
||||
song_usage_detail_dialog.setWindowTitle(translate('SongUsagePlugin.SongUsageDetailForm', 'Song Usage Extraction'))
|
||||
self.date_range_group_box.setTitle(translate('SongUsagePlugin.SongUsageDetailForm', 'Select Date Range'))
|
||||
self.to_label.setText(translate('SongUsagePlugin.SongUsageDetailForm', 'to'))
|
||||
self.file_group_box.setTitle(translate('SongUsagePlugin.SongUsageDetailForm', 'Report Location'))
|
||||
|
|
|
@ -39,6 +39,7 @@ from songusagedetaildialog import Ui_SongUsageDetailDialog
|
|||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class SongUsageDetailForm(QtGui.QDialog, Ui_SongUsageDetailDialog):
|
||||
"""
|
||||
Class documentation goes here.
|
||||
|
@ -57,13 +58,11 @@ class SongUsageDetailForm(QtGui.QDialog, Ui_SongUsageDetailDialog):
|
|||
"""
|
||||
We need to set up the screen
|
||||
"""
|
||||
toDate = Settings().value(self.plugin.settingsSection + u'/to date')
|
||||
fromDate = Settings().value(self.plugin.settingsSection + u'/from date')
|
||||
self.fromDate.setSelectedDate(fromDate)
|
||||
self.toDate.setSelectedDate(toDate)
|
||||
self.fileLineEdit.setText(Settings().value(self.plugin.settingsSection + u'/last directory export'))
|
||||
self.from_date_calendar.setSelectedDate(Settings().value(self.plugin.settingsSection + u'/from date'))
|
||||
self.to_date_calendar.setSelectedDate(Settings().value(self.plugin.settingsSection + u'/to date'))
|
||||
self.file_line_edit.setText(Settings().value(self.plugin.settingsSection + u'/last directory export'))
|
||||
|
||||
def defineOutputLocation(self):
|
||||
def define_output_location(self):
|
||||
"""
|
||||
Triggered when the Directory selection button is clicked
|
||||
"""
|
||||
|
@ -72,14 +71,14 @@ class SongUsageDetailForm(QtGui.QDialog, Ui_SongUsageDetailDialog):
|
|||
Settings().value(self.plugin.settingsSection + u'/last directory export'))
|
||||
if path:
|
||||
Settings().setValue(self.plugin.settingsSection + u'/last directory export', path)
|
||||
self.fileLineEdit.setText(path)
|
||||
self.file_line_edit.setText(path)
|
||||
|
||||
def accept(self):
|
||||
"""
|
||||
Ok was triggered so lets save the data and run the report
|
||||
"""
|
||||
log.debug(u'accept')
|
||||
path = self.fileLineEdit.text()
|
||||
path = self.file_line_edit.text()
|
||||
if not path:
|
||||
self.main_window.error_message(
|
||||
translate('SongUsagePlugin.SongUsageDetailForm', 'Output Path Not Selected'),
|
||||
|
@ -88,36 +87,36 @@ class SongUsageDetailForm(QtGui.QDialog, Ui_SongUsageDetailDialog):
|
|||
)
|
||||
return
|
||||
check_directory_exists(path)
|
||||
filename = translate('SongUsagePlugin.SongUsageDetailForm', 'usage_detail_%s_%s.txt') % (
|
||||
self.fromDate.selectedDate().toString(u'ddMMyyyy'),
|
||||
self.toDate.selectedDate().toString(u'ddMMyyyy'))
|
||||
Settings().setValue(u'songusage/from date', self.fromDate.selectedDate())
|
||||
Settings().setValue(u'songusage/to date', self.toDate.selectedDate())
|
||||
file_name = translate('SongUsagePlugin.SongUsageDetailForm', 'usage_detail_%s_%s.txt') % (
|
||||
self.from_date_calendar.selectedDate().toString(u'ddMMyyyy'),
|
||||
self.to_date_calendar.selectedDate().toString(u'ddMMyyyy'))
|
||||
Settings().setValue(self.plugin.settingsSection + u'/from date', self.from_date_calendar.selectedDate())
|
||||
Settings().setValue(self.plugin.settingsSection + u'/to date', self.to_date_calendar.selectedDate())
|
||||
usage = self.plugin.manager.get_all_objects(
|
||||
SongUsageItem, and_(
|
||||
SongUsageItem.usagedate >= self.fromDate.selectedDate().toPyDate(),
|
||||
SongUsageItem.usagedate < self.toDate.selectedDate().toPyDate()),
|
||||
SongUsageItem.usagedate >= self.from_date_calendar.selectedDate().toPyDate(),
|
||||
SongUsageItem.usagedate < self.to_date_calendar.selectedDate().toPyDate()),
|
||||
[SongUsageItem.usagedate, SongUsageItem.usagetime])
|
||||
outname = os.path.join(path, filename)
|
||||
fileHandle = None
|
||||
report_file_name = os.path.join(path, file_name)
|
||||
file_handle = None
|
||||
try:
|
||||
fileHandle = open(outname, u'w')
|
||||
file_handle = open(report_file_name, u'w')
|
||||
for instance in usage:
|
||||
record = u'\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",' \
|
||||
u'\"%s\",\"%s\"\n' % (instance.usagedate,
|
||||
instance.usagetime, instance.title, instance.copyright,
|
||||
instance.ccl_number, instance.authors, instance.plugin_name, instance.source)
|
||||
fileHandle.write(record.encode(u'utf-8'))
|
||||
file_handle.write(record.encode(u'utf-8'))
|
||||
self.main_window.information_message(
|
||||
translate('SongUsagePlugin.SongUsageDetailForm', 'Report Creation'),
|
||||
translate('SongUsagePlugin.SongUsageDetailForm', 'Report \n%s \n'
|
||||
'has been successfully created. ') % outname
|
||||
'has been successfully created. ') % report_file_name
|
||||
)
|
||||
except IOError:
|
||||
log.exception(u'Failed to write out song usage records')
|
||||
finally:
|
||||
if fileHandle:
|
||||
fileHandle.close()
|
||||
if file_handle:
|
||||
file_handle.close()
|
||||
self.close()
|
||||
|
||||
def _get_main_window(self):
|
||||
|
@ -128,4 +127,4 @@ class SongUsageDetailForm(QtGui.QDialog, Ui_SongUsageDetailDialog):
|
|||
self._main_window = Registry().get(u'main_window')
|
||||
return self._main_window
|
||||
|
||||
main_window = property(_get_main_window)
|
||||
main_window = property(_get_main_window)
|
||||
|
|
|
@ -42,7 +42,6 @@ from openlp.plugins.songusage.lib.db import init_schema, SongUsageItem
|
|||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
YEAR = QtCore.QDate().currentDate().year()
|
||||
if QtCore.QDate().currentDate().month() < 9:
|
||||
YEAR -= 1
|
||||
|
@ -54,7 +53,7 @@ __default_settings__ = {
|
|||
u'songusage/to date': QtCore.QDate(YEAR, 8, 31),
|
||||
u'songusage/from date': QtCore.QDate(YEAR - 1, 9, 1),
|
||||
u'songusage/last directory export': u''
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class SongUsagePlugin(Plugin):
|
||||
|
@ -67,7 +66,7 @@ class SongUsagePlugin(Plugin):
|
|||
self.icon = build_icon(u':/plugins/plugin_songusage.png')
|
||||
self.activeIcon = build_icon(u':/songusage/song_usage_active.png')
|
||||
self.inactiveIcon = build_icon(u':/songusage/song_usage_inactive.png')
|
||||
self.songUsageActive = False
|
||||
self.song_usage_active = False
|
||||
|
||||
def checkPreConditions(self):
|
||||
return self.manager.session is not None
|
||||
|
@ -83,59 +82,59 @@ class SongUsagePlugin(Plugin):
|
|||
"""
|
||||
log.info(u'add tools menu')
|
||||
self.toolsMenu = tools_menu
|
||||
self.songUsageMenu = QtGui.QMenu(tools_menu)
|
||||
self.songUsageMenu.setObjectName(u'songUsageMenu')
|
||||
self.songUsageMenu.setTitle(translate('SongUsagePlugin', '&Song Usage Tracking'))
|
||||
self.song_usage_menu = QtGui.QMenu(tools_menu)
|
||||
self.song_usage_menu.setObjectName(u'song_usage_menu')
|
||||
self.song_usage_menu.setTitle(translate('SongUsagePlugin', '&Song Usage Tracking'))
|
||||
# SongUsage Delete
|
||||
self.songUsageDelete = create_action(tools_menu, u'songUsageDelete',
|
||||
self.song_usage_delete = create_action(tools_menu, u'songUsageDelete',
|
||||
text=translate('SongUsagePlugin', '&Delete Tracking Data'),
|
||||
statustip=translate('SongUsagePlugin', 'Delete song usage data up to a specified date.'),
|
||||
triggers=self.onSongUsageDelete)
|
||||
triggers=self.on_song_usage_delete)
|
||||
# SongUsage Report
|
||||
self.songUsageReport = create_action(tools_menu, u'songUsageReport',
|
||||
self.song_usage_report = create_action(tools_menu, u'songUsageReport',
|
||||
text=translate('SongUsagePlugin', '&Extract Tracking Data'),
|
||||
statustip=translate('SongUsagePlugin', 'Generate a report on song usage.'),
|
||||
triggers=self.onSongUsageReport)
|
||||
triggers=self.on_song_usage_report)
|
||||
# SongUsage activation
|
||||
self.songUsageStatus = create_action(tools_menu, u'songUsageStatus',
|
||||
self.song_usage_status = create_action(tools_menu, u'songUsageStatus',
|
||||
text=translate('SongUsagePlugin', 'Toggle Tracking'),
|
||||
statustip=translate('SongUsagePlugin', 'Toggle the tracking of song usage.'), checked=False,
|
||||
shortcuts=[QtCore.Qt.Key_F4], triggers=self.toggleSongUsageState)
|
||||
can_shortcuts=True, triggers=self.toggle_song_usage_state)
|
||||
# Add Menus together
|
||||
self.toolsMenu.addAction(self.songUsageMenu.menuAction())
|
||||
self.songUsageMenu.addAction(self.songUsageStatus)
|
||||
self.songUsageMenu.addSeparator()
|
||||
self.songUsageMenu.addAction(self.songUsageReport)
|
||||
self.songUsageMenu.addAction(self.songUsageDelete)
|
||||
self.songUsageActiveButton = QtGui.QToolButton(self.main_window.statusBar)
|
||||
self.songUsageActiveButton.setCheckable(True)
|
||||
self.songUsageActiveButton.setAutoRaise(True)
|
||||
self.songUsageActiveButton.setStatusTip(translate('SongUsagePlugin', 'Toggle the tracking of song usage.'))
|
||||
self.songUsageActiveButton.setObjectName(u'songUsageActiveButton')
|
||||
self.main_window.statusBar.insertPermanentWidget(1, self.songUsageActiveButton)
|
||||
self.songUsageActiveButton.hide()
|
||||
self.toolsMenu.addAction(self.song_usage_menu.menuAction())
|
||||
self.song_usage_menu.addAction(self.song_usage_status)
|
||||
self.song_usage_menu.addSeparator()
|
||||
self.song_usage_menu.addAction(self.song_usage_report)
|
||||
self.song_usage_menu.addAction(self.song_usage_delete)
|
||||
self.song_usage_active_button = QtGui.QToolButton(self.main_window.statusBar)
|
||||
self.song_usage_active_button.setCheckable(True)
|
||||
self.song_usage_active_button.setAutoRaise(True)
|
||||
self.song_usage_active_button.setStatusTip(translate('SongUsagePlugin', 'Toggle the tracking of song usage.'))
|
||||
self.song_usage_active_button.setObjectName(u'song_usage_active_button')
|
||||
self.main_window.statusBar.insertPermanentWidget(1, self.song_usage_active_button)
|
||||
self.song_usage_active_button.hide()
|
||||
# Signals and slots
|
||||
QtCore.QObject.connect(self.songUsageStatus, QtCore.SIGNAL(u'visibilityChanged(bool)'),
|
||||
self.songUsageStatus.setChecked)
|
||||
QtCore.QObject.connect(self.songUsageActiveButton, QtCore.SIGNAL(u'toggled(bool)'), self.toggleSongUsageState)
|
||||
self.songUsageMenu.menuAction().setVisible(False)
|
||||
QtCore.QObject.connect(self.song_usage_status, QtCore.SIGNAL(u'visibilityChanged(bool)'),
|
||||
self.song_usage_status.setChecked)
|
||||
self.song_usage_active_button.toggled.connect(self.toggle_song_usage_state)
|
||||
self.song_usage_menu.menuAction().setVisible(False)
|
||||
|
||||
def initialise(self):
|
||||
log.info(u'SongUsage Initialising')
|
||||
Plugin.initialise(self)
|
||||
Registry().register_function(u'slidecontroller_live_started', self.display_song_usage)
|
||||
Registry().register_function(u'print_service_started', self.print_song_usage)
|
||||
self.songUsageActive = Settings().value(self.settingsSection + u'/active')
|
||||
self.song_usage_active = Settings().value(self.settingsSection + u'/active')
|
||||
# Set the button and checkbox state
|
||||
self.setButtonState()
|
||||
self.set_button_state()
|
||||
action_list = ActionList.get_instance()
|
||||
action_list.add_action(self.songUsageStatus, translate('SongUsagePlugin', 'Song Usage'))
|
||||
action_list.add_action(self.songUsageDelete, translate('SongUsagePlugin', 'Song Usage'))
|
||||
action_list.add_action(self.songUsageReport, translate('SongUsagePlugin', 'Song Usage'))
|
||||
self.songUsageDeleteForm = SongUsageDeleteForm(self.manager, self.main_window)
|
||||
self.songUsageDetailForm = SongUsageDetailForm(self, self.main_window)
|
||||
self.songUsageMenu.menuAction().setVisible(True)
|
||||
self.songUsageActiveButton.show()
|
||||
action_list.add_action(self.song_usage_status, translate('SongUsagePlugin', 'Song Usage'))
|
||||
action_list.add_action(self.song_usage_delete, translate('SongUsagePlugin', 'Song Usage'))
|
||||
action_list.add_action(self.song_usage_report, translate('SongUsagePlugin', 'Song Usage'))
|
||||
self.song_usage_delete_form = SongUsageDeleteForm(self.manager, self.main_window)
|
||||
self.song_usage_detail_form = SongUsageDetailForm(self, self.main_window)
|
||||
self.song_usage_menu.menuAction().setVisible(True)
|
||||
self.song_usage_active_button.show()
|
||||
|
||||
def finalise(self):
|
||||
"""
|
||||
|
@ -144,44 +143,43 @@ class SongUsagePlugin(Plugin):
|
|||
log.info(u'Plugin Finalise')
|
||||
self.manager.finalise()
|
||||
Plugin.finalise(self)
|
||||
self.songUsageMenu.menuAction().setVisible(False)
|
||||
self.song_usage_menu.menuAction().setVisible(False)
|
||||
action_list = ActionList.get_instance()
|
||||
action_list.remove_action(self.songUsageStatus, translate('SongUsagePlugin', 'Song Usage'))
|
||||
action_list.remove_action(self.songUsageDelete, translate('SongUsagePlugin', 'Song Usage'))
|
||||
action_list.remove_action(self.songUsageReport, translate('SongUsagePlugin', 'Song Usage'))
|
||||
self.songUsageActiveButton.hide()
|
||||
action_list.remove_action(self.song_usage_status, translate('SongUsagePlugin', 'Song Usage'))
|
||||
action_list.remove_action(self.song_usage_delete, translate('SongUsagePlugin', 'Song Usage'))
|
||||
action_list.remove_action(self.song_usage_report, translate('SongUsagePlugin', 'Song Usage'))
|
||||
self.song_usage_active_button.hide()
|
||||
# stop any events being processed
|
||||
self.songUsageActive = False
|
||||
self.song_usage_active = False
|
||||
|
||||
def toggleSongUsageState(self):
|
||||
def toggle_song_usage_state(self):
|
||||
"""
|
||||
Manage the state of the audit collection and amend
|
||||
the UI when necessary,
|
||||
"""
|
||||
self.songUsageActive = not self.songUsageActive
|
||||
Settings().setValue(self.settingsSection + u'/active', self.songUsageActive)
|
||||
self.setButtonState()
|
||||
self.song_usage_active = not self.song_usage_active
|
||||
Settings().setValue(self.settingsSection + u'/active', self.song_usage_active)
|
||||
self.set_button_state()
|
||||
|
||||
def setButtonState(self):
|
||||
def set_button_state(self):
|
||||
"""
|
||||
Keep buttons inline. Turn of signals to stop dead loop but we need the
|
||||
button and check box set correctly.
|
||||
"""
|
||||
self.songUsageActiveButton.blockSignals(True)
|
||||
self.songUsageStatus.blockSignals(True)
|
||||
if self.songUsageActive:
|
||||
self.songUsageActiveButton.setIcon(self.activeIcon)
|
||||
self.songUsageStatus.setChecked(True)
|
||||
self.songUsageActiveButton.setChecked(True)
|
||||
self.songUsageActiveButton.setToolTip(translate('SongUsagePlugin', 'Song usage tracking is active.'))
|
||||
self.song_usage_active_button.blockSignals(True)
|
||||
self.song_usage_status.blockSignals(True)
|
||||
if self.song_usage_active:
|
||||
self.song_usage_active_button.setIcon(self.activeIcon)
|
||||
self.song_usage_status.setChecked(True)
|
||||
self.song_usage_active_button.setChecked(True)
|
||||
self.song_usage_active_button.setToolTip(translate('SongUsagePlugin', 'Song usage tracking is active.'))
|
||||
else:
|
||||
self.songUsageActiveButton.setIcon(self.inactiveIcon)
|
||||
self.songUsageStatus.setChecked(False)
|
||||
self.songUsageActiveButton.setChecked(False)
|
||||
self.songUsageActiveButton.setToolTip(translate('SongUsagePlugin', 'Song usage tracking is inactive.'))
|
||||
self.songUsageActiveButton.blockSignals(False)
|
||||
self.songUsageStatus.blockSignals(False)
|
||||
|
||||
self.song_usage_active_button.setIcon(self.inactiveIcon)
|
||||
self.song_usage_status.setChecked(False)
|
||||
self.song_usage_active_button.setChecked(False)
|
||||
self.song_usage_active_button.setToolTip(translate('SongUsagePlugin', 'Song usage tracking is inactive.'))
|
||||
self.song_usage_active_button.blockSignals(False)
|
||||
self.song_usage_status.blockSignals(False)
|
||||
|
||||
def display_song_usage(self, item):
|
||||
"""
|
||||
|
@ -197,7 +195,7 @@ class SongUsagePlugin(Plugin):
|
|||
|
||||
def _add_song_usage(self, source, item):
|
||||
audit = item[0].audit
|
||||
if self.songUsageActive and audit:
|
||||
if self.song_usage_active and audit:
|
||||
song_usage_item = SongUsageItem()
|
||||
song_usage_item.usagedate = datetime.today()
|
||||
song_usage_item.usagetime = datetime.now().time()
|
||||
|
@ -209,12 +207,12 @@ class SongUsagePlugin(Plugin):
|
|||
song_usage_item.source = source
|
||||
self.manager.save_object(song_usage_item)
|
||||
|
||||
def onSongUsageDelete(self):
|
||||
self.songUsageDeleteForm.exec_()
|
||||
def on_song_usage_delete(self):
|
||||
self.song_usage_delete_form.exec_()
|
||||
|
||||
def onSongUsageReport(self):
|
||||
self.songUsageDetailForm.initialise()
|
||||
self.songUsageDetailForm.exec_()
|
||||
def on_song_usage_report(self):
|
||||
self.song_usage_detail_form.initialise()
|
||||
self.song_usage_detail_form.exec_()
|
||||
|
||||
def about(self):
|
||||
about_text = translate('SongUsagePlugin', '<strong>SongUsage Plugin'
|
||||
|
|
|
@ -45,12 +45,12 @@ class TestFormattingTags(TestCase):
|
|||
FormattingTags.load_tags()
|
||||
new_tags_list = FormattingTags.get_html_tags()
|
||||
|
||||
# THEN: Lists should be identically.
|
||||
assert old_tags_list == new_tags_list, u'The formatting tag lists should be identically.'
|
||||
# THEN: Lists should be identical.
|
||||
assert old_tags_list == new_tags_list, u'The formatting tag lists should be identical.'
|
||||
|
||||
def get_html_tags_with_user_tags_test(self):
|
||||
"""
|
||||
Test the FormattingTags class' get_html_tags static method in combination with user tags.
|
||||
FormattingTags class - test the get_html_tags(), add_html_tags() and remove_html_tag() methods.
|
||||
"""
|
||||
with patch(u'openlp.core.lib.translate') as mocked_translate, \
|
||||
patch(u'openlp.core.lib.settings') as mocked_settings, \
|
||||
|
@ -67,12 +67,18 @@ class TestFormattingTags(TestCase):
|
|||
# WHEN: Add our tag and get the tags again.
|
||||
FormattingTags.load_tags()
|
||||
FormattingTags.add_html_tags([TAG])
|
||||
new_tags_list = FormattingTags.get_html_tags()
|
||||
new_tags_list = copy.deepcopy(FormattingTags.get_html_tags())
|
||||
|
||||
# THEN: Lists should not be identically.
|
||||
# THEN: Lists should not be identical.
|
||||
assert old_tags_list != new_tags_list, u'The lists should be different.'
|
||||
|
||||
# THEN: Added tag and last tag should be the same.
|
||||
new_tag = new_tags_list.pop()
|
||||
assert TAG == new_tag, u'Tags should be identically.'
|
||||
assert TAG == new_tag, u'Tags should be identical.'
|
||||
|
||||
# WHEN: Remove the new tag.
|
||||
FormattingTags.remove_html_tag(len(new_tags_list))
|
||||
|
||||
# THEN: The lists should now be identical.
|
||||
assert old_tags_list == FormattingTags.get_html_tags(), u'The lists should be identical.'
|
||||
|
||||
|
|
|
@ -54,5 +54,5 @@ class TestScreenList(TestCase):
|
|||
new_screens = self.screens.screen_list
|
||||
assert len(old_screens) + 1 == len(new_screens), u'The new_screens list should be bigger.'
|
||||
|
||||
# THEN: The screens should be identically.
|
||||
assert SCREEN == new_screens.pop(), u'The new screen should be identically to the screen defined above.'
|
||||
# THEN: The screens should be identical.
|
||||
assert SCREEN == new_screens.pop(), u'The new screen should be identical to the screen defined above.'
|
||||
|
|
|
@ -0,0 +1,93 @@
|
|||
"""
|
||||
Package to test the openlp.core.lib.settings package.
|
||||
"""
|
||||
import os
|
||||
from unittest import TestCase
|
||||
from tempfile import mkstemp
|
||||
|
||||
from openlp.core.lib import Settings
|
||||
|
||||
from PyQt4 import QtGui
|
||||
|
||||
|
||||
class TestSettings(TestCase):
|
||||
|
||||
def setUp(self):
|
||||
"""
|
||||
Create the UI
|
||||
"""
|
||||
fd, self.ini_file = mkstemp(u'.ini')
|
||||
Settings().set_filename(self.ini_file)
|
||||
self.application = QtGui.QApplication.instance()
|
||||
|
||||
def tearDown(self):
|
||||
"""
|
||||
Delete all the C++ objects at the end so that we don't have a segfault
|
||||
"""
|
||||
del self.application
|
||||
os.unlink(self.ini_file)
|
||||
os.unlink(Settings().fileName())
|
||||
|
||||
def settings_basic_test(self):
|
||||
"""
|
||||
Test the Settings creation and its default usage
|
||||
"""
|
||||
# GIVEN: A new Settings setup
|
||||
|
||||
# WHEN reading a setting for the first time
|
||||
default_value = Settings().value(u'general/has run wizard')
|
||||
|
||||
# THEN the default value is returned
|
||||
assert default_value is False, u'The default value should be False'
|
||||
|
||||
# WHEN a new value is saved into config
|
||||
Settings().setValue(u'general/has run wizard', True)
|
||||
|
||||
# THEN the new value is returned when re-read
|
||||
assert Settings().value(u'general/has run wizard') is True, u'The saved value should have been returned'
|
||||
|
||||
def settings_override_test(self):
|
||||
"""
|
||||
Test the Settings creation and its override usage
|
||||
"""
|
||||
# GIVEN: an override for the settings
|
||||
screen_settings = {
|
||||
u'test/extend': u'very wide',
|
||||
}
|
||||
Settings().extend_default_settings(screen_settings)
|
||||
|
||||
# WHEN reading a setting for the first time
|
||||
extend = Settings().value(u'test/extend')
|
||||
|
||||
# THEN the default value is returned
|
||||
assert extend == u'very wide', u'The default value of "very wide" should be returned'
|
||||
|
||||
# WHEN a new value is saved into config
|
||||
Settings().setValue(u'test/extend', u'very short')
|
||||
|
||||
# THEN the new value is returned when re-read
|
||||
assert Settings().value(u'test/extend') == u'very short', u'The saved value should be returned'
|
||||
|
||||
def settings_override_with_group_test(self):
|
||||
"""
|
||||
Test the Settings creation and its override usage - with groups
|
||||
"""
|
||||
# GIVEN: an override for the settings
|
||||
screen_settings = {
|
||||
u'test/extend': u'very wide',
|
||||
}
|
||||
Settings.extend_default_settings(screen_settings)
|
||||
|
||||
# WHEN reading a setting for the first time
|
||||
settings = Settings()
|
||||
settings.beginGroup(u'test')
|
||||
extend = settings.value(u'extend')
|
||||
|
||||
# THEN the default value is returned
|
||||
assert extend == u'very wide', u'The default value defined should be returned'
|
||||
|
||||
# WHEN a new value is saved into config
|
||||
Settings().setValue(u'test/extend', u'very short')
|
||||
|
||||
# THEN the new value is returned when re-read
|
||||
assert Settings().value(u'test/extend') == u'very short', u'The saved value should be returned'
|
|
@ -0,0 +1,124 @@
|
|||
"""
|
||||
Package to test the openlp.core.utils.actions package.
|
||||
"""
|
||||
import os
|
||||
from tempfile import mkstemp
|
||||
from unittest import TestCase
|
||||
|
||||
from PyQt4 import QtGui, QtCore
|
||||
|
||||
from openlp.core.lib import Settings
|
||||
from openlp.core.utils import ActionList
|
||||
|
||||
|
||||
class TestActionList(TestCase):
|
||||
|
||||
def setUp(self):
|
||||
"""
|
||||
Prepare the tests
|
||||
"""
|
||||
self.action_list = ActionList.get_instance()
|
||||
self.settings = Settings()
|
||||
fd, self.ini_file = mkstemp(u'.ini')
|
||||
self.settings.set_filename(self.ini_file)
|
||||
self.settings.beginGroup(u'shortcuts')
|
||||
|
||||
def tearDown(self):
|
||||
"""
|
||||
Clean up
|
||||
"""
|
||||
self.settings.endGroup()
|
||||
os.unlink(self.ini_file)
|
||||
|
||||
def test_add_action_same_parent(self):
|
||||
"""
|
||||
ActionList test - Tests the add_action method. The actions have the same parent, the same shortcuts and both
|
||||
have the QtCore.Qt.WindowShortcut shortcut context set.
|
||||
"""
|
||||
# GIVEN: Two actions with the same shortcuts.
|
||||
parent = QtCore.QObject()
|
||||
action1 = QtGui.QAction(parent)
|
||||
action1.setObjectName(u'action1')
|
||||
action_with_same_shortcuts1 = QtGui.QAction(parent)
|
||||
action_with_same_shortcuts1.setObjectName(u'action_with_same_shortcuts1')
|
||||
# Add default shortcuts to Settings class.
|
||||
default_shortcuts = {
|
||||
u'shortcuts/action1': [QtGui.QKeySequence(u'a'), QtGui.QKeySequence(u'b')],
|
||||
u'shortcuts/action_with_same_shortcuts1': [QtGui.QKeySequence(u'b'), QtGui.QKeySequence(u'a')]
|
||||
}
|
||||
Settings.extend_default_settings(default_shortcuts)
|
||||
|
||||
# WHEN: Add the two actions to the action list.
|
||||
self.action_list.add_action(action1, u'example_category')
|
||||
self.action_list.add_action(action_with_same_shortcuts1, u'example_category')
|
||||
# Remove the actions again.
|
||||
self.action_list.remove_action(action1, u'example_category')
|
||||
self.action_list.remove_action(action_with_same_shortcuts1, u'example_category')
|
||||
|
||||
# THEN: As both actions have the same shortcuts, they should be removed from one action.
|
||||
assert len(action1.shortcuts()) == 2, u'The action should have two shortcut assigned.'
|
||||
assert len(action_with_same_shortcuts1.shortcuts()) == 0, u'The action should not have a shortcut assigned.'
|
||||
|
||||
def test_add_action_different_parent(self):
|
||||
"""
|
||||
ActionList test - Tests the add_action method. The actions have the different parent, the same shortcuts and
|
||||
both have the QtCore.Qt.WindowShortcut shortcut context set.
|
||||
"""
|
||||
# GIVEN: Two actions with the same shortcuts.
|
||||
parent = QtCore.QObject()
|
||||
action2 = QtGui.QAction(parent)
|
||||
action2.setObjectName(u'action2')
|
||||
second_parent = QtCore.QObject()
|
||||
action_with_same_shortcuts2 = QtGui.QAction(second_parent)
|
||||
action_with_same_shortcuts2.setObjectName(u'action_with_same_shortcuts2')
|
||||
# Add default shortcuts to Settings class.
|
||||
default_shortcuts = {
|
||||
u'shortcuts/action2': [QtGui.QKeySequence(u'c'), QtGui.QKeySequence(u'd')],
|
||||
u'shortcuts/action_with_same_shortcuts2': [QtGui.QKeySequence(u'd'), QtGui.QKeySequence(u'c')]
|
||||
}
|
||||
Settings.extend_default_settings(default_shortcuts)
|
||||
|
||||
# WHEN: Add the two actions to the action list.
|
||||
self.action_list.add_action(action2, u'example_category')
|
||||
self.action_list.add_action(action_with_same_shortcuts2, u'example_category')
|
||||
# Remove the actions again.
|
||||
self.action_list.remove_action(action2, u'example_category')
|
||||
self.action_list.remove_action(action_with_same_shortcuts2, u'example_category')
|
||||
|
||||
# THEN: As both actions have the same shortcuts, they should be removed from one action.
|
||||
assert len(action2.shortcuts()) == 2, u'The action should have two shortcut assigned.'
|
||||
assert len(action_with_same_shortcuts2.shortcuts()) == 0, u'The action should not have a shortcut assigned.'
|
||||
|
||||
def test_add_action_different_context(self):
|
||||
"""
|
||||
ActionList test - Tests the add_action method. The actions have the different parent, the same shortcuts and
|
||||
both have the QtCore.Qt.WidgetShortcut shortcut context set.
|
||||
"""
|
||||
# GIVEN: Two actions with the same shortcuts.
|
||||
parent = QtCore.QObject()
|
||||
action3 = QtGui.QAction(parent)
|
||||
action3.setObjectName(u'action3')
|
||||
action3.setShortcutContext(QtCore.Qt.WidgetShortcut)
|
||||
second_parent = QtCore.QObject()
|
||||
action_with_same_shortcuts3 = QtGui.QAction(second_parent)
|
||||
action_with_same_shortcuts3.setObjectName(u'action_with_same_shortcuts3')
|
||||
action_with_same_shortcuts3.setShortcutContext(QtCore.Qt.WidgetShortcut)
|
||||
# Add default shortcuts to Settings class.
|
||||
default_shortcuts = {
|
||||
u'shortcuts/action3': [QtGui.QKeySequence(u'e'), QtGui.QKeySequence(u'f')],
|
||||
u'shortcuts/action_with_same_shortcuts3': [QtGui.QKeySequence(u'e'), QtGui.QKeySequence(u'f')]
|
||||
}
|
||||
Settings.extend_default_settings(default_shortcuts)
|
||||
|
||||
# WHEN: Add the two actions to the action list.
|
||||
self.action_list.add_action(action3, u'example_category2')
|
||||
self.action_list.add_action(action_with_same_shortcuts3, u'example_category2')
|
||||
# Remove the actions again.
|
||||
self.action_list.remove_action(action3, u'example_category2')
|
||||
self.action_list.remove_action(action_with_same_shortcuts3, u'example_category2')
|
||||
|
||||
# THEN: Both action should keep their shortcuts.
|
||||
assert len(action3.shortcuts()) == 2, u'The action should have two shortcut assigned.'
|
||||
assert len(action_with_same_shortcuts3.shortcuts()) == 2, u'The action should have two shortcuts assigned.'
|
||||
|
||||
|
|
@ -1,12 +1,17 @@
|
|||
"""
|
||||
Functional tests to test the AppLocation class and related methods.
|
||||
"""
|
||||
import copy
|
||||
from unittest import TestCase
|
||||
|
||||
from mock import patch
|
||||
|
||||
from openlp.core.utils import AppLocation
|
||||
|
||||
|
||||
FILE_LIST = [u'file1', u'file2', u'file3.txt', u'file4.txt', u'file5.mp3', u'file6.mp3']
|
||||
|
||||
|
||||
class TestAppLocation(TestCase):
|
||||
"""
|
||||
A test suite to test out various methods around the AppLocation class.
|
||||
|
@ -15,10 +20,10 @@ class TestAppLocation(TestCase):
|
|||
"""
|
||||
Test the AppLocation.get_data_path() method
|
||||
"""
|
||||
with patch(u'openlp.core.utils.Settings') as mocked_class, \
|
||||
patch(u'openlp.core.utils.AppLocation.get_directory') as mocked_get_directory, \
|
||||
patch(u'openlp.core.utils.check_directory_exists') as mocked_check_directory_exists, \
|
||||
patch(u'openlp.core.utils.os') as mocked_os:
|
||||
with patch(u'openlp.core.utils.applocation.Settings') as mocked_class, \
|
||||
patch(u'openlp.core.utils.AppLocation.get_directory') as mocked_get_directory, \
|
||||
patch(u'openlp.core.utils.applocation.check_directory_exists') as mocked_check_directory_exists, \
|
||||
patch(u'openlp.core.utils.applocation.os') as mocked_os:
|
||||
# GIVEN: A mocked out Settings class and a mocked out AppLocation.get_directory()
|
||||
mocked_settings = mocked_class.return_value
|
||||
mocked_settings.contains.return_value = False
|
||||
|
@ -37,8 +42,8 @@ class TestAppLocation(TestCase):
|
|||
"""
|
||||
Test the AppLocation.get_data_path() method when a custom location is set in the settings
|
||||
"""
|
||||
with patch(u'openlp.core.utils.Settings') as mocked_class,\
|
||||
patch(u'openlp.core.utils.os') as mocked_os:
|
||||
with patch(u'openlp.core.utils.applocation.Settings') as mocked_class,\
|
||||
patch(u'openlp.core.utils.applocation.os') as mocked_os:
|
||||
# GIVEN: A mocked out Settings class which returns a custom data location
|
||||
mocked_settings = mocked_class.return_value
|
||||
mocked_settings.contains.return_value = True
|
||||
|
@ -51,12 +56,44 @@ class TestAppLocation(TestCase):
|
|||
mocked_settings.value.assert_called_with(u'advanced/data path')
|
||||
assert data_path == u'custom/dir', u'Result should be "custom/dir"'
|
||||
|
||||
def get_files_no_section_no_extension_test(self):
|
||||
"""
|
||||
Test the AppLocation.get_files() method with no parameters passed.
|
||||
"""
|
||||
with patch(u'openlp.core.utils.AppLocation.get_data_path') as mocked_get_data_path, \
|
||||
patch(u'openlp.core.utils.applocation.os.listdir') as mocked_listdir:
|
||||
# GIVEN: Our mocked modules/methods.
|
||||
mocked_get_data_path.return_value = u'test/dir'
|
||||
mocked_listdir.return_value = copy.deepcopy(FILE_LIST)
|
||||
|
||||
# When: Get the list of files.
|
||||
result = AppLocation.get_files()
|
||||
|
||||
# Then: check if the file lists are identical.
|
||||
assert result == FILE_LIST, u'The file lists should be identical.'
|
||||
|
||||
def get_files_test(self):
|
||||
"""
|
||||
Test the AppLocation.get_files() method with all parameters passed.
|
||||
"""
|
||||
with patch(u'openlp.core.utils.AppLocation.get_data_path') as mocked_get_data_path, \
|
||||
patch(u'openlp.core.utils.applocation.os.listdir') as mocked_listdir:
|
||||
# GIVEN: Our mocked modules/methods.
|
||||
mocked_get_data_path.return_value = u'test/dir'
|
||||
mocked_listdir.return_value = copy.deepcopy(FILE_LIST)
|
||||
|
||||
# When: Get the list of files.
|
||||
result = AppLocation.get_files(u'section', u'.mp3')
|
||||
|
||||
# Then: check if the file lists are identical.
|
||||
assert result == [u'file5.mp3', u'file6.mp3'], u'The file lists should be identical.'
|
||||
|
||||
def get_section_data_path_test(self):
|
||||
"""
|
||||
Test the AppLocation.get_section_data_path() method
|
||||
"""
|
||||
with patch(u'openlp.core.utils.AppLocation.get_data_path') as mocked_get_data_path, \
|
||||
patch(u'openlp.core.utils.check_directory_exists') as mocked_check_directory_exists:
|
||||
patch(u'openlp.core.utils.applocation.check_directory_exists') as mocked_check_directory_exists:
|
||||
# GIVEN: A mocked out AppLocation.get_data_path()
|
||||
mocked_get_data_path.return_value = u'test/dir'
|
||||
mocked_check_directory_exists.return_value = True
|
||||
|
@ -70,7 +107,7 @@ class TestAppLocation(TestCase):
|
|||
"""
|
||||
Test the AppLocation.get_directory() method for AppLocation.AppDir
|
||||
"""
|
||||
with patch(u'openlp.core.utils._get_frozen_path') as mocked_get_frozen_path:
|
||||
with patch(u'openlp.core.utils.applocation._get_frozen_path') as mocked_get_frozen_path:
|
||||
mocked_get_frozen_path.return_value = u'app/dir'
|
||||
# WHEN: We call AppLocation.get_directory
|
||||
directory = AppLocation.get_directory(AppLocation.AppDir)
|
||||
|
@ -81,10 +118,10 @@ class TestAppLocation(TestCase):
|
|||
"""
|
||||
Test the AppLocation.get_directory() method for AppLocation.PluginsDir
|
||||
"""
|
||||
with patch(u'openlp.core.utils._get_frozen_path') as mocked_get_frozen_path, \
|
||||
patch(u'openlp.core.utils.os.path.abspath') as mocked_abspath, \
|
||||
patch(u'openlp.core.utils.os.path.split') as mocked_split, \
|
||||
patch(u'openlp.core.utils.sys') as mocked_sys:
|
||||
with patch(u'openlp.core.utils.applocation._get_frozen_path') as mocked_get_frozen_path, \
|
||||
patch(u'openlp.core.utils.applocation.os.path.abspath') as mocked_abspath, \
|
||||
patch(u'openlp.core.utils.applocation.os.path.split') as mocked_split, \
|
||||
patch(u'openlp.core.utils.applocation.sys') as mocked_sys:
|
||||
mocked_abspath.return_value = u'plugins/dir'
|
||||
mocked_split.return_value = [u'openlp']
|
||||
mocked_get_frozen_path.return_value = u'plugins/dir'
|
||||
|
|
Loading…
Reference in New Issue