Head + conflicts

This commit is contained in:
Tim Bentley 2013-03-07 18:22:38 +00:00
commit 2464bef944
73 changed files with 2139 additions and 1909 deletions

View File

@ -136,6 +136,8 @@ class OpenLP(QtGui.QApplication):
self.processEvents() self.processEvents()
# start the main app window # start the main app window
self.main_window = MainWindow() self.main_window = MainWindow()
Registry().execute(u'bootstrap_initialise')
Registry().execute(u'bootstrap_post_set_up')
self.main_window.show() self.main_window.show()
if show_splash: if show_splash:
# now kill the splashscreen # now kill the splashscreen
@ -184,10 +186,8 @@ class OpenLP(QtGui.QApplication):
``traceback`` ``traceback``
A traceback object with the details of where the exception occurred. A traceback object with the details of where the exception occurred.
""" """
if not hasattr(self, u'mainWindow'):
log.exception(''.join(format_exception(exctype, value, traceback))) log.exception(''.join(format_exception(exctype, value, traceback)))
return if not hasattr(self, u'exception_form'):
if not hasattr(self, u'exceptionForm'):
self.exception_form = ExceptionForm(self.main_window) self.exception_form = ExceptionForm(self.main_window)
self.exception_form.exceptionTextEdit.setPlainText(''.join(format_exception(exctype, value, traceback))) self.exception_form.exceptionTextEdit.setPlainText(''.join(format_exception(exctype, value, traceback)))
self.set_normal_cursor() self.set_normal_cursor()

View File

@ -393,7 +393,6 @@ from settings import Settings
from listwidgetwithdnd import ListWidgetWithDnD from listwidgetwithdnd import ListWidgetWithDnD
from formattingtags import FormattingTags from formattingtags import FormattingTags
from spelltextedit import SpellTextEdit from spelltextedit import SpellTextEdit
from settingsmanager import SettingsManager
from plugin import PluginStatus, StringContent, Plugin from plugin import PluginStatus, StringContent, Plugin
from pluginmanager import PluginManager from pluginmanager import PluginManager
from settingstab import SettingsTab from settingstab import SettingsTab

View File

@ -127,7 +127,7 @@ sup {
document.getElementById('footer').innerHTML = footertext; document.getElementById('footer').innerHTML = footertext;
} }
function show_text(newtext){ function show_text(new_text){
var match = /-webkit-text-fill-color:[^;\"]+/gi; var match = /-webkit-text-fill-color:[^;\"]+/gi;
if(timer != null) if(timer != null)
clearTimeout(timer); clearTimeout(timer);
@ -142,57 +142,47 @@ sup {
if(outline != null) if(outline != null)
txt = outline; txt = outline;
if(window.getComputedStyle(txt).webkitTextStrokeWidth != '0px'){ if(window.getComputedStyle(txt).webkitTextStrokeWidth != '0px'){
newtext = newtext.replace(/(\s|&nbsp;)+(?![^<]*>)/g, new_text = new_text.replace(/(\s|&nbsp;)+(?![^<]*>)/g,
function(match) { function(match) {
return '</span>' + match + '<span>'; return '</span>' + match + '<span>';
}); });
newtext = '<span>' + newtext + '</span>'; new_text = '<span>' + new_text + '</span>';
} }
} }
text_fade('lyricsmain', newtext); text_fade('lyricsmain', new_text);
text_fade('lyricsoutline', newtext); text_fade('lyricsoutline', new_text);
text_fade('lyricsshadow', newtext.replace(match, '')); text_fade('lyricsshadow', new_text.replace(match, ''));
if(text_opacity() == 1) return;
timer = setTimeout(function(){
show_text(newtext);
}, 100);
} }
function text_fade(id, newtext){ function text_fade(id, new_text){
/* /*
Using -webkit-transition: opacity 1s linear; would have been preferred Show the text.
but it isn't currently quick enough when animating multiple layers of
large areas of large text. Therefore do it manually as best we can.
Hopefully in the future we can revisit and do more interesting
transitions using -webkit-transition and -webkit-transform.
However we need to ensure interrupted transitions (quickly change 2
slides) still looks pretty and is zippy.
*/ */
var text = document.getElementById(id); var text = document.getElementById(id);
if(text == null) return; if(text == null) return;
if(!transition){ if(!transition){
text.innerHTML = newtext; text.innerHTML = new_text;
return; return;
} }
if(newtext == text.innerHTML){ // Fade text out. 0.2 to minimize the time "nothing" is shown on the screen.
text.style.opacity = parseFloat(text.style.opacity) + 0.3; text.style.opacity = '0.2';
if(text.style.opacity > 0.7) // Fade new text in after the old text has finished fading out.
text.style.opacity = 1; timer = window.setTimeout(function(){_show_text(text, new_text)}, 400);
} else {
text.style.opacity = parseFloat(text.style.opacity) - 0.3;
if(text.style.opacity <= 0.1){
text.innerHTML = newtext;
}
}
} }
function text_opacity(){ function _show_text(text, new_text) {
var text = document.getElementById('lyricsmain'); /*
return getComputedStyle(text, '').opacity; Helper function to show the new_text delayed.
*/
text.innerHTML = new_text;
text.style.opacity = '1';
// Wait until the text is completely visible. We want to save the timer id, to be able to call
// clearTimeout(timer) when the text has changed before finishing fading.
timer = window.setTimeout(function(){timer = null;}, 400);
} }
function show_text_complete(){ function show_text_completed(){
return (text_opacity() == 1); return (timer == null);
} }
</script> </script>
</head> </head>
@ -218,7 +208,7 @@ def build_html(item, screen, is_live, background, image=None, plugins=None):
``screen`` ``screen``
Current display information Current display information
``islive`` ``is_live``
Item is going live, rather than preview/theme building Item is going live, rather than preview/theme building
``background`` ``background``
@ -336,6 +326,7 @@ def build_lyrics_css(item, webkit_ver):
.lyricscell { .lyricscell {
display: table-cell; display: table-cell;
word-wrap: break-word; word-wrap: break-word;
-webkit-transition: opacity 0.4s ease;
%s %s
} }
.lyricsmain { .lyricsmain {

View File

@ -229,25 +229,28 @@ class MediaManagerItem(QtGui.QWidget):
create_widget_action(self.listView, separator=True) create_widget_action(self.listView, separator=True)
if self.hasDeleteIcon: if self.hasDeleteIcon:
create_widget_action(self.listView, create_widget_action(self.listView,
u'listView%s%sItem' % (self.plugin.name.title(), StringContent.Delete.title()),
text=self.plugin.getString(StringContent.Delete)[u'title'], text=self.plugin.getString(StringContent.Delete)[u'title'],
icon=u':/general/general_delete.png', 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, separator=True)
create_widget_action(self.listView, create_widget_action(self.listView,
u'listView%s%sItem' % (self.plugin.name.title(), StringContent.Preview.title()),
text=self.plugin.getString(StringContent.Preview)[u'title'], text=self.plugin.getString(StringContent.Preview)[u'title'],
icon=u':/general/general_preview.png', icon=u':/general/general_preview.png',
shortcuts=[QtCore.Qt.Key_Enter, QtCore.Qt.Key_Return], can_shortcuts=True,
triggers=self.onPreviewClick) triggers=self.onPreviewClick)
create_widget_action(self.listView, create_widget_action(self.listView,
u'listView%s%sItem' % (self.plugin.name.title(), StringContent.Live.title()),
text=self.plugin.getString(StringContent.Live)[u'title'], text=self.plugin.getString(StringContent.Live)[u'title'],
icon=u':/general/general_live.png', icon=u':/general/general_live.png',
shortcuts=[QtCore.Qt.ShiftModifier | QtCore.Qt.Key_Enter, can_shortcuts=True,
QtCore.Qt.ShiftModifier | QtCore.Qt.Key_Return],
triggers=self.onLiveClick) triggers=self.onLiveClick)
create_widget_action(self.listView, 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'], text=self.plugin.getString(StringContent.Service)[u'title'],
icon=u':/general/general_add.png', icon=u':/general/general_add.png',
shortcuts=[QtCore.Qt.Key_Plus, QtCore.Qt.Key_Equal],
triggers=self.onAddClick) triggers=self.onAddClick)
if self.addToServiceItem: if self.addToServiceItem:
create_widget_action(self.listView, separator=True) create_widget_action(self.listView, separator=True)

View File

@ -148,7 +148,7 @@ class Plugin(QtCore.QObject):
QtCore.QObject.__init__(self) QtCore.QObject.__init__(self)
self.name = name self.name = name
self.textStrings = {} self.textStrings = {}
self.setPluginTextStrings() self.set_plugin_text_strings()
self.nameStrings = self.textStrings[StringContent.Name] self.nameStrings = self.textStrings[StringContent.Name]
if version: if version:
self.version = version self.version = version
@ -319,7 +319,7 @@ class Plugin(QtCore.QObject):
Settings().setValue(u'%s/%s files' % (self.settingsSection, self.name), loaded_list) Settings().setValue(u'%s/%s files' % (self.settingsSection, self.name), loaded_list)
settings.endGroup() settings.endGroup()
def usesTheme(self, theme): def uses_theme(self, theme):
""" """
Called to find out if a plugin is currently using a theme. Called to find out if a plugin is currently using a theme.
@ -327,7 +327,7 @@ class Plugin(QtCore.QObject):
""" """
return False return False
def renameTheme(self, oldTheme, newTheme): def rename_theme(self, oldTheme, newTheme):
""" """
Renames a theme a plugin is using making the plugin use the new name. Renames a theme a plugin is using making the plugin use the new name.

View File

@ -54,11 +54,37 @@ class PluginManager(object):
""" """
log.info(u'Plugin manager Initialising') log.info(u'Plugin manager Initialising')
Registry().register(u'plugin_manager', self) Registry().register(u'plugin_manager', self)
Registry().register_function(u'bootstrap_initialise', self.bootstrap_initialise)
self.base_path = os.path.abspath(AppLocation.get_directory(AppLocation.PluginsDir)) self.base_path = os.path.abspath(AppLocation.get_directory(AppLocation.PluginsDir))
log.debug(u'Base path %s ', self.base_path) log.debug(u'Base path %s ', self.base_path)
self.plugins = [] self.plugins = []
log.info(u'Plugin manager Initialised') log.info(u'Plugin manager Initialised')
def bootstrap_initialise(self):
"""
Bootstrap all the plugin manager functions
"""
log.info(u'bootstrap_initialise')
self.find_plugins()
# hook methods have to happen after find_plugins. Find plugins needs
# the controllers hence the hooks have moved from setupUI() to here
# Find and insert settings tabs
log.info(u'hook settings')
self.hook_settings_tabs()
# Find and insert media manager items
log.info(u'hook media')
self.hook_media_manager()
# Call the hook method to pull in import menus.
log.info(u'hook menus')
self.hook_import_menu()
# Call the hook method to pull in export menus.
self.hook_export_menu()
# Call the hook method to pull in tools menus.
self.hook_tools_menu()
# Call the initialise method to setup plugins.
log.info(u'initialise plugins')
self.initialise_plugins()
def find_plugins(self): def find_plugins(self):
""" """
Scan a directory for objects inheriting from the ``Plugin`` class. Scan a directory for objects inheriting from the ``Plugin`` class.
@ -118,56 +144,44 @@ class PluginManager(object):
if plugin.status is not PluginStatus.Disabled: if plugin.status is not PluginStatus.Disabled:
plugin.createMediaManagerItem() plugin.createMediaManagerItem()
def hook_settings_tabs(self, settings_form=None): def hook_settings_tabs(self):
""" """
Loop through all the plugins. If a plugin has a valid settings tab Loop through all the plugins. If a plugin has a valid settings tab
item, add it to the settings tab. item, add it to the settings tab.
Tabs are set for all plugins not just Active ones Tabs are set for all plugins not just Active ones
``settings_form``
Defaults to *None*. The settings form to add tabs to.
""" """
for plugin in self.plugins: for plugin in self.plugins:
if plugin.status is not PluginStatus.Disabled: if plugin.status is not PluginStatus.Disabled:
plugin.createSettingsTab(settings_form) plugin.createSettingsTab(self.settings_form)
if settings_form:
settings_form.plugins = self.plugins
def hook_import_menu(self, import_menu): def hook_import_menu(self):
""" """
Loop through all the plugins and give them an opportunity to add an Loop through all the plugins and give them an opportunity to add an
item to the import menu. item to the import menu.
``import_menu``
The Import menu.
""" """
for plugin in self.plugins: for plugin in self.plugins:
if plugin.status is not PluginStatus.Disabled: if plugin.status is not PluginStatus.Disabled:
plugin.addImportMenuItem(import_menu) plugin.addImportMenuItem(self.main_window.file_import_menu)
def hook_export_menu(self, export_menu): def hook_export_menu(self):
""" """
Loop through all the plugins and give them an opportunity to add an Loop through all the plugins and give them an opportunity to add an
item to the export menu. item to the export menu.
``export_menu``
The Export menu.
""" """
for plugin in self.plugins: for plugin in self.plugins:
if plugin.status is not PluginStatus.Disabled: if plugin.status is not PluginStatus.Disabled:
plugin.addExportMenuItem(export_menu) plugin.addExportMenuItem(self.main_window.file_export_menu)
def hook_tools_menu(self, tools_menu): def hook_tools_menu(self):
""" """
Loop through all the plugins and give them an opportunity to add an Loop through all the plugins and give them an opportunity to add an
item to the tools menu. item to the tools menu.
``tools_menu``
The Tools menu.
""" """
for plugin in self.plugins: for plugin in self.plugins:
if plugin.status is not PluginStatus.Disabled: if plugin.status is not PluginStatus.Disabled:
plugin.addToolsMenuItem(tools_menu) plugin.addToolsMenuItem(self.main_window.tools_menu)
def initialise_plugins(self): def initialise_plugins(self):
""" """
@ -211,3 +225,23 @@ class PluginManager(object):
if plugin.isActive(): if plugin.isActive():
plugin.new_service_created() plugin.new_service_created()
def _get_settings_form(self):
"""
Adds the plugin manager to the class dynamically
"""
if not hasattr(self, u'_settings_form'):
self._settings_form = Registry().get(u'settings_form')
return self._settings_form
settings_form = property(_get_settings_form)
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)

View File

@ -247,7 +247,7 @@ class Renderer(object):
serviceItem.footer = footer serviceItem.footer = footer
serviceItem.render(True) serviceItem.render(True)
if not self.force_page: if not self.force_page:
self.display.buildHtml(serviceItem) self.display.build_html(serviceItem)
raw_html = serviceItem.get_rendered_frame(0) raw_html = serviceItem.get_rendered_frame(0)
self.display.text(raw_html, False) self.display.text(raw_html, False)
preview = self.display.preview() preview = self.display.preview()
@ -662,4 +662,3 @@ class Renderer(object):
return self._theme_manager return self._theme_manager
theme_manager = property(_get_theme_manager) theme_manager = property(_get_theme_manager)

View File

@ -152,42 +152,99 @@ class Settings(QtCore.QSettings):
u'SettingsImport/type': u'OpenLP_settings_export', u'SettingsImport/type': u'OpenLP_settings_export',
u'SettingsImport/version': u'', u'SettingsImport/version': u'',
u'shortcuts/aboutItem': [QtGui.QKeySequence(u'Ctrl+F1')], u'shortcuts/aboutItem': [QtGui.QKeySequence(u'Ctrl+F1')],
u'shortcuts/addToService': [],
u'shortcuts/audioPauseItem': [], u'shortcuts/audioPauseItem': [],
u'shortcuts/displayTagItem': [], u'shortcuts/displayTagItem': [],
u'shortcuts/blankScreen': [QtCore.Qt.Key_Period], u'shortcuts/blankScreen': [QtGui.QKeySequence(QtCore.Qt.Key_Period)],
u'shortcuts/collapse': [QtCore.Qt.Key_Minus], u'shortcuts/collapse': [QtGui.QKeySequence(QtCore.Qt.Key_Minus)],
u'shortcuts/desktopScreen': [QtGui.QKeySequence(u'D')], u'shortcuts/desktopScreen': [QtGui.QKeySequence(u'D')],
u'shortcuts/down': [QtCore.Qt.Key_Down], u'shortcuts/delete': [],
u'shortcuts/escapeItem': [QtCore.Qt.Key_Escape], u'shortcuts/down': [QtGui.QKeySequence(QtCore.Qt.Key_Down)],
u'shortcuts/expand': [QtCore.Qt.Key_Plus], 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/exportThemeItem': [],
u'shortcuts/fileNewItem': [QtGui.QKeySequence(u'Ctrl+N')], u'shortcuts/fileNewItem': [QtGui.QKeySequence(u'Ctrl+N')],
u'shortcuts/fileSaveAsItem': [QtGui.QKeySequence(u'Ctrl+Shift+S')], u'shortcuts/fileSaveAsItem': [QtGui.QKeySequence(u'Ctrl+Shift+S')],
u'shortcuts/fileExitItem': [QtGui.QKeySequence(u'Alt+F4')], u'shortcuts/fileExitItem': [QtGui.QKeySequence(u'Alt+F4')],
u'shortcuts/fileSaveItem': [QtGui.QKeySequence(u'Ctrl+S')], u'shortcuts/fileSaveItem': [QtGui.QKeySequence(u'Ctrl+S')],
u'shortcuts/fileOpenItem': [QtGui.QKeySequence(u'Ctrl+O')], u'shortcuts/fileOpenItem': [QtGui.QKeySequence(u'Ctrl+O')],
u'shortcuts/goLive': [],
u'shortcuts/importThemeItem': [], u'shortcuts/importThemeItem': [],
u'shortcuts/importBibleItem': [], 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/modeDefaultItem': [],
u'shortcuts/modeLiveItem': [], u'shortcuts/modeLiveItem': [],
u'shortcuts/make_live': [QtCore.Qt.Key_Enter, QtCore.Qt.Key_Return], u'shortcuts/make_live': [QtGui.QKeySequence(QtCore.Qt.Key_Enter), QtGui.QKeySequence(QtCore.Qt.Key_Return)],
u'shortcuts/moveUp': [QtCore.Qt.Key_PageUp], u'shortcuts/moveUp': [QtGui.QKeySequence(QtCore.Qt.Key_PageUp)],
u'shortcuts/moveTop': [QtCore.Qt.Key_Home], u'shortcuts/moveTop': [QtGui.QKeySequence(QtCore.Qt.Key_Home)],
u'shortcuts/modeSetupItem': [], u'shortcuts/modeSetupItem': [],
u'shortcuts/moveBottom': [QtCore.Qt.Key_End], u'shortcuts/moveBottom': [QtGui.QKeySequence(QtCore.Qt.Key_End)],
u'shortcuts/moveDown': [QtCore.Qt.Key_PageDown], u'shortcuts/moveDown': [QtGui.QKeySequence(QtCore.Qt.Key_PageDown)],
u'shortcuts/nextTrackItem': [], u'shortcuts/nextTrackItem': [],
u'shortcuts/nextItem_live': [QtCore.Qt.Key_Down, QtCore.Qt.Key_PageDown], u'shortcuts/nextItem_live': [QtGui.QKeySequence(QtCore.Qt.Key_Down),
u'shortcuts/nextService': [QtCore.Qt.Key_Right], 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/offlineHelpItem': [],
u'shortcuts/onlineHelpItem': [QtGui.QKeySequence(u'Alt+F1')], 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/playSlidesLoop': [],
u'shortcuts/playSlidesOnce': [], 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/printServiceItem': [QtGui.QKeySequence(u'Ctrl+P')],
u'shortcuts/songExportItem': [], u'shortcuts/songExportItem': [],
u'shortcuts/songUsageStatus': [QtCore.Qt.Key_F4], u'shortcuts/songUsageStatus': [QtGui.QKeySequence(QtCore.Qt.Key_F4)],
u'shortcuts/settingsShortcutsItem': [], u'shortcuts/settingsShortcutsItem': [],
u'shortcuts/settingsImportItem': [], u'shortcuts/settingsImportItem': [],
u'shortcuts/settingsPluginListItem': [QtGui.QKeySequence(u'Alt+F7')], u'shortcuts/settingsPluginListItem': [QtGui.QKeySequence(u'Alt+F7')],
@ -200,17 +257,27 @@ class Settings(QtCore.QSettings):
u'shortcuts/shortcutAction_O': [QtGui.QKeySequence(u'O')], u'shortcuts/shortcutAction_O': [QtGui.QKeySequence(u'O')],
u'shortcuts/shortcutAction_P': [QtGui.QKeySequence(u'P')], u'shortcuts/shortcutAction_P': [QtGui.QKeySequence(u'P')],
u'shortcuts/shortcutAction_V': [QtGui.QKeySequence(u'V')], 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/settingsExportItem': [],
u'shortcuts/songUsageReport': [], u'shortcuts/songUsageReport': [],
u'shortcuts/songImportItem': [], u'shortcuts/songImportItem': [],
u'shortcuts/themeScreen': [QtGui.QKeySequence(u'T')], u'shortcuts/themeScreen': [QtGui.QKeySequence(u'T')],
u'shortcuts/toolsReindexItem': [], u'shortcuts/toolsReindexItem': [],
u'shortcuts/toolsAlertItem': [u'F7'], u'shortcuts/toolsAlertItem': [QtGui.QKeySequence(u'F7')],
u'shortcuts/toolsFirstTimeWizard': [], u'shortcuts/toolsFirstTimeWizard': [],
u'shortcuts/toolsOpenDataFolder': [], u'shortcuts/toolsOpenDataFolder': [],
u'shortcuts/toolsAddToolItem': [], u'shortcuts/toolsAddToolItem': [],
u'shortcuts/updateThemeImages': [], 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/viewThemeManagerItem': [QtGui.QKeySequence(u'F10')],
u'shortcuts/viewMediaManagerItem': [QtGui.QKeySequence(u'F8')], u'shortcuts/viewMediaManagerItem': [QtGui.QKeySequence(u'F8')],
u'shortcuts/viewPreviewPanel': [QtGui.QKeySequence(u'F11')], u'shortcuts/viewPreviewPanel': [QtGui.QKeySequence(u'F11')],
@ -287,6 +354,14 @@ class Settings(QtCore.QSettings):
else: else:
QtCore.QSettings.__init__(self, *args) 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): def remove_obsolete_settings(self):
""" """
This method is only called to clean up the config. It removes old settings and it renames settings. See This method is only called to clean up the config. It removes old settings and it renames settings. See

View File

@ -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

View File

@ -123,7 +123,7 @@ class SettingsTab(QtGui.QWidget):
""" """
self.load() self.load()
def postSetUp(self, postUpdate=False): def post_set_up(self, postUpdate=False):
""" """
Changes which need to be made after setup of application Changes which need to be made after setup of application

View File

@ -69,9 +69,8 @@ def add_welcome_page(parent, image):
def create_button_box(dialog, name, standard_buttons, custom_buttons=None): def create_button_box(dialog, name, standard_buttons, custom_buttons=None):
""" """
Creates a QDialogButtonBox with the given buttons. The ``accepted()`` and Creates a QDialogButtonBox with the given buttons. The ``accepted()`` and ``rejected()`` signals of the button box
``rejected()`` signals of the button box are connected with the dialogs are connected with the dialogs ``accept()`` and ``reject()`` slots.
``accept()`` and ``reject()`` slots.
``dialog`` ``dialog``
The parent object. This has to be a ``QDialog`` descendant. 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. A string which is set as object name.
``standard_buttons`` ``standard_buttons``
A list of strings for the used buttons. It might contain: ``ok``, A list of strings for the used buttons. It might contain: ``ok``, ``save``, ``cancel``, ``close``, and
``save``, ``cancel``, ``close``, and ``defaults``. ``defaults``.
``custom_buttons`` ``custom_buttons``
A list of additional buttons. If a item is a instance of A list of additional buttons. If a item is a instance of QtGui.QAbstractButton it is added with
QtGui.QAbstractButton it is added with QDialogButtonBox.ActionRole. QDialogButtonBox.ActionRole. Otherwhise the item has to be a tuple of a button and a ButtonRole.
Otherwhise the item has to be a tuple of a button and a ButtonRole.
""" """
if custom_buttons is None: if custom_buttons is None:
custom_buttons = [] custom_buttons = []
@ -116,8 +114,7 @@ def create_button_box(dialog, name, standard_buttons, custom_buttons=None):
def critical_error_message_box(title=None, message=None, parent=None, question=False): def critical_error_message_box(title=None, message=None, parent=None, question=False):
""" """
Provides a standard critical message box for errors that OpenLP displays Provides a standard critical message box for errors that OpenLP displays to users.
to users.
``title`` ``title``
The title for the message box. 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: if question:
return QtGui.QMessageBox.critical(parent, UiStrings().Error, message, return QtGui.QMessageBox.critical(parent, UiStrings().Error, message,
QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Yes | QtGui.QMessageBox.No)) 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) 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). A string which is set as object name (required).
``role`` ``role``
A string which can have one value out of ``delete``, ``up``, and A string which can have one value out of ``delete``, ``up``, and ``down``. This decides about default values
``down``. This decides about default values for properties like text, for properties like text, icon, or tooltip.
icon, or tooltip.
``text`` ``text``
A string for the action text. A string for the action text.
``icon`` ``icon``
Either a QIcon, a resource string, or a file location string for the Either a QIcon, a resource string, or a file location string for the action icon.
action icon.
``tooltip`` ``tooltip``
A string for the action tool tip. 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'icon', u':/services/service_down.png')
kwargs.setdefault(u'tooltip', translate('OpenLP.Ui', 'Move selection down one position.')) kwargs.setdefault(u'tooltip', translate('OpenLP.Ui', 'Move selection down one position.'))
else: else:
log.warn(u'The role "%s" is not defined in create_push_button().', log.warn(u'The role "%s" is not defined in create_push_button().', role)
role)
if kwargs.pop(u'class', u'') == u'toolbutton': if kwargs.pop(u'class', u'') == u'toolbutton':
button = QtGui.QToolButton(parent) button = QtGui.QToolButton(parent)
else: else:
@ -256,8 +249,10 @@ def create_action(parent, name, **kwargs):
``data`` ``data``
The action's data. The action's data.
``shortcuts`` ``can_shortcuts``
A QList<QKeySequence> (or a list of strings) which are set as 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`` ``context``
A context for the shortcut execution. A context for the shortcut execution.
@ -289,26 +284,24 @@ def create_action(parent, name, **kwargs):
action.setSeparator(True) action.setSeparator(True)
if u'data' in kwargs: if u'data' in kwargs:
action.setData(kwargs.pop(u'data')) action.setData(kwargs.pop(u'data'))
if kwargs.get(u'shortcuts'): if kwargs.pop(u'can_shortcuts', False):
action.setShortcuts(kwargs.pop(u'shortcuts')) action_list = ActionList.get_instance()
action_list.add_action(action, kwargs.pop(u'category', None))
if u'context' in kwargs: if u'context' in kwargs:
action.setShortcutContext(kwargs.pop(u'context')) 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'): if kwargs.get(u'triggers'):
action.triggered.connect(kwargs.pop(u'triggers')) action.triggered.connect(kwargs.pop(u'triggers'))
for key in kwargs.keys(): 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) log.warn(u'Parameter %s was not consumed in create_action().', key)
return action return action
def create_widget_action(parent, name=u'', **kwargs): def create_widget_action(parent, name=u'', **kwargs):
""" """
Return a new QAction by calling ``create_action(parent, name, **kwargs)``. Return a new QAction by calling ``create_action(parent, name, **kwargs)``. The shortcut context defaults to
The shortcut context defaults to ``QtCore.Qt.WidgetShortcut`` and the action ``QtCore.Qt.WidgetShortcut`` and the action is added to the parents action list.
is added to the parents action list.
""" """
kwargs.setdefault(u'context', QtCore.Qt.WidgetShortcut) kwargs.setdefault(u'context', QtCore.Qt.WidgetShortcut)
action = create_action(parent, name, **kwargs) action = create_action(parent, name, **kwargs)
@ -333,8 +326,7 @@ def set_case_insensitive_completer(cache, widget):
def create_valign_selection_widgets(parent): def create_valign_selection_widgets(parent):
""" """
Creates a standard label and combo box for asking users to select a Creates a standard label and combo box for asking users to select a vertical alignment.
vertical alignment.
``parent`` ``parent``
The parent object. This should be a ``QWidget`` descendant. The parent object. This should be a ``QWidget`` descendant.

View File

@ -308,9 +308,9 @@ class GeneralTab(SettingsTab):
settings.setValue(u'audio repeat list', self.repeatListCheckBox.isChecked()) settings.setValue(u'audio repeat list', self.repeatListCheckBox.isChecked())
settings.endGroup() settings.endGroup()
# On save update the screens as well # On save update the screens as well
self.postSetUp(True) self.post_set_up(True)
def postSetUp(self, postUpdate=False): def post_set_up(self, postUpdate=False):
""" """
Apply settings after settings tab has loaded and most of the Apply settings after settings tab has loaded and most of the
system so must be delayed system so must be delayed

View File

@ -68,7 +68,7 @@ class Display(QtGui.QGraphicsView):
self.parent = lambda: parent self.parent = lambda: parent
else: else:
QtGui.QGraphicsView.__init__(self, parent) QtGui.QGraphicsView.__init__(self, parent)
self.isLive = live self.is_live = live
self.controller = controller self.controller = controller
self.screen = {} self.screen = {}
# FIXME: On Mac OS X (tested on 10.7) the display screen is corrupt with # FIXME: On Mac OS X (tested on 10.7) the display screen is corrupt with
@ -82,40 +82,37 @@ class Display(QtGui.QGraphicsView):
""" """
Set up and build the screen base Set up and build the screen base
""" """
log.debug(u'Start Display base setup (live = %s)' % self.isLive) log.debug(u'Start Display base setup (live = %s)' % self.is_live)
self.setGeometry(self.screen[u'size']) self.setGeometry(self.screen[u'size'])
log.debug(u'Setup webView') log.debug(u'Setup webView')
self.webView = QtWebKit.QWebView(self) self.web_view = QtWebKit.QWebView(self)
self.webView.setGeometry(0, 0, self.screen[u'size'].width(), self.screen[u'size'].height()) self.web_view.setGeometry(0, 0, self.screen[u'size'].width(), self.screen[u'size'].height())
self.webView.settings().setAttribute(QtWebKit.QWebSettings.PluginsEnabled, True) self.web_view.settings().setAttribute(QtWebKit.QWebSettings.PluginsEnabled, True)
palette = self.webView.palette() palette = self.web_view.palette()
palette.setBrush(QtGui.QPalette.Base, QtCore.Qt.transparent) palette.setBrush(QtGui.QPalette.Base, QtCore.Qt.transparent)
self.webView.page().setPalette(palette) self.web_view.page().setPalette(palette)
self.webView.setAttribute(QtCore.Qt.WA_OpaquePaintEvent, False) self.web_view.setAttribute(QtCore.Qt.WA_OpaquePaintEvent, False)
self.page = self.webView.page() self.page = self.web_view.page()
self.frame = self.page.mainFrame() self.frame = self.page.mainFrame()
if self.isLive and log.getEffectiveLevel() == logging.DEBUG: if self.is_live and log.getEffectiveLevel() == logging.DEBUG:
self.webView.settings().setAttribute(QtWebKit.QWebSettings.DeveloperExtrasEnabled, True) self.web_view.settings().setAttribute(QtWebKit.QWebSettings.DeveloperExtrasEnabled, True)
QtCore.QObject.connect(self.webView, self.web_view.loadFinished.connect(self.is_web_loaded)
QtCore.SIGNAL(u'loadFinished(bool)'), self.isWebLoaded)
self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
self.frame.setScrollBarPolicy(QtCore.Qt.Vertical, self.frame.setScrollBarPolicy(QtCore.Qt.Vertical, QtCore.Qt.ScrollBarAlwaysOff)
QtCore.Qt.ScrollBarAlwaysOff) self.frame.setScrollBarPolicy(QtCore.Qt.Horizontal, QtCore.Qt.ScrollBarAlwaysOff)
self.frame.setScrollBarPolicy(QtCore.Qt.Horizontal,
QtCore.Qt.ScrollBarAlwaysOff)
def resizeEvent(self, event): def resizeEvent(self, event):
""" """
React to resizing of this display React to resizing of this display
""" """
self.webView.setGeometry(0, 0, self.width(), self.height()) self.web_view.setGeometry(0, 0, self.width(), self.height())
def isWebLoaded(self): def is_web_loaded(self):
""" """
Called by webView event to show display is fully loaded Called by webView event to show display is fully loaded
""" """
log.debug(u'Webloaded') log.debug(u'is web loaded')
self.webLoaded = True self.webLoaded = True
@ -129,11 +126,11 @@ class MainDisplay(Display):
""" """
Display.__init__(self, parent, live, controller) Display.__init__(self, parent, live, controller)
self.screens = ScreenList() self.screens = ScreenList()
self.rebuildCSS = False self.rebuild_css = False
self.hideMode = None self.hide_mode = None
self.override = {} self.override = {}
self.retranslateUi() self.retranslateUi()
self.mediaObject = None self.media_object = None
if live: if live:
self.audioPlayer = AudioPlayer(self) self.audioPlayer = AudioPlayer(self)
else: else:
@ -156,14 +153,14 @@ class MainDisplay(Display):
self.setWindowState(QtCore.Qt.WindowFullScreen) self.setWindowState(QtCore.Qt.WindowFullScreen)
self.setWindowFlags(windowFlags) self.setWindowFlags(windowFlags)
self.setAttribute(QtCore.Qt.WA_DeleteOnClose) self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
self.setTransparency(False) self.set_transparency(False)
if self.isLive: if self.is_live:
Registry().register_function(u'live_display_hide', self.hide_display) Registry().register_function(u'live_display_hide', self.hide_display)
Registry().register_function(u'live_display_show', self.show_display) Registry().register_function(u'live_display_show', self.show_display)
Registry().register_function(u'update_display_css', self.css_changed) Registry().register_function(u'update_display_css', self.css_changed)
Registry().register_function(u'config_updated', self.config_changed) Registry().register_function(u'config_updated', self.config_changed)
def setTransparency(self, enabled): def set_transparency(self, enabled):
""" """
Set the transparency of the window Set the transparency of the window
""" """
@ -178,17 +175,17 @@ class MainDisplay(Display):
""" """
We may need to rebuild the CSS on the live display. We may need to rebuild the CSS on the live display.
""" """
self.rebuildCSS = True self.rebuild_css = True
def config_changed(self): def config_changed(self):
""" """
Call the plugins to rebuild the Live display CSS as the screen has Call the plugins to rebuild the Live display CSS as the screen has
not been rebuild on exit of config. not been rebuild on exit of config.
""" """
if self.rebuildCSS and self.plugin_manager.plugins: if self.rebuild_css and self.plugin_manager.plugins:
for plugin in self.plugin_manager.plugins: for plugin in self.plugin_manager.plugins:
plugin.refreshCss(self.frame) plugin.refreshCss(self.frame)
self.rebuildCSS = False self.rebuild_css = False
def retranslateUi(self): def retranslateUi(self):
""" """
@ -200,11 +197,11 @@ class MainDisplay(Display):
""" """
Set up and build the output screen Set up and build the output screen
""" """
log.debug(u'Start MainDisplay setup (live = %s)' % self.isLive) log.debug(u'Start MainDisplay setup (live = %s)' % self.is_live)
self.screen = self.screens.current self.screen = self.screens.current
self.setVisible(False) self.setVisible(False)
Display.setup(self) Display.setup(self)
if self.isLive: if self.is_live:
# Build the initial frame. # Build the initial frame.
background_color = QtGui.QColor() background_color = QtGui.QColor()
background_color.setNamedColor(Settings().value(u'advanced/default color')) background_color.setNamedColor(Settings().value(u'advanced/default color'))
@ -225,7 +222,7 @@ class MainDisplay(Display):
splash_image) splash_image)
serviceItem = ServiceItem() serviceItem = ServiceItem()
serviceItem.bg_image_bytes = image_to_byte(self.initialFrame) serviceItem.bg_image_bytes = image_to_byte(self.initialFrame)
self.webView.setHtml(build_html(serviceItem, self.screen, self.isLive, None, self.web_view.setHtml(build_html(serviceItem, self.screen, self.is_live, None,
plugins=self.plugin_manager.plugins)) plugins=self.plugin_manager.plugins))
self.__hideMouse() self.__hideMouse()
log.debug(u'Finished MainDisplay setup') log.debug(u'Finished MainDisplay setup')
@ -288,7 +285,7 @@ class MainDisplay(Display):
self.setVisible(False) self.setVisible(False)
self.setGeometry(self.screen[u'size']) self.setGeometry(self.screen[u'size'])
def directImage(self, path, background): def direct_image(self, path, background):
""" """
API for replacement backgrounds so Images are added directly to cache. API for replacement backgrounds so Images are added directly to cache.
""" """
@ -299,7 +296,7 @@ class MainDisplay(Display):
self.override[u'theme'] = self.serviceItem.themedata.background_filename self.override[u'theme'] = self.serviceItem.themedata.background_filename
self.image(path) self.image(path)
# Update the preview frame. # Update the preview frame.
if self.isLive: if self.is_live:
self.live_controller.updatePreview() self.live_controller.updatePreview()
return True return True
@ -316,9 +313,9 @@ class MainDisplay(Display):
log.debug(u'image to display') log.debug(u'image to display')
image = self.image_manager.get_image_bytes(path, ImageSource.ImagePlugin) image = self.image_manager.get_image_bytes(path, ImageSource.ImagePlugin)
self.controller.media_controller.media_reset(self.controller) self.controller.media_controller.media_reset(self.controller)
self.displayImage(image) self.display_image(image)
def displayImage(self, image): def display_image(self, image):
""" """
Display an image, as is. Display an image, as is.
""" """
@ -329,16 +326,16 @@ class MainDisplay(Display):
js = u'show_image("");' js = u'show_image("");'
self.frame.evaluateJavaScript(js) self.frame.evaluateJavaScript(js)
def resetImage(self): def reset_image(self):
""" """
Reset the backgound image to the service item image. Used after the Reset the background image to the service item image. Used after the
image plugin has changed the background. image plugin has changed the background.
""" """
log.debug(u'resetImage') log.debug(u'reset_image')
if hasattr(self, u'serviceItem'): if hasattr(self, u'serviceItem'):
self.displayImage(self.serviceItem.bg_image_bytes) self.display_image(self.serviceItem.bg_image_bytes)
else: else:
self.displayImage(None) self.display_image(None)
# clear the cache # clear the cache
self.override = {} self.override = {}
@ -346,24 +343,27 @@ class MainDisplay(Display):
""" """
Generates a preview of the image displayed. Generates a preview of the image displayed.
""" """
log.debug(u'preview for %s', self.isLive) log.debug(u'preview for %s', self.is_live)
was_visible = self.isVisible()
self.application.process_events() self.application.process_events()
# We must have a service item to preview. # We must have a service item to preview.
if self.isLive and hasattr(self, u'serviceItem'): if self.is_live and hasattr(self, u'serviceItem'):
# Wait for the fade to finish before geting the preview. # Wait for the fade to finish before geting the preview.
# Important otherwise preview will have incorrect text if at all! # Important otherwise preview will have incorrect text if at all!
if self.serviceItem.themedata and self.serviceItem.themedata.display_slide_transition: if self.serviceItem.themedata and self.serviceItem.themedata.display_slide_transition:
while self.frame.evaluateJavaScript(u'show_text_complete()') == u'false': while not self.frame.evaluateJavaScript(u'show_text_completed()'):
self.application.process_events() self.application.process_events()
# Wait for the webview to update before getting the preview. # Wait for the webview to update before getting the preview.
# Important otherwise first preview will miss the background ! # Important otherwise first preview will miss the background !
while not self.webLoaded: while not self.webLoaded:
self.application.process_events() self.application.process_events()
# if was hidden keep it hidden # if was hidden keep it hidden
if self.isLive: if self.is_live:
if self.hideMode: if self.hide_mode:
self.hide_display(self.hideMode) self.hide_display(self.hide_mode)
else: # Only continue if the visibility wasn't changed during method call.
elif was_visible == self.isVisible():
# Single screen active # Single screen active
if self.screens.display_count == 1: if self.screens.display_count == 1:
# Only make visible if setting enabled. # Only make visible if setting enabled.
@ -373,12 +373,12 @@ class MainDisplay(Display):
self.setVisible(True) self.setVisible(True)
return QtGui.QPixmap.grabWidget(self) return QtGui.QPixmap.grabWidget(self)
def buildHtml(self, serviceItem, image_path=u''): def build_html(self, serviceItem, image_path=u''):
""" """
Store the serviceItem and build the new HTML from it. Add the Store the serviceItem and build the new HTML from it. Add the
HTML to the display HTML to the display
""" """
log.debug(u'buildHtml') log.debug(u'build_html')
self.webLoaded = False self.webLoaded = False
self.initialFrame = None self.initialFrame = None
self.serviceItem = serviceItem self.serviceItem = serviceItem
@ -396,30 +396,29 @@ class MainDisplay(Display):
else: else:
# replace the background # replace the background
background = self.image_manager.get_image_bytes(self.override[u'image'], ImageSource.ImagePlugin) background = self.image_manager.get_image_bytes(self.override[u'image'], ImageSource.ImagePlugin)
self.setTransparency(self.serviceItem.themedata.background_type == self.set_transparency(self.serviceItem.themedata.background_type ==
BackgroundType.to_string(BackgroundType.Transparent)) BackgroundType.to_string(BackgroundType.Transparent))
if self.serviceItem.themedata.background_filename: if self.serviceItem.themedata.background_filename:
self.serviceItem.bg_image_bytes = self.image_manager.get_image_bytes( self.serviceItem.bg_image_bytes = self.image_manager.get_image_bytes(
self.serviceItem.themedata.background_filename, self.serviceItem.themedata.background_filename, ImageSource.Theme
ImageSource.Theme
) )
if image_path: if image_path:
image_bytes = self.image_manager.get_image_bytes(image_path, ImageSource.ImagePlugin) image_bytes = self.image_manager.get_image_bytes(image_path, ImageSource.ImagePlugin)
else: else:
image_bytes = None image_bytes = None
html = build_html(self.serviceItem, self.screen, self.isLive, background, image_bytes, html = build_html(self.serviceItem, self.screen, self.is_live, background, image_bytes,
plugins=self.plugin_manager.plugins) plugins=self.plugin_manager.plugins)
log.debug(u'buildHtml - pre setHtml') log.debug(u'buildHtml - pre setHtml')
self.webView.setHtml(html) self.web_view.setHtml(html)
log.debug(u'buildHtml - post setHtml') log.debug(u'buildHtml - post setHtml')
if serviceItem.foot_text: if serviceItem.foot_text:
self.footer(serviceItem.foot_text) self.footer(serviceItem.foot_text)
# if was hidden keep it hidden # if was hidden keep it hidden
if self.hideMode and self.isLive and not serviceItem.is_media(): if self.hide_mode and self.is_live and not serviceItem.is_media():
if Settings().value(u'general/auto unblank'): if Settings().value(u'general/auto unblank'):
Registry().execute(u'slidecontroller_live_unblank') Registry().execute(u'slidecontroller_live_unblank')
else: else:
self.hide_display(self.hideMode) self.hide_display(self.hide_mode)
self.__hideMouse() self.__hideMouse()
def footer(self, text): def footer(self, text):
@ -450,13 +449,12 @@ class MainDisplay(Display):
if mode != HideMode.Screen: if mode != HideMode.Screen:
if self.isHidden(): if self.isHidden():
self.setVisible(True) self.setVisible(True)
self.webView.setVisible(True) self.web_view.setVisible(True)
self.hideMode = mode self.hide_mode = mode
def show_display(self): def show_display(self):
""" """
Show the stored layers so the screen reappears as it was Show the stored layers so the screen reappears as it was originally.
originally.
Make the stored images None to release memory. Make the stored images None to release memory.
""" """
log.debug(u'show_display') log.debug(u'show_display')
@ -467,9 +465,9 @@ class MainDisplay(Display):
self.frame.evaluateJavaScript('show_blank("show");') self.frame.evaluateJavaScript('show_blank("show");')
if self.isHidden(): if self.isHidden():
self.setVisible(True) self.setVisible(True)
self.hideMode = None self.hide_mode = None
# Trigger actions when display is active again. # Trigger actions when display is active again.
if self.isLive: if self.is_live:
Registry().execute(u'live_display_active') Registry().execute(u'live_display_active')
def __hideMouse(self): def __hideMouse(self):
@ -543,38 +541,38 @@ class AudioPlayer(QtCore.QObject):
self.currentIndex = -1 self.currentIndex = -1
self.playlist = [] self.playlist = []
self.repeat = False self.repeat = False
self.mediaObject = Phonon.MediaObject() self.media_object = Phonon.MediaObject()
self.mediaObject.setTickInterval(100) self.media_object.setTickInterval(100)
self.audioObject = Phonon.AudioOutput(Phonon.VideoCategory) self.audio_object = Phonon.AudioOutput(Phonon.VideoCategory)
Phonon.createPath(self.mediaObject, self.audioObject) Phonon.createPath(self.media_object, self.audio_object)
QtCore.QObject.connect(self.mediaObject, QtCore.SIGNAL(u'aboutToFinish()'), self.onAboutToFinish) self.media_object.aboutToFinish.connect(self.on_about_to_finish)
QtCore.QObject.connect(self.mediaObject, QtCore.SIGNAL(u'finished()'), self.onFinished) self.media_object.finished.connect(self.on_finished)
def __del__(self): def __del__(self):
""" """
Shutting down so clean up connections Shutting down so clean up connections
""" """
self.stop() self.stop()
for path in self.mediaObject.outputPaths(): for path in self.media_object.outputPaths():
path.disconnect() path.disconnect()
def onAboutToFinish(self): def on_about_to_finish(self):
""" """
Just before the audio player finishes the current track, queue the next Just before the audio player finishes the current track, queue the next
item in the playlist, if there is one. item in the playlist, if there is one.
""" """
self.currentIndex += 1 self.currentIndex += 1
if len(self.playlist) > self.currentIndex: if len(self.playlist) > self.currentIndex:
self.mediaObject.enqueue(self.playlist[self.currentIndex]) self.media_object.enqueue(self.playlist[self.currentIndex])
def onFinished(self): def on_finished(self):
""" """
When the audio track finishes. When the audio track finishes.
""" """
if self.repeat: if self.repeat:
log.debug(u'Repeat is enabled... here we go again!') log.debug(u'Repeat is enabled... here we go again!')
self.mediaObject.clearQueue() self.media_object.clearQueue()
self.mediaObject.clear() self.media_object.clear()
self.currentIndex = -1 self.currentIndex = -1
self.play() self.play()
@ -582,7 +580,7 @@ class AudioPlayer(QtCore.QObject):
""" """
Connect the volume slider to the output channel. Connect the volume slider to the output channel.
""" """
slider.setAudioOutput(self.audioObject) slider.setAudioOutput(self.audio_object)
def reset(self): def reset(self):
""" """
@ -591,7 +589,7 @@ class AudioPlayer(QtCore.QObject):
self.currentIndex = -1 self.currentIndex = -1
self.playlist = [] self.playlist = []
self.stop() self.stop()
self.mediaObject.clear() self.media_object.clear()
def play(self): def play(self):
""" """
@ -599,24 +597,24 @@ class AudioPlayer(QtCore.QObject):
""" """
log.debug(u'AudioPlayer.play() called') log.debug(u'AudioPlayer.play() called')
if self.currentIndex == -1: if self.currentIndex == -1:
self.onAboutToFinish() self.on_about_to_finish()
self.mediaObject.play() self.media_object.play()
def pause(self): def pause(self):
""" """
Pause the Audio Pause the Audio
""" """
log.debug(u'AudioPlayer.pause() called') log.debug(u'AudioPlayer.pause() called')
self.mediaObject.pause() self.media_object.pause()
def stop(self): def stop(self):
""" """
Stop the Audio and clean up Stop the Audio and clean up
""" """
log.debug(u'AudioPlayer.stop() called') log.debug(u'AudioPlayer.stop() called')
self.mediaObject.stop() self.media_object.stop()
def addToPlaylist(self, filenames): def add_to_playlist(self, filenames):
""" """
Add another file to the playlist. Add another file to the playlist.
@ -633,31 +631,30 @@ class AudioPlayer(QtCore.QObject):
""" """
if not self.repeat and self.currentIndex + 1 >= len(self.playlist): if not self.repeat and self.currentIndex + 1 >= len(self.playlist):
return return
isPlaying = self.mediaObject.state() == Phonon.PlayingState isPlaying = self.media_object.state() == Phonon.PlayingState
self.currentIndex += 1 self.currentIndex += 1
if self.repeat and self.currentIndex == len(self.playlist): if self.repeat and self.currentIndex == len(self.playlist):
self.currentIndex = 0 self.currentIndex = 0
self.mediaObject.clearQueue() self.media_object.clearQueue()
self.mediaObject.clear() self.media_object.clear()
self.mediaObject.enqueue(self.playlist[self.currentIndex]) self.media_object.enqueue(self.playlist[self.currentIndex])
if isPlaying: if isPlaying:
self.mediaObject.play() self.media_object.play()
def goTo(self, index): def go_to(self, index):
""" """
Go to a particular track in the list Go to a particular track in the list
""" """
isPlaying = self.mediaObject.state() == Phonon.PlayingState isPlaying = self.media_object.state() == Phonon.PlayingState
self.mediaObject.clearQueue() self.media_object.clearQueue()
self.mediaObject.clear() self.media_object.clear()
self.currentIndex = index self.currentIndex = index
self.mediaObject.enqueue(self.playlist[self.currentIndex]) self.media_object.enqueue(self.playlist[self.currentIndex])
if isPlaying: if isPlaying:
self.mediaObject.play() self.media_object.play()
#@todo is this used?
def connectSlot(self, signal, slot): def connectSlot(self, signal, slot):
""" """
Connect a slot to a signal on the media object Connect a slot to a signal on the media object. Used by slidecontroller to connect to audio object.
""" """
QtCore.QObject.connect(self.mediaObject, signal, slot) QtCore.QObject.connect(self.media_object, signal, slot)

View File

@ -105,13 +105,13 @@ class Ui_MainWindow(object):
self.controlSplitter.setObjectName(u'controlSplitter') self.controlSplitter.setObjectName(u'controlSplitter')
self.mainContentLayout.addWidget(self.controlSplitter) self.mainContentLayout.addWidget(self.controlSplitter)
# Create slide controllers # Create slide controllers
self.previewController = SlideController(self) self.preview_controller = SlideController(self)
self.liveController = SlideController(self, True) self.live_controller = SlideController(self, True)
previewVisible = Settings().value(u'user interface/preview panel') previewVisible = Settings().value(u'user interface/preview panel')
self.previewController.panel.setVisible(previewVisible) self.preview_controller.panel.setVisible(previewVisible)
liveVisible = Settings().value(u'user interface/live panel') liveVisible = Settings().value(u'user interface/live panel')
panelLocked = Settings().value(u'user interface/lock panel') panelLocked = Settings().value(u'user interface/lock panel')
self.liveController.panel.setVisible(liveVisible) self.live_controller.panel.setVisible(liveVisible)
# Create menu # Create menu
self.menuBar = QtGui.QMenuBar(main_window) self.menuBar = QtGui.QMenuBar(main_window)
self.menuBar.setObjectName(u'menuBar') self.menuBar.setObjectName(u'menuBar')
@ -119,18 +119,18 @@ class Ui_MainWindow(object):
self.fileMenu.setObjectName(u'fileMenu') self.fileMenu.setObjectName(u'fileMenu')
self.recentFilesMenu = QtGui.QMenu(self.fileMenu) self.recentFilesMenu = QtGui.QMenu(self.fileMenu)
self.recentFilesMenu.setObjectName(u'recentFilesMenu') self.recentFilesMenu.setObjectName(u'recentFilesMenu')
self.fileImportMenu = QtGui.QMenu(self.fileMenu) self.file_import_menu = QtGui.QMenu(self.fileMenu)
self.fileImportMenu.setObjectName(u'fileImportMenu') self.file_import_menu.setObjectName(u'file_import_menu')
self.fileExportMenu = QtGui.QMenu(self.fileMenu) self.file_export_menu = QtGui.QMenu(self.fileMenu)
self.fileExportMenu.setObjectName(u'fileExportMenu') self.file_export_menu.setObjectName(u'file_export_menu')
# View Menu # View Menu
self.viewMenu = QtGui.QMenu(self.menuBar) self.viewMenu = QtGui.QMenu(self.menuBar)
self.viewMenu.setObjectName(u'viewMenu') self.viewMenu.setObjectName(u'viewMenu')
self.viewModeMenu = QtGui.QMenu(self.viewMenu) self.viewModeMenu = QtGui.QMenu(self.viewMenu)
self.viewModeMenu.setObjectName(u'viewModeMenu') self.viewModeMenu.setObjectName(u'viewModeMenu')
# Tools Menu # Tools Menu
self.toolsMenu = QtGui.QMenu(self.menuBar) self.tools_menu = QtGui.QMenu(self.menuBar)
self.toolsMenu.setObjectName(u'toolsMenu') self.tools_menu.setObjectName(u'tools_menu')
# Settings Menu # Settings Menu
self.settingsMenu = QtGui.QMenu(self.menuBar) self.settingsMenu = QtGui.QMenu(self.menuBar)
self.settingsMenu.setObjectName(u'settingsMenu') self.settingsMenu.setObjectName(u'settingsMenu')
@ -174,99 +174,101 @@ class Ui_MainWindow(object):
main_window.addDockWidget(QtCore.Qt.RightDockWidgetArea, self.themeManagerDock) main_window.addDockWidget(QtCore.Qt.RightDockWidgetArea, self.themeManagerDock)
# Create the menu items # Create the menu items
action_list = ActionList.get_instance() 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', self.fileNewItem = create_action(main_window, u'fileNewItem',
icon=u':/general/general_new.png', icon=u':/general/general_new.png',
shortcuts=[QtGui.QKeySequence(u'Ctrl+N')], can_shortcuts=True,
category=UiStrings().File, category=UiStrings().File,
triggers=self.serviceManagerContents.on_new_service_clicked) triggers=self.serviceManagerContents.on_new_service_clicked)
self.fileOpenItem = create_action(main_window, u'fileOpenItem', self.fileOpenItem = create_action(main_window, u'fileOpenItem',
icon=u':/general/general_open.png', icon=u':/general/general_open.png',
shortcuts=[QtGui.QKeySequence(u'Ctrl+O')], can_shortcuts=True,
category=UiStrings().File, category=UiStrings().File,
triggers=self.serviceManagerContents.on_load_service_clicked) triggers=self.serviceManagerContents.on_load_service_clicked)
self.fileSaveItem = create_action(main_window, u'fileSaveItem', self.fileSaveItem = create_action(main_window, u'fileSaveItem',
icon=u':/general/general_save.png', icon=u':/general/general_save.png',
shortcuts=[QtGui.QKeySequence(u'Ctrl+S')], can_shortcuts=True,
category=UiStrings().File, category=UiStrings().File,
triggers=self.serviceManagerContents.save_file) triggers=self.serviceManagerContents.save_file)
self.fileSaveAsItem = create_action(main_window, u'fileSaveAsItem', self.fileSaveAsItem = create_action(main_window, u'fileSaveAsItem',
shortcuts=[QtGui.QKeySequence(u'Ctrl+Shift+S')], can_shortcuts=True,
category=UiStrings().File, category=UiStrings().File,
triggers=self.serviceManagerContents.save_file_as) triggers=self.serviceManagerContents.save_file_as)
self.printServiceOrderItem = create_action(main_window, self.printServiceOrderItem = create_action(main_window,
u'printServiceItem', shortcuts=[QtGui.QKeySequence(u'Ctrl+P')], u'printServiceItem', can_shortcuts=True,
category=UiStrings().File, category=UiStrings().File,
triggers=self.serviceManagerContents.print_service_order) triggers=self.serviceManagerContents.print_service_order)
self.fileExitItem = create_action(main_window, u'fileExitItem', self.fileExitItem = create_action(main_window, u'fileExitItem',
icon=u':/system/system_exit.png', icon=u':/system/system_exit.png',
shortcuts=[QtGui.QKeySequence(u'Alt+F4')], can_shortcuts=True,
category=UiStrings().File, triggers=main_window.close) category=UiStrings().File, triggers=main_window.close)
# Give QT Extra Hint that this is the Exit Menu Item # Give QT Extra Hint that this is the Exit Menu Item
self.fileExitItem.setMenuRole(QtGui.QAction.QuitRole) self.fileExitItem.setMenuRole(QtGui.QAction.QuitRole)
action_list.add_category(UiStrings().Import, CategoryOrder.standardMenu) action_list.add_category(UiStrings().Import, CategoryOrder.standard_menu)
self.importThemeItem = create_action(main_window, u'importThemeItem', category=UiStrings().Import) self.importThemeItem = create_action(
main_window, u'importThemeItem', category=UiStrings().Import, can_shortcuts=True)
self.importLanguageItem = create_action(main_window, u'importLanguageItem') self.importLanguageItem = create_action(main_window, u'importLanguageItem')
action_list.add_category(UiStrings().Export, CategoryOrder.standardMenu) action_list.add_category(UiStrings().Export, CategoryOrder.standard_menu)
self.exportThemeItem = create_action(main_window, u'exportThemeItem', category=UiStrings().Export) self.exportThemeItem = create_action(
main_window, u'exportThemeItem', category=UiStrings().Export, can_shortcuts=True)
self.exportLanguageItem = create_action(main_window, u'exportLanguageItem') 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, self.viewMediaManagerItem = create_action(main_window,
u'viewMediaManagerItem', shortcuts=[QtGui.QKeySequence(u'F8')], u'viewMediaManagerItem',
icon=u':/system/system_mediamanager.png', icon=u':/system/system_mediamanager.png',
checked=self.mediaManagerDock.isVisible(), checked=self.mediaManagerDock.isVisible(),
can_shortcuts=True,
category=UiStrings().View, triggers=self.toggleMediaManager) category=UiStrings().View, triggers=self.toggleMediaManager)
self.viewThemeManagerItem = create_action(main_window, self.viewThemeManagerItem = create_action(main_window,
u'viewThemeManagerItem', shortcuts=[QtGui.QKeySequence(u'F10')], u'viewThemeManagerItem', can_shortcuts=True,
icon=u':/system/system_thememanager.png', icon=u':/system/system_thememanager.png',
checked=self.themeManagerDock.isVisible(), checked=self.themeManagerDock.isVisible(),
category=UiStrings().View, triggers=self.toggleThemeManager) category=UiStrings().View, triggers=self.toggleThemeManager)
self.viewServiceManagerItem = create_action(main_window, self.viewServiceManagerItem = create_action(main_window,
u'viewServiceManagerItem', shortcuts=[QtGui.QKeySequence(u'F9')], u'viewServiceManagerItem', can_shortcuts=True,
icon=u':/system/system_servicemanager.png', icon=u':/system/system_servicemanager.png',
checked=self.serviceManagerDock.isVisible(), checked=self.serviceManagerDock.isVisible(),
category=UiStrings().View, triggers=self.toggleServiceManager) category=UiStrings().View, triggers=self.toggleServiceManager)
self.viewPreviewPanel = create_action(main_window, u'viewPreviewPanel', 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) category=UiStrings().View, triggers=self.setPreviewPanelVisibility)
self.viewLivePanel = create_action(main_window, u'viewLivePanel', 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) category=UiStrings().View, triggers=self.setLivePanelVisibility)
self.lockPanel = create_action(main_window, u'lockPanel', self.lockPanel = create_action(main_window, u'lockPanel',
checked=panelLocked, triggers=self.setLockPanel) can_shortcuts=True, checked=panelLocked,
action_list.add_category(UiStrings().ViewMode, category=UiStrings().View,
CategoryOrder.standardMenu) triggers=self.setLockPanel)
self.modeDefaultItem = create_action(main_window, u'modeDefaultItem', checked=False, action_list.add_category(UiStrings().ViewMode, CategoryOrder.standard_menu)
category=UiStrings().ViewMode) self.modeDefaultItem = create_action(
self.modeSetupItem = create_action(main_window, u'modeSetupItem', checked=False, category=UiStrings().ViewMode) main_window, u'modeDefaultItem', checked=False, category=UiStrings().ViewMode, can_shortcuts=True)
self.modeLiveItem = create_action(main_window, u'modeLiveItem', checked=True, category=UiStrings().ViewMode) 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 = QtGui.QActionGroup(main_window)
self.modeGroup.addAction(self.modeDefaultItem) self.modeGroup.addAction(self.modeDefaultItem)
self.modeGroup.addAction(self.modeSetupItem) self.modeGroup.addAction(self.modeSetupItem)
self.modeGroup.addAction(self.modeLiveItem) self.modeGroup.addAction(self.modeLiveItem)
self.modeDefaultItem.setChecked(True) 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, self.toolsAddToolItem = create_action(main_window,
u'toolsAddToolItem', icon=u':/tools/tools_add.png', u'toolsAddToolItem', icon=u':/tools/tools_add.png', category=UiStrings().Tools, can_shortcuts=True)
category=UiStrings().Tools)
self.toolsOpenDataFolder = create_action(main_window, self.toolsOpenDataFolder = create_action(main_window,
u'toolsOpenDataFolder', icon=u':/general/general_open.png', u'toolsOpenDataFolder', icon=u':/general/general_open.png', category=UiStrings().Tools, can_shortcuts=True)
category=UiStrings().Tools)
self.toolsFirstTimeWizard = create_action(main_window, self.toolsFirstTimeWizard = create_action(main_window,
u'toolsFirstTimeWizard', icon=u':/general/general_revert.png', u'toolsFirstTimeWizard', icon=u':/general/general_revert.png',
category=UiStrings().Tools) category=UiStrings().Tools, can_shortcuts=True)
self.updateThemeImages = create_action(main_window, self.updateThemeImages = create_action(main_window,
u'updateThemeImages', category=UiStrings().Tools) u'updateThemeImages', category=UiStrings().Tools, can_shortcuts=True)
action_list.add_category(UiStrings().Settings, action_list.add_category(UiStrings().Settings, CategoryOrder.standard_menu)
CategoryOrder.standardMenu)
self.settingsPluginListItem = create_action(main_window, self.settingsPluginListItem = create_action(main_window,
u'settingsPluginListItem', u'settingsPluginListItem',
icon=u':/system/settings_plugin_list.png', icon=u':/system/settings_plugin_list.png',
shortcuts=[QtGui.QKeySequence(u'Alt+F7')], can_shortcuts=True,
category=UiStrings().Settings, triggers=self.onPluginItemClicked) category=UiStrings().Settings, triggers=self.onPluginItemClicked)
# i18n Language Items # i18n Language Items
self.autoLanguageItem = create_action(main_window, u'autoLanguageItem', self.autoLanguageItem = create_action(main_window, u'autoLanguageItem', checked=LanguageManager.auto_language)
checked=LanguageManager.auto_language)
self.languageGroup = QtGui.QActionGroup(main_window) self.languageGroup = QtGui.QActionGroup(main_window)
self.languageGroup.setExclusive(True) self.languageGroup.setExclusive(True)
self.languageGroup.setObjectName(u'languageGroup') self.languageGroup.setObjectName(u'languageGroup')
@ -277,20 +279,21 @@ class Ui_MainWindow(object):
languageItem = create_action(main_window, key, checked=qmList[key] == savedLanguage) languageItem = create_action(main_window, key, checked=qmList[key] == savedLanguage)
add_actions(self.languageGroup, [languageItem]) add_actions(self.languageGroup, [languageItem])
self.settingsShortcutsItem = create_action(main_window, u'settingsShortcutsItem', 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. # Formatting Tags were also known as display tags.
self.formattingTagItem = create_action(main_window, u'displayTagItem', 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', 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 # Give QT Extra Hint that this is the Preferences Menu Item
self.settingsConfigureItem.setMenuRole(QtGui.QAction.PreferencesRole) self.settingsConfigureItem.setMenuRole(QtGui.QAction.PreferencesRole)
self.settingsImportItem = create_action(main_window, u'settingsImportItem', category=UiStrings().Settings) self.settingsImportItem = create_action(
self.settingsExportItem = create_action(main_window, u'settingsExportItem', category=UiStrings().Settings) main_window, u'settingsImportItem', category=UiStrings().Import, can_shortcuts=True)
action_list.add_category(UiStrings().Help, CategoryOrder.standardMenu) 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', self.aboutItem = create_action(main_window, u'aboutItem', icon=u':/system/system_about.png',
shortcuts=[QtGui.QKeySequence(u'Ctrl+F1')], can_shortcuts=True, category=UiStrings().Help, triggers=self.onAboutItemClicked)
category=UiStrings().Help, triggers=self.onAboutItemClicked)
# Give QT Extra Hint that this is an About Menu Item # Give QT Extra Hint that this is an About Menu Item
self.aboutItem.setMenuRole(QtGui.QAction.AboutRole) self.aboutItem.setMenuRole(QtGui.QAction.AboutRole)
if os.name == u'nt': if os.name == u'nt':
@ -298,18 +301,20 @@ class Ui_MainWindow(object):
AppLocation.get_directory(AppLocation.AppDir), 'OpenLP.chm') AppLocation.get_directory(AppLocation.AppDir), 'OpenLP.chm')
self.offlineHelpItem = create_action(main_window, u'offlineHelpItem', self.offlineHelpItem = create_action(main_window, u'offlineHelpItem',
icon=u':/system/system_help_contents.png', icon=u':/system/system_help_contents.png',
shortcuts=[QtGui.QKeySequence(u'F1')], can_shortcuts=True,
category=UiStrings().Help, triggers=self.onOfflineHelpClicked) category=UiStrings().Help, triggers=self.onOfflineHelpClicked)
self.onlineHelpItem = create_action(main_window, u'onlineHelpItem', self.onlineHelpItem = create_action(main_window, u'onlineHelpItem',
icon=u':/system/system_online_help.png', icon=u':/system/system_online_help.png',
shortcuts=[QtGui.QKeySequence(u'Alt+F1')], can_shortcuts=True,
category=UiStrings().Help, triggers=self.onOnlineHelpClicked) 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.file_import_menu, (self.settingsImportItem, None, self.importThemeItem,
add_actions(self.fileExportMenu, (self.settingsExportItem, None, self.exportThemeItem, self.exportLanguageItem)) self.importLanguageItem))
add_actions(self.file_export_menu, (self.settingsExportItem, None, self.exportThemeItem,
self.exportLanguageItem))
add_actions(self.fileMenu, (self.fileNewItem, self.fileOpenItem, add_actions(self.fileMenu, (self.fileNewItem, self.fileOpenItem,
self.fileSaveItem, self.fileSaveAsItem, self.recentFilesMenu.menuAction(), None, self.fileSaveItem, self.fileSaveAsItem, self.recentFilesMenu.menuAction(), None,
self.fileImportMenu.menuAction(), self.fileExportMenu.menuAction(), None, self.printServiceOrderItem, self.file_import_menu.menuAction(), self.file_export_menu.menuAction(), None, self.printServiceOrderItem,
self.fileExitItem)) self.fileExitItem))
add_actions(self.viewModeMenu, (self.modeDefaultItem, self.modeSetupItem, self.modeLiveItem)) add_actions(self.viewModeMenu, (self.modeDefaultItem, self.modeSetupItem, self.modeLiveItem))
add_actions(self.viewMenu, (self.viewModeMenu.menuAction(), None, self.viewMediaManagerItem, add_actions(self.viewMenu, (self.viewModeMenu.menuAction(), None, self.viewMediaManagerItem,
@ -326,16 +331,16 @@ class Ui_MainWindow(object):
else: else:
add_actions(self.settingsMenu, (self.settingsPluginListItem, self.settingsLanguageMenu.menuAction(), None, add_actions(self.settingsMenu, (self.settingsPluginListItem, self.settingsLanguageMenu.menuAction(), None,
self.formattingTagItem, self.settingsShortcutsItem, self.settingsConfigureItem)) self.formattingTagItem, self.settingsShortcutsItem, self.settingsConfigureItem))
add_actions(self.toolsMenu, (self.toolsAddToolItem, None)) add_actions(self.tools_menu, (self.toolsAddToolItem, None))
add_actions(self.toolsMenu, (self.toolsOpenDataFolder, None)) add_actions(self.tools_menu, (self.toolsOpenDataFolder, None))
add_actions(self.toolsMenu, (self.toolsFirstTimeWizard, None)) add_actions(self.tools_menu, (self.toolsFirstTimeWizard, None))
add_actions(self.toolsMenu, [self.updateThemeImages]) add_actions(self.tools_menu, [self.updateThemeImages])
if os.name == u'nt': if os.name == u'nt':
add_actions(self.helpMenu, (self.offlineHelpItem, self.onlineHelpItem, None, self.webSiteItem, add_actions(self.helpMenu, (self.offlineHelpItem, self.onlineHelpItem, None, self.webSiteItem,
self.aboutItem)) self.aboutItem))
else: else:
add_actions(self.helpMenu, (self.onlineHelpItem, None, self.webSiteItem, self.aboutItem)) add_actions(self.helpMenu, (self.onlineHelpItem, None, self.webSiteItem, self.aboutItem))
add_actions(self.menuBar, (self.fileMenu.menuAction(), self.viewMenu.menuAction(), self.toolsMenu.menuAction(), add_actions(self.menuBar, (self.fileMenu.menuAction(), self.viewMenu.menuAction(), self.tools_menu.menuAction(),
self.settingsMenu.menuAction(), self.helpMenu.menuAction())) self.settingsMenu.menuAction(), self.helpMenu.menuAction()))
# Initialise the translation # Initialise the translation
self.retranslateUi(main_window) self.retranslateUi(main_window)
@ -356,12 +361,12 @@ class Ui_MainWindow(object):
mainWindow.mainTitle = UiStrings().OLPV2x mainWindow.mainTitle = UiStrings().OLPV2x
mainWindow.setWindowTitle(mainWindow.mainTitle) mainWindow.setWindowTitle(mainWindow.mainTitle)
self.fileMenu.setTitle(translate('OpenLP.MainWindow', '&File')) self.fileMenu.setTitle(translate('OpenLP.MainWindow', '&File'))
self.fileImportMenu.setTitle(translate('OpenLP.MainWindow', '&Import')) self.file_import_menu.setTitle(translate('OpenLP.MainWindow', '&Import'))
self.fileExportMenu.setTitle(translate('OpenLP.MainWindow', '&Export')) self.file_export_menu.setTitle(translate('OpenLP.MainWindow', '&Export'))
self.recentFilesMenu.setTitle(translate('OpenLP.MainWindow', '&Recent Files')) self.recentFilesMenu.setTitle(translate('OpenLP.MainWindow', '&Recent Files'))
self.viewMenu.setTitle(translate('OpenLP.MainWindow', '&View')) self.viewMenu.setTitle(translate('OpenLP.MainWindow', '&View'))
self.viewModeMenu.setTitle(translate('OpenLP.MainWindow', 'M&ode')) self.viewModeMenu.setTitle(translate('OpenLP.MainWindow', 'M&ode'))
self.toolsMenu.setTitle(translate('OpenLP.MainWindow', '&Tools')) self.tools_menu.setTitle(translate('OpenLP.MainWindow', '&Tools'))
self.settingsMenu.setTitle(translate('OpenLP.MainWindow', '&Settings')) self.settingsMenu.setTitle(translate('OpenLP.MainWindow', '&Settings'))
self.settingsLanguageMenu.setTitle(translate('OpenLP.MainWindow', '&Language')) self.settingsLanguageMenu.setTitle(translate('OpenLP.MainWindow', '&Language'))
self.helpMenu.setTitle(translate('OpenLP.MainWindow', '&Help')) self.helpMenu.setTitle(translate('OpenLP.MainWindow', '&Help'))
@ -475,102 +480,67 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
self.playersSettingsSection = u'players' self.playersSettingsSection = u'players'
self.displayTagsSection = u'displayTags' self.displayTagsSection = u'displayTags'
self.headerSection = u'SettingsImport' self.headerSection = u'SettingsImport'
self.recentFiles = []
self.timer_id = 0
self.timer_version_id = 0
self.new_data_path = None
self.copy_data = False
Settings().set_up_default_values() Settings().set_up_default_values()
Settings().remove_obsolete_settings() Settings().remove_obsolete_settings()
self.serviceNotSaved = False self.serviceNotSaved = False
self.aboutForm = AboutForm(self) self.aboutForm = AboutForm(self)
self.mediaController = MediaController(self) self.media_controller = MediaController()
self.settingsForm = SettingsForm(self) self.settingsForm = SettingsForm(self)
self.formattingTagForm = FormattingTagForm(self) self.formattingTagForm = FormattingTagForm(self)
self.shortcutForm = ShortcutListForm(self) self.shortcutForm = ShortcutListForm(self)
self.recentFiles = []
self.timer_id = 0
self.timer_version_id = 0
# Set up the path with plugins # Set up the path with plugins
self.plugin_manager = PluginManager() self.plugin_manager = PluginManager()
self.imageManager = ImageManager() self.image_manager = ImageManager()
# Set up the interface # Set up the interface
self.setupUi(self) self.setupUi(self)
# Register the active media players and suffixes # Define the media Dock Manager
self.mediaController.check_available_media_players() self.mediaDockManager = MediaDockManager(self.mediaToolBox)
# Load settings after setupUi so default UI sizes are overwritten # Load settings after setupUi so default UI sizes are overwritten
self.loadSettings() self.loadSettings()
# Once settings are loaded update the menu with the recent files. # Once settings are loaded update the menu with the recent files.
self.updateRecentFilesMenu() self.updateRecentFilesMenu()
self.pluginForm = PluginForm(self) self.pluginForm = PluginForm(self)
self.new_data_path = None
self.copy_data = False
# Set up signals and slots # Set up signals and slots
QtCore.QObject.connect(self.importThemeItem, QtCore.SIGNAL(u'triggered()'),
self.themeManagerContents.on_import_theme)
QtCore.QObject.connect(self.exportThemeItem, QtCore.SIGNAL(u'triggered()'),
self.themeManagerContents.on_export_theme)
QtCore.QObject.connect(self.mediaManagerDock, QtCore.SIGNAL(u'visibilityChanged(bool)'), QtCore.QObject.connect(self.mediaManagerDock, QtCore.SIGNAL(u'visibilityChanged(bool)'),
self.viewMediaManagerItem.setChecked) self.viewMediaManagerItem.setChecked)
QtCore.QObject.connect(self.serviceManagerDock, QtCore.SIGNAL(u'visibilityChanged(bool)'), QtCore.QObject.connect(self.serviceManagerDock, QtCore.SIGNAL(u'visibilityChanged(bool)'),
self.viewServiceManagerItem.setChecked) self.viewServiceManagerItem.setChecked)
QtCore.QObject.connect(self.themeManagerDock, QtCore.SIGNAL(u'visibilityChanged(bool)'), QtCore.QObject.connect(self.themeManagerDock, QtCore.SIGNAL(u'visibilityChanged(bool)'),
self.viewThemeManagerItem.setChecked) self.viewThemeManagerItem.setChecked)
QtCore.QObject.connect(self.webSiteItem, QtCore.SIGNAL(u'triggered()'), self.onHelpWebSiteClicked) self.importThemeItem.triggered.connect(self.themeManagerContents.on_import_theme)
QtCore.QObject.connect(self.toolsOpenDataFolder, QtCore.SIGNAL(u'triggered()'), self.exportThemeItem.triggered.connect(self.themeManagerContents.on_export_theme)
self.onToolsOpenDataFolderClicked) self.webSiteItem.triggered.connect(self.onHelpWebSiteClicked)
QtCore.QObject.connect(self.toolsFirstTimeWizard, QtCore.SIGNAL(u'triggered()'), self.onFirstTimeWizardClicked) self.toolsOpenDataFolder.triggered.connect(self.onToolsOpenDataFolderClicked)
QtCore.QObject.connect(self.updateThemeImages, QtCore.SIGNAL(u'triggered()'), self.onUpdateThemeImages) self.toolsFirstTimeWizard.triggered.connect(self.onFirstTimeWizardClicked)
QtCore.QObject.connect(self.formattingTagItem, QtCore.SIGNAL(u'triggered()'), self.onFormattingTagItemClicked) self.updateThemeImages.triggered.connect(self.onUpdateThemeImages)
QtCore.QObject.connect(self.settingsConfigureItem, QtCore.SIGNAL(u'triggered()'), self.formattingTagItem.triggered.connect(self.onFormattingTagItemClicked)
self.onSettingsConfigureItemClicked) self.settingsConfigureItem.triggered.connect(self.onSettingsConfigureItemClicked)
QtCore.QObject.connect(self.settingsShortcutsItem, QtCore.SIGNAL(u'triggered()'), self.settingsShortcutsItem.triggered.connect(self.onSettingsShortcutsItemClicked)
self.onSettingsShortcutsItemClicked) self.settingsImportItem.triggered.connect(self.onSettingsImportItemClicked)
QtCore.QObject.connect(self.settingsImportItem, QtCore.SIGNAL(u'triggered()'), self.settingsExportItem.triggered.connect(self.onSettingsExportItemClicked)
self.onSettingsImportItemClicked)
QtCore.QObject.connect(self.settingsExportItem, QtCore.SIGNAL(u'triggered()'), self.onSettingsExportItemClicked)
# i18n set signals for languages # i18n set signals for languages
self.languageGroup.triggered.connect(LanguageManager.set_language) self.languageGroup.triggered.connect(LanguageManager.set_language)
QtCore.QObject.connect(self.modeDefaultItem, QtCore.SIGNAL(u'triggered()'), self.onModeDefaultItemClicked) self.modeDefaultItem.triggered.connect(self.onModeDefaultItemClicked)
QtCore.QObject.connect(self.modeSetupItem, QtCore.SIGNAL(u'triggered()'), self.onModeSetupItemClicked) self.modeSetupItem.triggered.connect(self.onModeSetupItemClicked)
QtCore.QObject.connect(self.modeLiveItem, QtCore.SIGNAL(u'triggered()'), self.onModeLiveItemClicked) self.modeLiveItem.triggered.connect(self.onModeLiveItemClicked)
# Media Manager # Media Manager
QtCore.QObject.connect(self.mediaToolBox, QtCore.SIGNAL(u'currentChanged(int)'), self.onMediaToolBoxChanged) self.mediaToolBox.currentChanged.connect(self.onMediaToolBoxChanged)
self.application.set_busy_cursor() self.application.set_busy_cursor()
# Simple message boxes # Simple message boxes
Registry().register_function(u'theme_update_global', self.default_theme_changed) Registry().register_function(u'theme_update_global', self.default_theme_changed)
Registry().register_function(u'openlp_version_check', self.version_notice) Registry().register_function(u'openlp_version_check', self.version_notice)
Registry().register_function(u'config_screen_changed', self.screen_changed) Registry().register_function(u'config_screen_changed', self.screen_changed)
self.renderer = Renderer() self.renderer = Renderer()
# Define the media Dock Manager
self.mediaDockManager = MediaDockManager(self.mediaToolBox)
log.info(u'Load Plugins')
self.plugin_manager.find_plugins()
# hook methods have to happen after find_plugins. Find plugins needs
# the controllers hence the hooks have moved from setupUI() to here
# Find and insert settings tabs
log.info(u'hook settings')
self.plugin_manager.hook_settings_tabs(self.settingsForm)
# Find and insert media manager items
log.info(u'hook media')
self.plugin_manager.hook_media_manager()
# Call the hook method to pull in import menus.
log.info(u'hook menus')
self.plugin_manager.hook_import_menu(self.fileImportMenu)
# Call the hook method to pull in export menus.
self.plugin_manager.hook_export_menu(self.fileExportMenu)
# Call the hook method to pull in tools menus.
self.plugin_manager.hook_tools_menu(self.toolsMenu)
# Call the initialise method to setup plugins.
log.info(u'initialise plugins')
self.plugin_manager.initialise_plugins()
# Create the displays as all necessary components are loaded.
self.previewController.screenSizeChanged()
self.liveController.screenSizeChanged()
log.info(u'Load data from Settings') log.info(u'Load data from Settings')
if Settings().value(u'advanced/save current plugin'): if Settings().value(u'advanced/save current plugin'):
savedPlugin = Settings().value(u'advanced/current media plugin') savedPlugin = Settings().value(u'advanced/current media plugin')
if savedPlugin != -1: if savedPlugin != -1:
self.mediaToolBox.setCurrentIndex(savedPlugin) self.mediaToolBox.setCurrentIndex(savedPlugin)
self.settingsForm.postSetUp()
# Once all components are initialised load the Themes
log.info(u'Load Themes')
self.themeManagerContents.load_themes(True)
# Reset the cursor # Reset the cursor
self.application.set_normal_cursor() self.application.set_normal_cursor()
@ -605,8 +575,8 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
Show the main form, as well as the display form Show the main form, as well as the display form
""" """
QtGui.QWidget.show(self) QtGui.QWidget.show(self)
if self.liveController.display.isVisible(): if self.live_controller.display.isVisible():
self.liveController.display.setFocus() self.live_controller.display.setFocus()
self.activateWindow() self.activateWindow()
if self.arguments: if self.arguments:
args = [] args = []
@ -699,7 +669,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
Check and display message if screen blank on setup. Check and display message if screen blank on setup.
""" """
settings = Settings() settings = Settings()
self.liveController.mainDisplaySetBackground() self.live_controller.mainDisplaySetBackground()
if settings.value(u'%s/screen blank' % self.generalSettingsSection): if settings.value(u'%s/screen blank' % self.generalSettingsSection):
if settings.value(u'%s/blank warning' % self.generalSettingsSection): if settings.value(u'%s/blank warning' % self.generalSettingsSection):
QtGui.QMessageBox.question(self, translate('OpenLP.MainWindow', 'OpenLP Main Display Blanked'), QtGui.QMessageBox.question(self, translate('OpenLP.MainWindow', 'OpenLP Main Display Blanked'),
@ -806,8 +776,8 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
""" """
We need to make sure, that the SlidePreview's size is correct. We need to make sure, that the SlidePreview's size is correct.
""" """
self.previewController.previewSizeChanged() self.preview_controller.previewSizeChanged()
self.liveController.previewSizeChanged() self.live_controller.previewSizeChanged()
def onSettingsShortcutsItemClicked(self): def onSettingsShortcutsItemClicked(self):
""" """
@ -1015,10 +985,10 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
""" """
log.debug(u'screen_changed') log.debug(u'screen_changed')
self.application.set_busy_cursor() self.application.set_busy_cursor()
self.imageManager.update_display() self.image_manager.update_display()
self.renderer.update_display() self.renderer.update_display()
self.previewController.screenSizeChanged() self.preview_controller.screenSizeChanged()
self.liveController.screenSizeChanged() self.live_controller.screenSizeChanged()
self.setFocus() self.setFocus()
self.activateWindow() self.activateWindow()
self.application.set_normal_cursor() self.application.set_normal_cursor()
@ -1071,8 +1041,8 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
``save_settings`` ``save_settings``
Switch to prevent saving settings. Defaults to **True**. Switch to prevent saving settings. Defaults to **True**.
""" """
self.imageManager.stop_manager = True self.image_manager.stop_manager = True
while self.imageManager.image_thread.isRunning(): while self.image_manager.image_thread.isRunning():
time.sleep(0.1) time.sleep(0.1)
# Clean temporary files used by services # Clean temporary files used by services
self.serviceManagerContents.clean_up() self.serviceManagerContents.clean_up()
@ -1089,9 +1059,9 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
if self.new_data_path: if self.new_data_path:
self.changeDataDirectory() self.changeDataDirectory()
# Close down the display # Close down the display
if self.liveController.display: if self.live_controller.display:
self.liveController.display.close() self.live_controller.display.close()
self.liveController.display = None self.live_controller.display = None
def serviceChanged(self, reset=False, serviceName=None): def serviceChanged(self, reset=False, serviceName=None):
""" """
@ -1172,7 +1142,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
True - Visible True - Visible
False - Hidden False - Hidden
""" """
self.previewController.panel.setVisible(visible) self.preview_controller.panel.setVisible(visible)
Settings().setValue(u'user interface/preview panel', visible) Settings().setValue(u'user interface/preview panel', visible)
self.viewPreviewPanel.setChecked(visible) self.viewPreviewPanel.setChecked(visible)
@ -1210,7 +1180,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
True - Visible True - Visible
False - Hidden False - Hidden
""" """
self.liveController.panel.setVisible(visible) self.live_controller.panel.setVisible(visible)
Settings().setValue(u'user interface/live panel', visible) Settings().setValue(u'user interface/live panel', visible)
self.viewLivePanel.setChecked(visible) self.viewLivePanel.setChecked(visible)
@ -1230,8 +1200,8 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
self.move(settings.value(u'main window position')) self.move(settings.value(u'main window position'))
self.restoreGeometry(settings.value(u'main window geometry')) self.restoreGeometry(settings.value(u'main window geometry'))
self.restoreState(settings.value(u'main window state')) self.restoreState(settings.value(u'main window state'))
self.liveController.splitter.restoreState(settings.value(u'live splitter geometry')) self.live_controller.splitter.restoreState(settings.value(u'live splitter geometry'))
self.previewController.splitter.restoreState(settings.value(u'preview splitter geometry')) self.preview_controller.splitter.restoreState(settings.value(u'preview splitter geometry'))
self.controlSplitter.restoreState(settings.value(u'main window splitter geometry')) self.controlSplitter.restoreState(settings.value(u'main window splitter geometry'))
settings.endGroup() settings.endGroup()
@ -1251,8 +1221,8 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
settings.setValue(u'main window position', self.pos()) settings.setValue(u'main window position', self.pos())
settings.setValue(u'main window state', self.saveState()) settings.setValue(u'main window state', self.saveState())
settings.setValue(u'main window geometry', self.saveGeometry()) settings.setValue(u'main window geometry', self.saveGeometry())
settings.setValue(u'live splitter geometry', self.liveController.splitter.saveState()) settings.setValue(u'live splitter geometry', self.live_controller.splitter.saveState())
settings.setValue(u'preview splitter geometry', self.previewController.splitter.saveState()) settings.setValue(u'preview splitter geometry', self.preview_controller.splitter.saveState())
settings.setValue(u'main window splitter geometry', self.controlSplitter.saveState()) settings.setValue(u'main window splitter geometry', self.controlSplitter.saveState())
settings.endGroup() settings.endGroup()

View File

@ -61,8 +61,8 @@ class MediaSlider(QtGui.QSlider):
""" """
Override event to allow hover time to be displayed. Override event to allow hover time to be displayed.
""" """
timevalue = QtGui.QStyle.sliderValueFromPosition(self.minimum(), self.maximum(), event.x(), self.width()) time_value = QtGui.QStyle.sliderValueFromPosition(self.minimum(), self.maximum(), event.x(), self.width())
self.setToolTip(u'%s' % datetime.timedelta(seconds=int(timevalue / 1000))) self.setToolTip(u'%s' % datetime.timedelta(seconds=int(time_value / 1000)))
QtGui.QSlider.mouseMoveEvent(self, event) QtGui.QSlider.mouseMoveEvent(self, event)
def mousePressEvent(self, event): def mousePressEvent(self, event):
@ -88,20 +88,20 @@ class MediaController(object):
slidecontroller or plugin which built them. ControllerType is the class slidecontroller or plugin which built them. ControllerType is the class
containing the key values. containing the key values.
mediaPlayers are an array of media players keyed on player name. media_players are an array of media players keyed on player name.
currentMediaPlayer is an array of player instances keyed on ControllerType. current_media_players is an array of player instances keyed on ControllerType.
""" """
def __init__(self, parent): def __init__(self):
""" """
Constructor Constructor
""" """
self.mainWindow = parent
Registry().register(u'media_controller', self) Registry().register(u'media_controller', self)
self.mediaPlayers = {} Registry().register_function(u'bootstrap_initialise', self.check_available_media_players)
self.media_players = {}
self.displayControllers = {} self.displayControllers = {}
self.currentMediaPlayer = {} self.current_media_players = {}
# Timer for video state # Timer for video state
self.timer = QtCore.QTimer() self.timer = QtCore.QTimer()
self.timer.setInterval(200) self.timer.setInterval(200)
@ -126,22 +126,22 @@ class MediaController(object):
Set the active players and available media files Set the active players and available media files
""" """
savedPlayers = get_media_players()[0] savedPlayers = get_media_players()[0]
for player in self.mediaPlayers.keys(): for player in self.media_players.keys():
self.mediaPlayers[player].isActive = player in savedPlayers self.media_players[player].isActive = player in savedPlayers
def _generate_extensions_lists(self): def _generate_extensions_lists(self):
""" """
Set the active players and available media files Set the active players and available media files
""" """
self.audio_extensions_list = [] self.audio_extensions_list = []
for player in self.mediaPlayers.values(): for player in self.media_players.values():
if player.isActive: if player.isActive:
for item in player.audio_extensions_list: for item in player.audio_extensions_list:
if not item in self.audio_extensions_list: if not item in self.audio_extensions_list:
self.audio_extensions_list.append(item) self.audio_extensions_list.append(item)
self.service_manager.supported_suffixes(item[2:]) self.service_manager.supported_suffixes(item[2:])
self.video_extensions_list = [] self.video_extensions_list = []
for player in self.mediaPlayers.values(): for player in self.media_players.values():
if player.isActive: if player.isActive:
for item in player.video_extensions_list: for item in player.video_extensions_list:
if item not in self.video_extensions_list: if item not in self.video_extensions_list:
@ -156,16 +156,14 @@ class MediaController(object):
``player`` ``player``
Individual player class which has been enabled Individual player class which has been enabled
""" """
self.mediaPlayers[player.name] = player self.media_players[player.name] = player
def check_available_media_players(self): def check_available_media_players(self):
""" """
Check to see if we have any media Player's available. Check to see if we have any media Player's available.
""" """
log.debug(u'_check_available_media_players') log.debug(u'_check_available_media_players')
controller_dir = os.path.join( controller_dir = os.path.join(AppLocation.get_directory(AppLocation.AppDir), u'core', u'ui', u'media')
AppLocation.get_directory(AppLocation.AppDir),
u'core', u'ui', u'media')
for filename in os.listdir(controller_dir): for filename in os.listdir(controller_dir):
if filename.endswith(u'player.py') and not filename == 'mediaplayer.py': if filename.endswith(u'player.py') and not filename == 'mediaplayer.py':
path = os.path.join(controller_dir, filename) path = os.path.join(controller_dir, filename)
@ -182,13 +180,13 @@ class MediaController(object):
for player_class in player_classes: for player_class in player_classes:
player = player_class(self) player = player_class(self)
self.register_players(player) self.register_players(player)
if not self.mediaPlayers: if not self.media_players:
return False return False
savedPlayers, overriddenPlayer = get_media_players() savedPlayers, overriddenPlayer = get_media_players()
invalidMediaPlayers = [mediaPlayer for mediaPlayer in savedPlayers invalid_media_players = [mediaPlayer for mediaPlayer in savedPlayers
if not mediaPlayer in self.mediaPlayers or not self.mediaPlayers[mediaPlayer].check_available()] if not mediaPlayer in self.media_players or not self.media_players[mediaPlayer].check_available()]
if invalidMediaPlayers: if invalid_media_players:
for invalidPlayer in invalidMediaPlayers: for invalidPlayer in invalid_media_players:
savedPlayers.remove(invalidPlayer) savedPlayers.remove(invalidPlayer)
set_media_players(savedPlayers, overriddenPlayer) set_media_players(savedPlayers, overriddenPlayer)
self._set_active_players() self._set_active_players()
@ -200,22 +198,22 @@ class MediaController(object):
Check if there is a running media Player and do updating stuff (e.g. Check if there is a running media Player and do updating stuff (e.g.
update the UI) update the UI)
""" """
if not self.currentMediaPlayer.keys(): if not self.current_media_players.keys():
self.timer.stop() self.timer.stop()
else: else:
any_active = False any_active = False
for source in self.currentMediaPlayer.keys(): for source in self.current_media_players.keys():
display = self._define_display(self.displayControllers[source]) display = self._define_display(self.displayControllers[source])
self.currentMediaPlayer[source].resize(display) self.current_media_players[source].resize(display)
self.currentMediaPlayer[source].update_ui(display) self.current_media_players[source].update_ui(display)
if self.currentMediaPlayer[source].state == MediaState.Playing: if self.current_media_players[source].state == MediaState.Playing:
any_active = True any_active = True
# There are still any active players - no need to stop timer. # There are still any active players - no need to stop timer.
if any_active: if any_active:
return return
# no players are active anymore # no players are active anymore
for source in self.currentMediaPlayer.keys(): for source in self.current_media_players.keys():
if self.currentMediaPlayer[source].state != MediaState.Paused: if self.current_media_players[source].state != MediaState.Paused:
display = self._define_display(self.displayControllers[source]) display = self._define_display(self.displayControllers[source])
display.controller.seekSlider.setSliderPosition(0) display.controller.seekSlider.setSliderPosition(0)
self.timer.stop() self.timer.stop()
@ -225,7 +223,7 @@ class MediaController(object):
Add css style sheets to htmlbuilder Add css style sheets to htmlbuilder
""" """
css = u'' css = u''
for player in self.mediaPlayers.values(): for player in self.media_players.values():
if player.isActive: if player.isActive:
css += player.get_media_display_css() css += player.get_media_display_css()
return css return css
@ -235,7 +233,7 @@ class MediaController(object):
Add javascript functions to htmlbuilder Add javascript functions to htmlbuilder
""" """
js = u'' js = u''
for player in self.mediaPlayers.values(): for player in self.media_players.values():
if player.isActive: if player.isActive:
js += player.get_media_display_javascript() js += player.get_media_display_javascript()
return js return js
@ -245,7 +243,7 @@ class MediaController(object):
Add html code to htmlbuilder Add html code to htmlbuilder
""" """
html = u'' html = u''
for player in self.mediaPlayers.values(): for player in self.media_players.values():
if player.isActive: if player.isActive:
html += player.get_media_display_html() html += player.get_media_display_html()
return html return html
@ -257,7 +255,7 @@ class MediaController(object):
``controller`` ``controller``
The controller where a player will be placed The controller where a player will be placed
""" """
self.displayControllers[controller.controllerType] = controller self.displayControllers[controller.controller_type] = controller
self.setup_generic_controls(controller) self.setup_generic_controls(controller)
def setup_generic_controls(self, controller): def setup_generic_controls(self, controller):
@ -272,13 +270,13 @@ class MediaController(object):
controller.mediabar = OpenLPToolbar(controller) controller.mediabar = OpenLPToolbar(controller)
controller.mediabar.addToolbarAction(u'playbackPlay', text=u'media_playback_play', controller.mediabar.addToolbarAction(u'playbackPlay', text=u'media_playback_play',
icon=u':/slides/media_playback_start.png', icon=u':/slides/media_playback_start.png',
tooltip=translate('OpenLP.SlideController', 'Start playing media.'), triggers=controller.sendToPlugins) tooltip=translate('OpenLP.SlideController', 'Start playing media.'), triggers=controller.send_to_plugins)
controller.mediabar.addToolbarAction(u'playbackPause', text=u'media_playback_pause', controller.mediabar.addToolbarAction(u'playbackPause', text=u'media_playback_pause',
icon=u':/slides/media_playback_pause.png', icon=u':/slides/media_playback_pause.png',
tooltip=translate('OpenLP.SlideController', 'Pause playing media.'), triggers=controller.sendToPlugins) tooltip=translate('OpenLP.SlideController', 'Pause playing media.'), triggers=controller.send_to_plugins)
controller.mediabar.addToolbarAction(u'playbackStop', text=u'media_playback_stop', controller.mediabar.addToolbarAction(u'playbackStop', text=u'media_playback_stop',
icon=u':/slides/media_playback_stop.png', icon=u':/slides/media_playback_stop.png',
tooltip=translate('OpenLP.SlideController', 'Stop playing media.'), triggers=controller.sendToPlugins) tooltip=translate('OpenLP.SlideController', 'Stop playing media.'), triggers=controller.send_to_plugins)
# Build the seekSlider. # Build the seekSlider.
controller.seekSlider = MediaSlider(QtCore.Qt.Horizontal, self, controller) controller.seekSlider = MediaSlider(QtCore.Qt.Horizontal, self, controller)
controller.seekSlider.setMaximum(1000) controller.seekSlider.setMaximum(1000)
@ -300,15 +298,15 @@ class MediaController(object):
controller.volumeSlider.setGeometry(QtCore.QRect(90, 160, 221, 24)) controller.volumeSlider.setGeometry(QtCore.QRect(90, 160, 221, 24))
controller.volumeSlider.setObjectName(u'volumeSlider') controller.volumeSlider.setObjectName(u'volumeSlider')
controller.mediabar.addToolbarWidget(controller.volumeSlider) controller.mediabar.addToolbarWidget(controller.volumeSlider)
controller.controllerLayout.addWidget(controller.mediabar) controller.controller_layout.addWidget(controller.mediabar)
controller.mediabar.setVisible(False) controller.mediabar.setVisible(False)
# Signals # Signals
QtCore.QObject.connect(controller.seekSlider, QtCore.SIGNAL(u'valueChanged(int)'), controller.sendToPlugins) controller.seekSlider.valueChanged.connect(controller.send_to_plugins)
QtCore.QObject.connect(controller.volumeSlider, QtCore.SIGNAL(u'valueChanged(int)'), controller.sendToPlugins) controller.volumeSlider.valueChanged.connect(controller.send_to_plugins)
def setup_display(self, display, preview): def setup_display(self, display, preview):
""" """
After a new display is configured, all media related widget will be After a new display is configured, all media related widgets will be
created too created too
``display`` ``display``
@ -322,11 +320,11 @@ class MediaController(object):
# update player status # update player status
self._set_active_players() self._set_active_players()
display.hasAudio = True display.hasAudio = True
if display.isLive and preview: if display.is_live and preview:
return return
if preview: if preview:
display.hasAudio = False display.hasAudio = False
for player in self.mediaPlayers.values(): for player in self.media_players.values():
if player.isActive: if player.isActive:
player.setup(display) player.setup(display)
@ -343,10 +341,10 @@ class MediaController(object):
""" """
# Generic controls # Generic controls
controller.mediabar.setVisible(value) controller.mediabar.setVisible(value)
if controller.isLive and controller.display: if controller.is_live and controller.display:
if self.currentMediaPlayer and value: if self.current_media_players and value:
if self.currentMediaPlayer[controller.controllerType] != self.mediaPlayers[u'webkit']: if self.current_media_players[controller.controller_type] != self.media_players[u'webkit']:
controller.display.setTransparency(False) controller.display.set_transparency(False)
def resize(self, display, player): def resize(self, display, player):
""" """
@ -387,7 +385,7 @@ class MediaController(object):
controller.media_info.is_background = videoBehindText controller.media_info.is_background = videoBehindText
controller.media_info.file_info = QtCore.QFileInfo(serviceItem.get_frame_path()) controller.media_info.file_info = QtCore.QFileInfo(serviceItem.get_frame_path())
display = self._define_display(controller) display = self._define_display(controller)
if controller.isLive: if controller.is_live:
isValid = self._check_file_type(controller, display, serviceItem) isValid = self._check_file_type(controller, display, serviceItem)
display.override[u'theme'] = u'' display.override[u'theme'] = u''
display.override[u'video'] = True display.override[u'video'] = True
@ -398,7 +396,7 @@ class MediaController(object):
else: else:
controller.media_info.start_time = serviceItem.start_time controller.media_info.start_time = serviceItem.start_time
controller.media_info.end_time = serviceItem.end_time controller.media_info.end_time = serviceItem.end_time
elif controller.previewDisplay: elif controller.preview_display:
isValid = self._check_file_type(controller, display, serviceItem) isValid = self._check_file_type(controller, display, serviceItem)
if not isValid: if not isValid:
# Media could not be loaded correctly # Media could not be loaded correctly
@ -406,12 +404,12 @@ class MediaController(object):
translate('MediaPlugin.MediaItem', 'Unsupported File')) translate('MediaPlugin.MediaItem', 'Unsupported File'))
return False return False
# dont care about actual theme, set a black background # dont care about actual theme, set a black background
if controller.isLive and not controller.media_info.is_background: if controller.is_live and not controller.media_info.is_background:
display.frame.evaluateJavaScript(u'show_video( "setBackBoard", null, null, null,"visible");') display.frame.evaluateJavaScript(u'show_video( "setBackBoard", null, null, null,"visible");')
# now start playing - Preview is autoplay! # now start playing - Preview is autoplay!
autoplay = False autoplay = False
# Preview requested # Preview requested
if not controller.isLive: if not controller.is_live:
autoplay = True autoplay = True
# Visible or background requested or Service Item wants to autostart # Visible or background requested or Service Item wants to autostart
elif not hidden or controller.media_info.is_background or serviceItem.will_auto_start: elif not hidden or controller.media_info.is_background or serviceItem.will_auto_start:
@ -425,7 +423,7 @@ class MediaController(object):
translate('MediaPlugin.MediaItem', 'Unsupported File')) translate('MediaPlugin.MediaItem', 'Unsupported File'))
return False return False
self.set_controls_visible(controller, True) self.set_controls_visible(controller, True)
log.debug(u'use %s controller' % self.currentMediaPlayer[controller.controllerType]) log.debug(u'use %s controller' % self.current_media_players[controller.controller_type])
return True return True
def media_length(self, serviceItem): def media_length(self, serviceItem):
@ -442,7 +440,7 @@ class MediaController(object):
controller.media_info = MediaInfo() controller.media_info = MediaInfo()
controller.media_info.volume = 0 controller.media_info.volume = 0
controller.media_info.file_info = QtCore.QFileInfo(serviceItem.get_frame_path()) controller.media_info.file_info = QtCore.QFileInfo(serviceItem.get_frame_path())
display = controller.previewDisplay display = controller._display
if not self._check_file_type(controller, display, serviceItem): if not self._check_file_type(controller, display, serviceItem):
# Media could not be loaded correctly # Media could not be loaded correctly
critical_error_message_box(translate('MediaPlugin.MediaItem', 'Unsupported File'), critical_error_message_box(translate('MediaPlugin.MediaItem', 'Unsupported File'),
@ -454,7 +452,7 @@ class MediaController(object):
return False return False
serviceItem.set_media_length(controller.media_info.length) serviceItem.set_media_length(controller.media_info.length)
self.media_stop(controller) self.media_stop(controller)
log.debug(u'use %s controller' % self.currentMediaPlayer[controller.controllerType]) log.debug(u'use %s controller' % self.current_media_players[controller.controller_type])
return True return True
def _check_file_type(self, controller, display, serviceItem): def _check_file_type(self, controller, display, serviceItem):
@ -473,27 +471,27 @@ class MediaController(object):
if controller.media_info.file_info.isFile(): if controller.media_info.file_info.isFile():
suffix = u'*.%s' % controller.media_info.file_info.suffix().lower() suffix = u'*.%s' % controller.media_info.file_info.suffix().lower()
for title in usedPlayers: for title in usedPlayers:
player = self.mediaPlayers[title] player = self.media_players[title]
if suffix in player.video_extensions_list: if suffix in player.video_extensions_list:
if not controller.media_info.is_background or controller.media_info.is_background and \ if not controller.media_info.is_background or controller.media_info.is_background and \
player.canBackground: player.canBackground:
self.resize(display, player) self.resize(display, player)
if player.load(display): if player.load(display):
self.currentMediaPlayer[controller.controllerType] = player self.current_media_players[controller.controller_type] = player
controller.media_info.media_type = MediaType.Video controller.media_info.media_type = MediaType.Video
return True return True
if suffix in player.audio_extensions_list: if suffix in player.audio_extensions_list:
if player.load(display): if player.load(display):
self.currentMediaPlayer[controller.controllerType] = player self.current_media_players[controller.controller_type] = player
controller.media_info.media_type = MediaType.Audio controller.media_info.media_type = MediaType.Audio
return True return True
else: else:
for title in usedPlayers: for title in usedPlayers:
player = self.mediaPlayers[title] player = self.media_players[title]
if player.canFolder: if player.canFolder:
self.resize(display, player) self.resize(display, player)
if player.load(display): if player.load(display):
self.currentMediaPlayer[controller.controllerType] = player self.current_media_players[controller.controller_type] = player
controller.media_info.media_type = MediaType.Video controller.media_info.media_type = MediaType.Video
return True return True
# no valid player found # no valid player found
@ -520,7 +518,7 @@ class MediaController(object):
controller.seekSlider.blockSignals(True) controller.seekSlider.blockSignals(True)
controller.volumeSlider.blockSignals(True) controller.volumeSlider.blockSignals(True)
display = self._define_display(controller) display = self._define_display(controller)
if not self.currentMediaPlayer[controller.controllerType].play(display): if not self.current_media_players[controller.controller_type].play(display):
controller.seekSlider.blockSignals(False) controller.seekSlider.blockSignals(False)
controller.volumeSlider.blockSignals(False) controller.volumeSlider.blockSignals(False)
return False return False
@ -530,7 +528,7 @@ class MediaController(object):
self.media_volume(controller, controller.media_info.volume) self.media_volume(controller, controller.media_info.volume)
if status: if status:
display.frame.evaluateJavaScript(u'show_blank("desktop");') display.frame.evaluateJavaScript(u'show_blank("desktop");')
self.currentMediaPlayer[controller.controllerType].set_visible(display, True) self.current_media_players[controller.controller_type].set_visible(display, True)
# Flash needs to be played and will not AutoPlay # Flash needs to be played and will not AutoPlay
if controller.media_info.is_flash: if controller.media_info.is_flash:
controller.mediabar.actions[u'playbackPlay'].setVisible(True) controller.mediabar.actions[u'playbackPlay'].setVisible(True)
@ -539,9 +537,9 @@ class MediaController(object):
controller.mediabar.actions[u'playbackPlay'].setVisible(False) controller.mediabar.actions[u'playbackPlay'].setVisible(False)
controller.mediabar.actions[u'playbackPause'].setVisible(True) controller.mediabar.actions[u'playbackPause'].setVisible(True)
controller.mediabar.actions[u'playbackStop'].setVisible(True) controller.mediabar.actions[u'playbackStop'].setVisible(True)
if controller.isLive: if controller.is_live:
if controller.hideMenu.defaultAction().isChecked(): if controller.hide_menu.defaultAction().isChecked():
controller.hideMenu.defaultAction().trigger() controller.hide_menu.defaultAction().trigger()
# Start Timer for ui updates # Start Timer for ui updates
if not self.timer.isActive(): if not self.timer.isActive():
self.timer.start() self.timer.start()
@ -568,7 +566,7 @@ class MediaController(object):
""" """
log.debug(u'media_pause') log.debug(u'media_pause')
display = self._define_display(controller) display = self._define_display(controller)
self.currentMediaPlayer[controller.controllerType].pause(display) self.current_media_players[controller.controller_type].pause(display)
controller.mediabar.actions[u'playbackPlay'].setVisible(True) controller.mediabar.actions[u'playbackPlay'].setVisible(True)
controller.mediabar.actions[u'playbackStop'].setVisible(True) controller.mediabar.actions[u'playbackStop'].setVisible(True)
controller.mediabar.actions[u'playbackPause'].setVisible(False) controller.mediabar.actions[u'playbackPause'].setVisible(False)
@ -592,10 +590,10 @@ class MediaController(object):
""" """
log.debug(u'media_stop') log.debug(u'media_stop')
display = self._define_display(controller) display = self._define_display(controller)
if controller.controllerType in self.currentMediaPlayer: if controller.controller_type in self.current_media_players:
display.frame.evaluateJavaScript(u'show_blank("black");') display.frame.evaluateJavaScript(u'show_blank("black");')
self.currentMediaPlayer[controller.controllerType].stop(display) self.current_media_players[controller.controller_type].stop(display)
self.currentMediaPlayer[controller.controllerType].set_visible(display, False) self.current_media_players[controller.controller_type].set_visible(display, False)
controller.seekSlider.setSliderPosition(0) controller.seekSlider.setSliderPosition(0)
controller.mediabar.actions[u'playbackPlay'].setVisible(True) controller.mediabar.actions[u'playbackPlay'].setVisible(True)
controller.mediabar.actions[u'playbackStop'].setVisible(False) controller.mediabar.actions[u'playbackStop'].setVisible(False)
@ -621,7 +619,7 @@ class MediaController(object):
""" """
log.debug(u'media_volume %d' % volume) log.debug(u'media_volume %d' % volume)
display = self._define_display(controller) display = self._define_display(controller)
self.currentMediaPlayer[controller.controllerType].volume(display, volume) self.current_media_players[controller.controller_type].volume(display, volume)
controller.volumeSlider.setValue(volume) controller.volumeSlider.setValue(volume)
def media_seek_msg(self, msg): def media_seek_msg(self, msg):
@ -647,7 +645,7 @@ class MediaController(object):
""" """
log.debug(u'media_seek') log.debug(u'media_seek')
display = self._define_display(controller) display = self._define_display(controller)
self.currentMediaPlayer[controller.controllerType].seek(display, seekVal) self.current_media_players[controller.controller_type].seek(display, seekVal)
def media_reset(self, controller): def media_reset(self, controller):
""" """
@ -656,12 +654,12 @@ class MediaController(object):
log.debug(u'media_reset') log.debug(u'media_reset')
self.set_controls_visible(controller, False) self.set_controls_visible(controller, False)
display = self._define_display(controller) display = self._define_display(controller)
if controller.controllerType in self.currentMediaPlayer: if controller.controller_type in self.current_media_players:
display.override = {} display.override = {}
self.currentMediaPlayer[controller.controllerType].reset(display) self.current_media_players[controller.controller_type].reset(display)
self.currentMediaPlayer[controller.controllerType].set_visible(display, False) self.current_media_players[controller.controller_type].set_visible(display, False)
display.frame.evaluateJavaScript(u'show_video( "setBackBoard", null, null, null,"hidden");') display.frame.evaluateJavaScript(u'show_video( "setBackBoard", null, null, null,"hidden");')
del self.currentMediaPlayer[controller.controllerType] del self.current_media_players[controller.controller_type]
def media_hide(self, msg): def media_hide(self, msg):
""" """
@ -670,15 +668,14 @@ class MediaController(object):
``msg`` ``msg``
First element is the boolean for Live indication First element is the boolean for Live indication
""" """
isLive = msg[1] is_live = msg[1]
if not isLive: if not is_live:
return return
controller = self.mainWindow.liveController display = self._define_display(self.live_controller)
display = self._define_display(controller) if self.live_controller.controller_type in self.current_media_players and \
if controller.controllerType in self.currentMediaPlayer and \ self.current_media_players[self.live_controller.controller_type].state == MediaState.Playing:
self.currentMediaPlayer[controller.controllerType].state == MediaState.Playing: self.current_media_players[self.live_controller.controller_type].pause(display)
self.currentMediaPlayer[controller.controllerType].pause(display) self.current_media_players[self.live_controller.controller_type].set_visible(display, False)
self.currentMediaPlayer[controller.controllerType].set_visible(display, False)
def media_blank(self, msg): def media_blank(self, msg):
""" """
@ -688,16 +685,15 @@ class MediaController(object):
First element is the boolean for Live indication First element is the boolean for Live indication
Second element is the hide mode Second element is the hide mode
""" """
isLive = msg[1] is_live = msg[1]
hide_mode = msg[2] hide_mode = msg[2]
if not isLive: if not is_live:
return return
Registry().execute(u'live_display_hide', hide_mode) Registry().execute(u'live_display_hide', hide_mode)
controller = self.mainWindow.liveController display = self._define_display(self.live_controller)
display = self._define_display(controller) if self.current_media_players[self.live_controller.controller_type].state == MediaState.Playing:
if self.currentMediaPlayer[controller.controllerType].state == MediaState.Playing: self.current_media_players[self.live_controller.controller_type].pause(display)
self.currentMediaPlayer[controller.controllerType].pause(display) self.current_media_players[self.live_controller.controller_type].set_visible(display, False)
self.currentMediaPlayer[controller.controllerType].set_visible(display, False)
def media_unblank(self, msg): def media_unblank(self, msg):
""" """
@ -708,15 +704,14 @@ class MediaController(object):
Second element is the boolean for Live indication Second element is the boolean for Live indication
""" """
Registry().execute(u'live_display_show') Registry().execute(u'live_display_show')
isLive = msg[1] is_live = msg[1]
if not isLive: if not is_live:
return return
controller = self.mainWindow.liveController display = self._define_display(self.live_controller)
display = self._define_display(controller) if self.live_controller.controller_type in self.current_media_players and \
if controller.controllerType in self.currentMediaPlayer and \ self.current_media_players[self.live_controller.controller_type].state != MediaState.Playing:
self.currentMediaPlayer[controller.controllerType].state != MediaState.Playing: if self.current_media_players[self.live_controller.controller_type].play(display):
if self.currentMediaPlayer[controller.controllerType].play(display): self.current_media_players[self.live_controller.controller_type].set_visible(display, True)
self.currentMediaPlayer[controller.controllerType].set_visible(display, True)
# Start Timer for ui updates # Start Timer for ui updates
if not self.timer.isActive(): if not self.timer.isActive():
self.timer.start() self.timer.start()
@ -736,9 +731,9 @@ class MediaController(object):
``controller`` ``controller``
Controller to be used Controller to be used
""" """
if controller.isLive: if controller.is_live:
return controller.display return controller.display
return controller.previewDisplay return controller.preview_display
def _get_service_manager(self): def _get_service_manager(self):
""" """
@ -749,3 +744,13 @@ class MediaController(object):
return self._service_manager return self._service_manager
service_manager = property(_get_service_manager) service_manager = property(_get_service_manager)
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)

View File

@ -55,7 +55,7 @@ class PlayerTab(SettingsTab):
""" """
Constructor Constructor
""" """
self.mediaPlayers = self.media_controller.mediaPlayers self.media_players = self.media_controller.media_players
self.savedUsedPlayers = None self.savedUsedPlayers = None
self.iconPath = u':/media/multimedia-player.png' self.iconPath = u':/media/multimedia-player.png'
player_translated = translate('OpenLP.PlayerTab', 'Players') player_translated = translate('OpenLP.PlayerTab', 'Players')
@ -171,7 +171,7 @@ class PlayerTab(SettingsTab):
self.playerCheckBoxes[u'%s' % player].setEnabled(False) self.playerCheckBoxes[u'%s' % player].setEnabled(False)
else: else:
self.playerCheckBoxes[u'%s' % player].setEnabled(True) self.playerCheckBoxes[u'%s' % player].setEnabled(True)
self.playerOrderlistWidget.addItem(self.mediaPlayers[unicode(player)].original_name) self.playerOrderlistWidget.addItem(self.media_players[unicode(player)].original_name)
def onUpButtonClicked(self): def onUpButtonClicked(self):
""" """
@ -232,13 +232,13 @@ class PlayerTab(SettingsTab):
Registry().execute(u'mediaitem_media_rebuild') Registry().execute(u'mediaitem_media_rebuild')
Registry().execute(u'config_screen_changed') Registry().execute(u'config_screen_changed')
def postSetUp(self, postUpdate=False): def post_set_up(self):
""" """
Late setup for players as the MediaController has to be initialised Late setup for players as the MediaController has to be initialised
first. first.
""" """
for key, player in self.mediaPlayers.iteritems(): for key, player in self.media_players.iteritems():
player = self.mediaPlayers[key] player = self.media_players[key]
checkbox = MediaQCheckBox(self.mediaPlayerGroupBox) checkbox = MediaQCheckBox(self.mediaPlayerGroupBox)
checkbox.setEnabled(player.available) checkbox.setEnabled(player.available)
checkbox.setObjectName(player.name + u'CheckBox') checkbox.setObjectName(player.name + u'CheckBox')
@ -258,8 +258,8 @@ class PlayerTab(SettingsTab):
""" """
Translations for players is dependent on their setup as well Translations for players is dependent on their setup as well
""" """
for key in self.mediaPlayers: for key in self.media_players:
player = self.mediaPlayers[key] player = self.media_players[key]
checkbox = self.playerCheckBoxes[player.name] checkbox = self.playerCheckBoxes[player.name]
checkbox.setPlayerName(player.name) checkbox.setPlayerName(player.name)
if player.available: if player.available:

View File

@ -122,7 +122,7 @@ class VlcPlayer(MediaPlayer):
command_line_options = u'--no-video-title-show' command_line_options = u'--no-video-title-show'
if not display.hasAudio: if not display.hasAudio:
command_line_options += u' --no-audio --no-video-title-show' command_line_options += u' --no-audio --no-video-title-show'
if Settings().value(u'advanced/hide mouse') and display.controller.isLive: if Settings().value(u'advanced/hide mouse') and display.controller.is_live:
command_line_options += u' --mouse-hide-timeout=0' command_line_options += u' --mouse-hide-timeout=0'
display.vlcInstance = vlc.Instance(command_line_options) display.vlcInstance = vlc.Instance(command_line_options)
# creating an empty vlc media player # creating an empty vlc media player

View File

@ -307,8 +307,8 @@ class WebkitPlayer(MediaPlayer):
""" """
Set up the player Set up the player
""" """
display.webView.resize(display.size()) display.web_view.resize(display.size())
display.webView.raise_() display.web_view.raise_()
self.hasOwnWidget = False self.hasOwnWidget = False
def check_available(self): def check_available(self):
@ -333,7 +333,7 @@ class WebkitPlayer(MediaPlayer):
loop = u'true' loop = u'true'
else: else:
loop = u'false' loop = u'false'
display.webView.setVisible(True) display.web_view.setVisible(True)
if controller.media_info.file_info.suffix() == u'swf': if controller.media_info.file_info.suffix() == u'swf':
controller.media_info.is_flash = True controller.media_info.is_flash = True
js = u'show_flash("load","%s");' % (path.replace(u'\\', u'\\\\')) js = u'show_flash("load","%s");' % (path.replace(u'\\', u'\\\\'))
@ -346,14 +346,14 @@ class WebkitPlayer(MediaPlayer):
""" """
Resize the player Resize the player
""" """
display.webView.resize(display.size()) display.web_view.resize(display.size())
def play(self, display): def play(self, display):
""" """
Play a video Play a video
""" """
controller = display.controller controller = display.controller
display.webLoaded = True display.web_loaded = True
length = 0 length = 0
start_time = 0 start_time = 0
if self.state != MediaState.Paused and controller.media_info.start_time > 0: if self.state != MediaState.Paused and controller.media_info.start_time > 0:
@ -368,7 +368,7 @@ class WebkitPlayer(MediaPlayer):
# TODO add playing check and get the correct media length # TODO add playing check and get the correct media length
controller.media_info.length = length controller.media_info.length = length
self.state = MediaState.Playing self.state = MediaState.Playing
display.webView.raise_() display.web_view.raise_()
return True return True
def pause(self, display): def pause(self, display):

View File

@ -406,7 +406,7 @@ class PrintServiceForm(QtGui.QDialog, Ui_PrintServiceDialog):
# Only continue when we include the song's text. # Only continue when we include the song's text.
if not self.slideTextCheckBox.isChecked(): if not self.slideTextCheckBox.isChecked():
return return
for item in self.service_manager.serviceItems: for item in self.service_manager.service_items:
# Trigger Audit requests # Trigger Audit requests
Registry().register_function(u'print_service_started', [item[u'service_item']]) Registry().register_function(u'print_service_started', [item[u'service_item']])

View File

@ -152,52 +152,52 @@ class ServiceManagerDialog(object):
# Add the bottom toolbar # Add the bottom toolbar
self.order_toolbar = OpenLPToolbar(self) self.order_toolbar = OpenLPToolbar(self)
action_list = ActionList.get_instance() 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', self.service_manager_list.moveTop = self.order_toolbar.addToolbarAction(u'moveTop',
text=translate('OpenLP.ServiceManager', 'Move to &top'), icon=u':/services/service_top.png', 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.'), 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', self.service_manager_list.moveUp = self.order_toolbar.addToolbarAction(u'moveUp',
text=translate('OpenLP.ServiceManager', 'Move &up'), icon=u':/services/service_up.png', text=translate('OpenLP.ServiceManager', 'Move &up'), icon=u':/services/service_up.png',
tooltip=translate('OpenLP.ServiceManager', 'Move item up one position in the service.'), 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', self.service_manager_list.moveDown = self.order_toolbar.addToolbarAction(u'moveDown',
text=translate('OpenLP.ServiceManager', 'Move &down'), icon=u':/services/service_down.png', text=translate('OpenLP.ServiceManager', 'Move &down'), icon=u':/services/service_down.png',
tooltip=translate('OpenLP.ServiceManager', 'Move item down one position in the service.'), 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', self.service_manager_list.moveBottom = self.order_toolbar.addToolbarAction(u'moveBottom',
text=translate('OpenLP.ServiceManager', 'Move to &bottom'), icon=u':/services/service_bottom.png', 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.'), 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', 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, 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) action_list.add_action(self.service_manager_list.down)
self.service_manager_list.up = self.order_toolbar.addToolbarAction(u'up', self.service_manager_list.up = self.order_toolbar.addToolbarAction(u'up',
text=translate('OpenLP.ServiceManager', 'Move up'), tooltip=translate('OpenLP.ServiceManager', text=translate('OpenLP.ServiceManager', 'Move up'), can_shortcuts=True,
'Moves the selection up the window.'), visible=False, shortcuts=[QtCore.Qt.Key_Up], tooltip=translate('OpenLP.ServiceManager', 'Moves the selection up the window.'), visible=False,
triggers=self.on_move_selection_up) triggers=self.on_move_selection_up)
action_list.add_action(self.service_manager_list.up) action_list.add_action(self.service_manager_list.up)
self.order_toolbar.addSeparator() 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', text=translate('OpenLP.ServiceManager', '&Delete From Service'), icon=u':/general/general_delete.png',
tooltip=translate('OpenLP.ServiceManager', 'Delete the selected item from the service.'), 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.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', text=translate('OpenLP.ServiceManager', '&Expand all'), icon=u':/services/service_expand_all.png',
tooltip=translate('OpenLP.ServiceManager', 'Expand all the service items.'), tooltip=translate('OpenLP.ServiceManager', 'Expand all the service items.'),
shortcuts=[QtCore.Qt.Key_Plus], category=UiStrings().Service, triggers=self.onExpandAll) category=UiStrings().Service, triggers=self.onExpandAll)
self.service_manager_list.collapse = self.order_toolbar.addToolbarAction(u'collapse', 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', text=translate('OpenLP.ServiceManager', '&Collapse all'), icon=u':/services/service_collapse_all.png',
tooltip=translate('OpenLP.ServiceManager', 'Collapse all the service items.'), 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.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', text=translate('OpenLP.ServiceManager', 'Go Live'), icon=u':/general/general_live.png',
tooltip=translate('OpenLP.ServiceManager', 'Send the selected item to Live.'), 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) triggers=self.make_live)
self.layout.addWidget(self.order_toolbar) self.layout.addWidget(self.order_toolbar)
# Connect up our signals and slots # Connect up our signals and slots

View File

@ -50,6 +50,7 @@ class SettingsForm(QtGui.QDialog, Ui_SettingsDialog):
Initialise the settings form Initialise the settings form
""" """
Registry().register(u'settings_form', self) Registry().register(u'settings_form', self)
Registry().register_function(u'bootstrap_post_set_up', self.post_set_up)
QtGui.QDialog.__init__(self, parent) QtGui.QDialog.__init__(self, parent)
self.setupUi(self) self.setupUi(self)
# General tab # General tab
@ -75,7 +76,7 @@ class SettingsForm(QtGui.QDialog, Ui_SettingsDialog):
self.insertTab(self.advancedTab, 2, PluginStatus.Active) self.insertTab(self.advancedTab, 2, PluginStatus.Active)
self.insertTab(self.playerTab, 3, PluginStatus.Active) self.insertTab(self.playerTab, 3, PluginStatus.Active)
count = 4 count = 4
for plugin in self.plugins: for plugin in self.plugin_manager.plugins:
if plugin.settingsTab: if plugin.settingsTab:
self.insertTab(plugin.settingsTab, count, plugin.status) self.insertTab(plugin.settingsTab, count, plugin.status)
count += 1 count += 1
@ -118,17 +119,17 @@ class SettingsForm(QtGui.QDialog, Ui_SettingsDialog):
self.stackedLayout.widget(tabIndex).cancel() self.stackedLayout.widget(tabIndex).cancel()
return QtGui.QDialog.reject(self) return QtGui.QDialog.reject(self)
def postSetUp(self): def post_set_up(self):
""" """
Run any post-setup code for the tabs on the form Run any post-setup code for the tabs on the form
""" """
self.generalTab.postSetUp() self.generalTab.post_set_up()
self.themesTab.postSetUp() self.themesTab.post_set_up()
self.advancedTab.postSetUp() self.advancedTab.post_set_up()
self.playerTab.postSetUp() self.playerTab.post_set_up()
for plugin in self.plugins: for plugin in self.plugin_manager.plugins:
if plugin.settingsTab: if plugin.settingsTab:
plugin.settingsTab.postSetUp() plugin.settingsTab.post_set_up()
def tabChanged(self, tabIndex): def tabChanged(self, tabIndex):
""" """
@ -166,3 +167,13 @@ class SettingsForm(QtGui.QDialog, Ui_SettingsDialog):
return self._service_manager return self._service_manager
service_manager = property(_get_service_manager) service_manager = property(_get_service_manager)
def _get_plugin_manager(self):
"""
Adds the plugin manager to the class dynamically
"""
if not hasattr(self, u'_plugin_manager'):
self._plugin_manager = Registry().get(u'plugin_manager')
return self._plugin_manager
plugin_manager = property(_get_plugin_manager)

View File

@ -56,8 +56,8 @@ class ShortcutListForm(QtGui.QDialog, Ui_ShortcutListDialog):
self.setupUi(self) self.setupUi(self)
self.changedActions = {} self.changedActions = {}
self.action_list = ActionList.get_instance() self.action_list = ActionList.get_instance()
QtCore.QObject.connect(self.primaryPushButton, QtCore.SIGNAL(u'toggled(bool)'), self.dialog_was_shown = False
self.onPrimaryPushButtonClicked) QtCore.QObject.connect(self.primaryPushButton, QtCore.SIGNAL(u'toggled(bool)'), self.onPrimaryPushButtonClicked)
QtCore.QObject.connect(self.alternatePushButton, QtCore.SIGNAL(u'toggled(bool)'), QtCore.QObject.connect(self.alternatePushButton, QtCore.SIGNAL(u'toggled(bool)'),
self.onAlternatePushButtonClicked) self.onAlternatePushButtonClicked)
QtCore.QObject.connect(self.treeWidget, QtCore.QObject.connect(self.treeWidget,
@ -72,8 +72,7 @@ class ShortcutListForm(QtGui.QDialog, Ui_ShortcutListDialog):
self.onRestoreDefaultsClicked) self.onRestoreDefaultsClicked)
QtCore.QObject.connect(self.defaultRadioButton, QtCore.SIGNAL(u'clicked(bool)'), QtCore.QObject.connect(self.defaultRadioButton, QtCore.SIGNAL(u'clicked(bool)'),
self.onDefaultRadioButtonClicked) self.onDefaultRadioButtonClicked)
QtCore.QObject.connect(self.customRadioButton, QtCore.SIGNAL(u'clicked(bool)'), QtCore.QObject.connect(self.customRadioButton, QtCore.SIGNAL(u'clicked(bool)'), self.onCustomRadioButtonClicked)
self.onCustomRadioButtonClicked)
def keyPressEvent(self, event): def keyPressEvent(self, event):
""" """
@ -93,9 +92,12 @@ class ShortcutListForm(QtGui.QDialog, Ui_ShortcutListDialog):
""" """
if not self.primaryPushButton.isChecked() and not self.alternatePushButton.isChecked(): if not self.primaryPushButton.isChecked() and not self.alternatePushButton.isChecked():
return 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() key = event.key()
if key == QtCore.Qt.Key_Shift or key == QtCore.Qt.Key_Control or \ if key in (QtCore.Qt.Key_Shift, QtCore.Qt.Key_Control, QtCore.Qt.Key_Meta, QtCore.Qt.Key_Alt):
key == QtCore.Qt.Key_Meta or key == QtCore.Qt.Key_Alt:
return return
key_string = QtGui.QKeySequence(key).toString() key_string = QtGui.QKeySequence(key).toString()
if event.modifiers() & QtCore.Qt.ControlModifier == QtCore.Qt.ControlModifier: 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) key_sequence = QtGui.QKeySequence(key_string)
if self._validiate_shortcut(self._currentItemAction(), key_sequence): if self._validiate_shortcut(self._currentItemAction(), key_sequence):
if self.primaryPushButton.isChecked(): if self.primaryPushButton.isChecked():
self._adjustButton(self.primaryPushButton, self._adjustButton(self.primaryPushButton, False, text=key_sequence.toString())
False, text=key_sequence.toString())
elif self.alternatePushButton.isChecked(): elif self.alternatePushButton.isChecked():
self._adjustButton(self.alternatePushButton, self._adjustButton(self.alternatePushButton, False, text=key_sequence.toString())
False, text=key_sequence.toString())
def exec_(self): def exec_(self):
""" """
@ -147,8 +147,8 @@ class ShortcutListForm(QtGui.QDialog, Ui_ShortcutListDialog):
def refreshShortcutList(self): def refreshShortcutList(self):
""" """
This refreshes the item's shortcuts shown in the list. Note, this This refreshes the item's shortcuts shown in the list. Note, this neither adds new actions nor removes old
neither adds new actions nor removes old actions. actions.
""" """
iterator = QtGui.QTreeWidgetItemIterator(self.treeWidget) iterator = QtGui.QTreeWidgetItemIterator(self.treeWidget)
while iterator.value(): while iterator.value():
@ -204,21 +204,19 @@ class ShortcutListForm(QtGui.QDialog, Ui_ShortcutListDialog):
new_shortcuts = [] new_shortcuts = []
if shortcuts: if shortcuts:
new_shortcuts.append(shortcuts[0]) new_shortcuts.append(shortcuts[0])
new_shortcuts.append( new_shortcuts.append(QtGui.QKeySequence(self.alternatePushButton.text()))
QtGui.QKeySequence(self.alternatePushButton.text()))
self.changedActions[action] = new_shortcuts self.changedActions[action] = new_shortcuts
if not self.primaryPushButton.text(): if not self.primaryPushButton.text():
# When we do not have a primary shortcut, the just entered alternate # When we do not have a primary shortcut, the just entered alternate shortcut will automatically become the
# shortcut will automatically become the primary shortcut. That is # primary shortcut. That is why we have to adjust the primary button's text.
# why we have to adjust the primary button's text.
self.primaryPushButton.setText(self.alternatePushButton.text()) self.primaryPushButton.setText(self.alternatePushButton.text())
self.alternatePushButton.setText(u'') self.alternatePushButton.setText(u'')
self.refreshShortcutList() self.refreshShortcutList()
def onItemDoubleClicked(self, item, column): def onItemDoubleClicked(self, item, column):
""" """
A item has been double clicked. The ``primaryPushButton`` will be A item has been double clicked. The ``primaryPushButton`` will be checked and the item's shortcut will be
checked and the item's shortcut will be displayed. displayed.
""" """
action = self._currentItemAction(item) action = self._currentItemAction(item)
if action is None: if action is None:
@ -234,8 +232,7 @@ class ShortcutListForm(QtGui.QDialog, Ui_ShortcutListDialog):
def onCurrentItemChanged(self, item=None, previousItem=None): def onCurrentItemChanged(self, item=None, previousItem=None):
""" """
A item has been pressed. We adjust the button's text to the action's A item has been pressed. We adjust the button's text to the action's shortcut which is encapsulate in the item.
shortcut which is encapsulate in the item.
""" """
action = self._currentItemAction(item) action = self._currentItemAction(item)
self.primaryPushButton.setEnabled(action is not None) self.primaryPushButton.setEnabled(action is not None)
@ -253,9 +250,8 @@ class ShortcutListForm(QtGui.QDialog, Ui_ShortcutListDialog):
if len(action.defaultShortcuts) == 2: if len(action.defaultShortcuts) == 2:
alternate_label_text = action.defaultShortcuts[1].toString() alternate_label_text = action.defaultShortcuts[1].toString()
shortcuts = self._actionShortcuts(action) shortcuts = self._actionShortcuts(action)
# We do not want to loose pending changes, that is why we have to # We do not want to loose pending changes, that is why we have to keep the text when, this function has not
# keep the text when, this function has not been triggered by a # been triggered by a signal.
# signal.
if item is None: if item is None:
primary_text = self.primaryPushButton.text() primary_text = self.primaryPushButton.text()
alternate_text = self.alternatePushButton.text() alternate_text = self.alternatePushButton.text()
@ -264,8 +260,7 @@ class ShortcutListForm(QtGui.QDialog, Ui_ShortcutListDialog):
elif len(shortcuts) == 2: elif len(shortcuts) == 2:
primary_text = shortcuts[0].toString() primary_text = shortcuts[0].toString()
alternate_text = shortcuts[1].toString() alternate_text = shortcuts[1].toString()
# When we are capturing a new shortcut, we do not want, the buttons to # When we are capturing a new shortcut, we do not want, the buttons to display the current shortcut.
# display the current shortcut.
if self.primaryPushButton.isChecked(): if self.primaryPushButton.isChecked():
primary_text = u'' primary_text = u''
if self.alternatePushButton.isChecked(): if self.alternatePushButton.isChecked():
@ -274,8 +269,7 @@ class ShortcutListForm(QtGui.QDialog, Ui_ShortcutListDialog):
self.alternatePushButton.setText(alternate_text) self.alternatePushButton.setText(alternate_text)
self.primaryLabel.setText(primary_label_text) self.primaryLabel.setText(primary_label_text)
self.alternateLabel.setText(alternate_label_text) self.alternateLabel.setText(alternate_label_text)
# We do not want to toggle and radio button, as the function has not # We do not want to toggle and radio button, as the function has not been triggered by a signal.
# been triggered by a signal.
if item is None: if item is None:
return return
if primary_label_text == primary_text and alternate_label_text == alternate_text: 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): def onDefaultRadioButtonClicked(self, toggled):
""" """
The default radio button has been clicked, which means we have to make The default radio button has been clicked, which means we have to make sure, that we use the default shortcuts
sure, that we use the default shortcuts for the action. for the action.
""" """
if not toggled: if not toggled:
return return
@ -325,9 +319,8 @@ class ShortcutListForm(QtGui.QDialog, Ui_ShortcutListDialog):
def onCustomRadioButtonClicked(self, toggled): def onCustomRadioButtonClicked(self, toggled):
""" """
The custom shortcut radio button was clicked, thus we have to restore The custom shortcut radio button was clicked, thus we have to restore the custom shortcuts by calling those
the custom shortcuts by calling those functions triggered by button functions triggered by button clicks.
clicks.
""" """
if not toggled: if not toggled:
return return
@ -337,8 +330,8 @@ class ShortcutListForm(QtGui.QDialog, Ui_ShortcutListDialog):
def save(self): def save(self):
""" """
Save the shortcuts. **Note**, that we do not have to load the shortcuts, Save the shortcuts. **Note**, that we do not have to load the shortcuts, as they are loaded in
as they are loaded in :class:`~openlp.core.utils.ActionList`. :class:`~openlp.core.utils.ActionList`.
""" """
settings = Settings() settings = Settings()
settings.beginGroup(u'shortcuts') settings.beginGroup(u'shortcuts')
@ -348,8 +341,7 @@ class ShortcutListForm(QtGui.QDialog, Ui_ShortcutListDialog):
continue continue
for action in category.actions: for action in category.actions:
if action in self.changedActions: if action in self.changedActions:
old_shortcuts = map(unicode, old_shortcuts = map(QtGui.QKeySequence.toString, action.shortcuts())
map(QtGui.QKeySequence.toString, action.shortcuts()))
action.setShortcuts(self.changedActions[action]) action.setShortcuts(self.changedActions[action])
self.action_list.update_shortcut_map(action, old_shortcuts) self.action_list.update_shortcut_map(action, old_shortcuts)
settings.setValue(action.objectName(), action.shortcuts()) settings.setValue(action.objectName(), action.shortcuts())
@ -367,13 +359,10 @@ class ShortcutListForm(QtGui.QDialog, Ui_ShortcutListDialog):
new_shortcuts = [] new_shortcuts = []
if action.defaultShortcuts: if action.defaultShortcuts:
new_shortcuts.append(action.defaultShortcuts[0]) new_shortcuts.append(action.defaultShortcuts[0])
# We have to check if the primary default shortcut is available. But # We have to check if the primary default shortcut is available. But we only have to check, if the action
# we only have to check, if the action has a default primary # has a default primary shortcut (an "empty" shortcut is always valid and if the action does not have a
# shortcut (an "empty" shortcut is always valid and if the action # default primary shortcut, then the alternative shortcut (not the default one) will become primary
# does not have a default primary shortcut, then the alternative # shortcut, thus the check will assume that an action were going to have the same shortcut twice.
# 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]: if not self._validiate_shortcut(action, new_shortcuts[0]) and new_shortcuts[0] != shortcuts[0]:
return return
if len(shortcuts) == 2: if len(shortcuts) == 2:
@ -405,9 +394,8 @@ class ShortcutListForm(QtGui.QDialog, Ui_ShortcutListDialog):
def _validiate_shortcut(self, changing_action, key_sequence): def _validiate_shortcut(self, changing_action, key_sequence):
""" """
Checks if the given ``changing_action `` can use the given Checks if the given ``changing_action `` can use the given ``key_sequence``. Returns ``True`` if the
``key_sequence``. Returns ``True`` if the ``key_sequence`` can be used ``key_sequence`` can be used by the action, otherwise displays a dialog and returns ``False``.
by the action, otherwise displays a dialog and returns ``False``.
``changing_action`` ``changing_action``
The action which wants to use the ``key_sequence``. The action which wants to use the ``key_sequence``.
@ -429,11 +417,9 @@ class ShortcutListForm(QtGui.QDialog, Ui_ShortcutListDialog):
# Have the same parent, thus they cannot have the same shortcut. # Have the same parent, thus they cannot have the same shortcut.
if action.parent() is changing_action.parent(): if action.parent() is changing_action.parent():
is_valid = False is_valid = False
# The new shortcut is already assigned, but if both shortcuts # The new shortcut is already assigned, but if both shortcuts are only valid in a different widget the
# are only valid in a different widget the new shortcut is # new shortcut is vaild, because they will not interfere.
# vaild, because they will not interfere. if action.shortcutContext() in [QtCore.Qt.WindowShortcut, QtCore.Qt.ApplicationShortcut]:
if action.shortcutContext() in [QtCore.Qt.WindowShortcut,
QtCore.Qt.ApplicationShortcut]:
is_valid = False is_valid = False
if changing_action.shortcutContext() in [QtCore.Qt.WindowShortcut, QtCore.Qt.ApplicationShortcut]: if changing_action.shortcutContext() in [QtCore.Qt.WindowShortcut, QtCore.Qt.ApplicationShortcut]:
is_valid = False is_valid = False
@ -443,13 +429,13 @@ class ShortcutListForm(QtGui.QDialog, Ui_ShortcutListDialog):
'The shortcut "%s" is already assigned to another action, please use a different shortcut.') % 'The shortcut "%s" is already assigned to another action, please use a different shortcut.') %
key_sequence.toString() key_sequence.toString()
) )
self.dialog_was_shown = True
return is_valid return is_valid
def _actionShortcuts(self, action): def _actionShortcuts(self, action):
""" """
This returns the shortcuts for the given ``action``, which also includes This returns the shortcuts for the given ``action``, which also includes those shortcuts which are not saved
those shortcuts which are not saved yet but already assigned (as changes yet but already assigned (as changes yre applied when closing the dialog).
are applied when closing the dialog).
""" """
if action in self.changedActions: if action in self.changedActions:
return self.changedActions[action] return self.changedActions[action]
@ -457,8 +443,8 @@ class ShortcutListForm(QtGui.QDialog, Ui_ShortcutListDialog):
def _currentItemAction(self, item=None): def _currentItemAction(self, item=None):
""" """
Returns the action of the given ``item``. If no item is given, we return Returns the action of the given ``item``. If no item is given, we return the action of the current item of
the action of the current item of the ``treeWidget``. the ``treeWidget``.
""" """
if item is None: if item is None:
item = self.treeWidget.currentItem() item = self.treeWidget.currentItem()
@ -487,3 +473,4 @@ class ShortcutListForm(QtGui.QDialog, Ui_ShortcutListDialog):
return self._main_window return self._main_window
main_window = property(_get_main_window) main_window = property(_get_main_window)

File diff suppressed because it is too large Load Diff

View File

@ -38,9 +38,8 @@ import re
from xml.etree.ElementTree import ElementTree, XML from xml.etree.ElementTree import ElementTree, XML
from PyQt4 import QtCore, QtGui from PyQt4 import QtCore, QtGui
from openlp.core.lib import ImageSource, OpenLPToolbar, Registry, SettingsManager, Settings, UiStrings, \ from openlp.core.lib import ImageSource, OpenLPToolbar, Registry, Settings, UiStrings, get_text_file_string, \
get_text_file_string, build_icon, translate, check_item_selected, check_directory_exists, create_thumb, \ build_icon, translate, check_item_selected, check_directory_exists, create_thumb, validate_thumb
validate_thumb
from openlp.core.lib.theme import ThemeXML, BackgroundType, VerticalType, BackgroundGradientType 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.lib.ui import critical_error_message_box, create_widget_action
from openlp.core.theme import Theme from openlp.core.theme import Theme
@ -60,6 +59,7 @@ class ThemeManager(QtGui.QWidget):
""" """
QtGui.QWidget.__init__(self, parent) QtGui.QWidget.__init__(self, parent)
Registry().register(u'theme_manager', self) Registry().register(u'theme_manager', self)
Registry().register_function(u'bootstrap_initialise', self.load_first_time_themes)
self.settingsSection = u'themes' self.settingsSection = u'themes'
self.themeForm = ThemeForm(self) self.themeForm = ThemeForm(self)
self.fileRenameForm = FileRenameForm() self.fileRenameForm = FileRenameForm()
@ -145,18 +145,6 @@ class ThemeManager(QtGui.QWidget):
# Last little bits of setting up # Last little bits of setting up
self.config_updated() self.config_updated()
def first_time(self):
"""
Import new themes downloaded by the first time wizard
"""
self.application.set_busy_cursor()
files = SettingsManager.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): def config_updated(self):
""" """
Triggered when Config dialog is updated. Triggered when Config dialog is updated.
@ -265,8 +253,8 @@ class ThemeManager(QtGui.QWidget):
self.cloneThemeData(old_theme_data, new_theme_name) self.cloneThemeData(old_theme_data, new_theme_name)
self.delete_theme(old_theme_name) self.delete_theme(old_theme_name)
for plugin in self.plugin_manager.plugins: for plugin in self.plugin_manager.plugins:
if plugin.usesTheme(old_theme_name): if plugin.uses_theme(old_theme_name):
plugin.renameTheme(old_theme_name, new_theme_name) plugin.rename_theme(old_theme_name, new_theme_name)
self.renderer.update_theme(new_theme_name, old_theme_name) self.renderer.update_theme(new_theme_name, old_theme_name)
self.load_themes() self.load_themes()
@ -292,8 +280,7 @@ class ThemeManager(QtGui.QWidget):
save_to = None save_to = None
save_from = None save_from = None
if theme_data.background_type == u'image': if theme_data.background_type == u'image':
save_to = os.path.join(self.path, new_theme_name, save_to = os.path.join(self.path, new_theme_name, os.path.split(unicode(theme_data.background_filename))[1])
os.path.split(unicode(theme_data.background_filename))[1])
save_from = theme_data.background_filename save_from = theme_data.background_filename
theme_data.theme_name = new_theme_name theme_data.theme_name = new_theme_name
theme_data.extend_image_filename(self.path) theme_data.extend_image_filename(self.path)
@ -389,7 +376,6 @@ class ThemeManager(QtGui.QWidget):
theme_zip.close() theme_zip.close()
self.application.set_normal_cursor() self.application.set_normal_cursor()
def on_import_theme(self): def on_import_theme(self):
""" """
Opens a file dialog to select the theme file(s) to import before Opens a file dialog to select the theme file(s) to import before
@ -410,19 +396,17 @@ class ThemeManager(QtGui.QWidget):
self.load_themes() self.load_themes()
self.application.set_normal_cursor() self.application.set_normal_cursor()
def load_themes(self, first_time=False): def load_first_time_themes(self):
""" """
Loads the theme lists and triggers updates accross the whole system Imports any themes on start up and makes sure there is at least one theme
using direct calls or core functions and events for the plugins.
The plugins will call back in to get the real list if they want it.
""" """
log.debug(u'Load themes from dir') self.application.set_busy_cursor()
self.theme_list = [] files = AppLocation.get_files(self.settingsSection, u'.otz')
self.theme_list_widget.clear() for theme_file in files:
files = SettingsManager.get_files(self.settingsSection, u'.png') theme_file = os.path.join(self.path, theme_file)
if first_time: self.unzip_theme(theme_file, self.path)
self.first_time() delete_file(theme_file)
files = SettingsManager.get_files(self.settingsSection, u'.png') files = AppLocation.get_files(self.settingsSection, u'.png')
# No themes have been found so create one # No themes have been found so create one
if not files: if not files:
theme = ThemeXML() theme = ThemeXML()
@ -430,7 +414,19 @@ class ThemeManager(QtGui.QWidget):
self._write_theme(theme, None, None) self._write_theme(theme, None, None)
Settings().setValue(self.settingsSection + u'/global theme', theme.theme_name) Settings().setValue(self.settingsSection + u'/global theme', theme.theme_name)
self.config_updated() self.config_updated()
files = SettingsManager.get_files(self.settingsSection, u'.png') self.application.set_normal_cursor()
self.load_themes()
def load_themes(self):
"""
Loads the theme lists and triggers updates across the whole system
using direct calls or core functions and events for the plugins.
The plugins will call back in to get the real list if they want it.
"""
log.debug(u'Load themes from dir')
self.theme_list = []
self.theme_list_widget.clear()
files = AppLocation.get_files(self.settingsSection, u'.png')
# Sort the themes by its name considering language specific # Sort the themes by its name considering language specific
files.sort(key=lambda file_name: unicode(file_name), cmp=locale_compare) files.sort(key=lambda file_name: unicode(file_name), cmp=locale_compare)
# now process the file list of png files # now process the file list of png files
@ -751,7 +747,7 @@ class ThemeManager(QtGui.QWidget):
# check for use in the system else where. # check for use in the system else where.
if testPlugin: if testPlugin:
for plugin in self.plugin_manager.plugins: for plugin in self.plugin_manager.plugins:
if plugin.usesTheme(theme): if plugin.uses_theme(theme):
critical_error_message_box(translate('OpenLP.ThemeManager', 'Validation Error'), critical_error_message_box(translate('OpenLP.ThemeManager', 'Validation Error'),
translate('OpenLP.ThemeManager', 'Theme %s is used in the %s plugin.') % translate('OpenLP.ThemeManager', 'Theme %s is used in the %s plugin.') %
(theme, plugin.name)) (theme, plugin.name))

View File

@ -155,7 +155,7 @@ class ThemesTab(SettingsTab):
self.renderer.set_theme_level(self.theme_level) self.renderer.set_theme_level(self.theme_level)
Registry().execute(u'theme_update_global', self.global_theme) Registry().execute(u'theme_update_global', self.global_theme)
def postSetUp(self): def post_set_up(self):
""" """
After setting things up... After setting things up...
""" """

View File

@ -39,9 +39,10 @@ from subprocess import Popen, PIPE
import sys import sys
import urllib2 import urllib2
from PyQt4 import QtGui, QtCore
from openlp.core.lib import Registry, Settings from openlp.core.lib import Registry, Settings
from PyQt4 import QtGui, QtCore
if sys.platform != u'win32' and sys.platform != u'darwin': if sys.platform != u'win32' and sys.platform != u'darwin':
try: try:
@ -50,8 +51,7 @@ if sys.platform != u'win32' and sys.platform != u'darwin':
except ImportError: except ImportError:
XDG_BASE_AVAILABLE = False XDG_BASE_AVAILABLE = False
import openlp from openlp.core.lib import translate
from openlp.core.lib import translate, check_directory_exists
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
APPLICATION_VERSION = {} APPLICATION_VERSION = {}
@ -78,108 +78,6 @@ class VersionThread(QtCore.QThread):
if LooseVersion(str(version)) > LooseVersion(str(app_version[u'full'])): if LooseVersion(str(version)) > LooseVersion(str(app_version[u'full'])):
Registry().execute(u'openlp_version_check', u'%s' % version) 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
SharedData = 8
# 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 or dir_type == AppLocation.SharedData:
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 or dir_type == AppLocation.SharedData:
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 or dir_type == AppLocation.SharedData:
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): def _get_frozen_path(frozen_option, non_frozen_option):
""" """
@ -437,11 +335,11 @@ def get_uno_command():
Returns the UNO command to launch an openoffice.org instance. Returns the UNO command to launch an openoffice.org instance.
""" """
COMMAND = u'soffice' COMMAND = u'soffice'
OPTIONS = u'-nologo -norestore -minimized -nodefault -nofirststartwizard' OPTIONS = u'--nologo --norestore --minimized --nodefault --nofirststartwizard'
if UNO_CONNECTION_TYPE == u'pipe': if UNO_CONNECTION_TYPE == u'pipe':
CONNECTION = u'"-accept=pipe,name=openlp_pipe;urp;"' CONNECTION = u'"--accept=pipe,name=openlp_pipe;urp;"'
else: else:
CONNECTION = u'"-accept=socket,host=localhost,port=2002;urp;"' CONNECTION = u'"--accept=socket,host=localhost,port=2002;urp;"'
return u'%s %s %s' % (COMMAND, OPTIONS, CONNECTION) return u'%s %s %s' % (COMMAND, OPTIONS, CONNECTION)
@ -498,9 +396,11 @@ def locale_compare(string1, string2):
locale_direct_compare = locale.strcoll locale_direct_compare = locale.strcoll
from applocation import AppLocation
from languagemanager import LanguageManager from languagemanager import LanguageManager
from actions import ActionList from actions import ActionList
__all__ = [u'AppLocation', u'ActionList', u'LanguageManager', u'get_application_version', u'check_latest_version', __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'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'] u'delete_file', u'clean_filename', u'format_time', u'locale_compare', u'locale_direct_compare']

View File

@ -37,8 +37,8 @@ from openlp.core.lib import Settings
class ActionCategory(object): class ActionCategory(object):
""" """
The :class:`~openlp.core.utils.ActionCategory` class encapsulates a The :class:`~openlp.core.utils.ActionCategory` class encapsulates a category for the
category for the :class:`~openlp.core.utils.CategoryList` class. :class:`~openlp.core.utils.CategoryList` class.
""" """
def __init__(self, name, weight=0): def __init__(self, name, weight=0):
""" """
@ -51,8 +51,7 @@ class ActionCategory(object):
class CategoryActionList(object): class CategoryActionList(object):
""" """
The :class:`~openlp.core.utils.CategoryActionList` class provides a sorted The :class:`~openlp.core.utils.CategoryActionList` class provides a sorted list of actions within a category.
list of actions within a category.
""" """
def __init__(self): def __init__(self):
""" """
@ -142,9 +141,9 @@ class CategoryActionList(object):
class CategoryList(object): class CategoryList(object):
""" """
The :class:`~openlp.core.utils.CategoryList` class encapsulates a category The :class:`~openlp.core.utils.CategoryList` class encapsulates a category list for the
list for the :class:`~openlp.core.utils.ActionList` class and provides an :class:`~openlp.core.utils.ActionList` class and provides an iterator interface for walking through the list of
iterator interface for walking through the list of actions in this category. actions in this category.
""" """
def __init__(self): def __init__(self):
@ -244,10 +243,9 @@ class CategoryList(object):
class ActionList(object): class ActionList(object):
""" """
The :class:`~openlp.core.utils.ActionList` class contains a list of menu The :class:`~openlp.core.utils.ActionList` class contains a list of menu actions and categories associated with
actions and categories associated with those actions. Each category also those actions. Each category also has a weight by which it is sorted when iterating through the list of actions or
has a weight by which it is sorted when iterating through the list of categories.
actions or categories.
""" """
instance = None instance = None
shortcut_map = {} shortcut_map = {}
@ -271,48 +269,44 @@ class ActionList(object):
""" """
Add an action to the list of actions. Add an action to the list of actions.
**Note**: The action's objectName must be set when you want to add it!
``action`` ``action``
The action to add (QAction). **Note**, the action must not have an The action to add (QAction). **Note**, the action must not have an empty ``objectName``.
empty ``objectName``.
``category`` ``category``
The category this action belongs to. The category has to be a python The category this action belongs to. The category has to be a python string. . **Note**, if the category
string. . **Note**, if the category is ``None``, the category and is ``None``, the category and its actions are being hidden in the shortcut dialog. However, if they are
its actions are being hidden in the shortcut dialog. However, if added, it is possible to avoid assigning shortcuts twice, which is important.
they are added, it is possible to avoid assigning shortcuts twice,
which is important.
``weight`` ``weight``
The weight specifies how important a category is. However, this only The weight specifies how important a category is. However, this only has an impact on the order the
has an impact on the order the categories are displayed. categories are displayed.
""" """
if category not in self.categories: if category not in self.categories:
self.categories.append(category) 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: if weight is None:
self.categories[category].actions.append(action) self.categories[category].actions.append(action)
else: else:
self.categories[category].actions.add(action, weight) self.categories[category].actions.add(action, weight)
# Load the shortcut from the config. # Load the shortcut from the config.
settings = Settings()
settings.beginGroup(u'shortcuts')
shortcuts = settings.value(action.objectName()) shortcuts = settings.value(action.objectName())
settings.endGroup() settings.endGroup()
if not shortcuts: if not shortcuts:
action.setShortcuts([]) action.setShortcuts([])
return return
# We have to do this to ensure that the loaded shortcut list e. g. # We have to do this to ensure that the loaded shortcut list e. g. STRG+O (German) is converted to CTRL+O,
# STRG+O (German) is converted to CTRL+O, which is only done when we # which is only done when we convert the strings in this way (QKeySequencet -> uncode).
# convert the strings in this way (QKeySequence -> QString -> unicode). shortcuts = map(QtGui.QKeySequence.toString, map(QtGui.QKeySequence, shortcuts))
shortcuts = map(QtGui.QKeySequence, shortcuts) # Check the alternate shortcut first, to avoid problems when the alternate shortcut becomes the primary shortcut
shortcuts = map(unicode, map(QtGui.QKeySequence.toString, shortcuts)) # after removing the (initial) primary shortcut due to conflicts.
# 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: if len(shortcuts) == 2:
existing_actions = ActionList.shortcut_map.get(shortcuts[1], []) existing_actions = ActionList.shortcut_map.get(shortcuts[1], [])
# Check for conflicts with other actions considering the shortcut # Check for conflicts with other actions considering the shortcut context.
# context.
if self._is_shortcut_available(existing_actions, action): if self._is_shortcut_available(existing_actions, action):
actions = ActionList.shortcut_map.get(shortcuts[1], []) actions = ActionList.shortcut_map.get(shortcuts[1], [])
actions.append(action) actions.append(action)
@ -321,28 +315,24 @@ class ActionList(object):
shortcuts.remove(shortcuts[1]) shortcuts.remove(shortcuts[1])
# Check the primary shortcut. # Check the primary shortcut.
existing_actions = ActionList.shortcut_map.get(shortcuts[0], []) existing_actions = ActionList.shortcut_map.get(shortcuts[0], [])
# Check for conflicts with other actions considering the shortcut # Check for conflicts with other actions considering the shortcut context.
# context.
if self._is_shortcut_available(existing_actions, action): if self._is_shortcut_available(existing_actions, action):
actions = ActionList.shortcut_map.get(shortcuts[0], []) actions = ActionList.shortcut_map.get(shortcuts[0], [])
actions.append(action) actions.append(action)
ActionList.shortcut_map[shortcuts[0]] = actions ActionList.shortcut_map[shortcuts[0]] = actions
else: else:
shortcuts.remove(shortcuts[0]) shortcuts.remove(shortcuts[0])
action.setShortcuts( action.setShortcuts([QtGui.QKeySequence(shortcut) for shortcut in shortcuts])
[QtGui.QKeySequence(shortcut) for shortcut in shortcuts])
def remove_action(self, action, category=None): def remove_action(self, action, category=None):
""" """
This removes an action from its category. Empty categories are This removes an action from its category. Empty categories are automatically removed.
automatically removed.
``action`` ``action``
The ``QAction`` object to be removed. The ``QAction`` object to be removed.
``category`` ``category``
The name (unicode string) of the category, which contains the The name (unicode string) of the category, which contains the action. Defaults to None.
action. Defaults to None.
""" """
if category not in self.categories: if category not in self.categories:
return return
@ -350,10 +340,9 @@ class ActionList(object):
# Remove empty categories. # Remove empty categories.
if not self.categories[category].actions: if not self.categories[category].actions:
self.categories.remove(category) self.categories.remove(category)
shortcuts = map(unicode, map(QtGui.QKeySequence.toString, action.shortcuts())) shortcuts = map(QtGui.QKeySequence.toString, action.shortcuts())
for shortcut in shortcuts: for shortcut in shortcuts:
# Remove action from the list of actions which are using this # Remove action from the list of actions which are using this shortcut.
# shortcut.
ActionList.shortcut_map[shortcut].remove(action) ActionList.shortcut_map[shortcut].remove(action)
# Remove empty entries. # Remove empty entries.
if not ActionList.shortcut_map[shortcut]: if not ActionList.shortcut_map[shortcut]:
@ -361,8 +350,7 @@ class ActionList(object):
def add_category(self, name, weight): def add_category(self, name, weight):
""" """
Add an empty category to the list of categories. This is ony convenient Add an empty category to the list of categories. This is only convenient for categories with a given weight.
for categories with a given weight.
``name`` ``name``
The category's name. The category's name.
@ -381,27 +369,24 @@ class ActionList(object):
def update_shortcut_map(self, action, old_shortcuts): def update_shortcut_map(self, action, old_shortcuts):
""" """
Remove the action for the given ``old_shortcuts`` from the Remove the action for the given ``old_shortcuts`` from the ``shortcut_map`` to ensure its up-to-dateness.
``shortcut_map`` to ensure its up-to-dateness.
**Note**: The new action's shortcuts **must** be assigned to the given **Note**: The new action's shortcuts **must** be assigned to the given ``action`` **before** calling this
``action`` **before** calling this method. method.
``action`` ``action``
The action whose shortcuts are supposed to be updated in the The action whose shortcuts are supposed to be updated in the ``shortcut_map``.
``shortcut_map``.
``old_shortcuts`` ``old_shortcuts``
A list of unicode keysequences. A list of unicode keysequences.
""" """
for old_shortcut in old_shortcuts: for old_shortcut in old_shortcuts:
# Remove action from the list of actions which are using this # Remove action from the list of actions which are using this shortcut.
# shortcut.
ActionList.shortcut_map[old_shortcut].remove(action) ActionList.shortcut_map[old_shortcut].remove(action)
# Remove empty entries. # Remove empty entries.
if not ActionList.shortcut_map[old_shortcut]: if not ActionList.shortcut_map[old_shortcut]:
del 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. # Add the new shortcuts to the map.
for new_shortcut in new_shortcuts: for new_shortcut in new_shortcuts:
existing_actions = ActionList.shortcut_map.get(new_shortcut, []) existing_actions = ActionList.shortcut_map.get(new_shortcut, [])
@ -410,8 +395,7 @@ class ActionList(object):
def _is_shortcut_available(self, existing_actions, action): def _is_shortcut_available(self, existing_actions, action):
""" """
Checks if the given ``action`` may use its assigned shortcut(s) or not. Checks if the given ``action`` may use its assigned shortcut(s) or not. Returns ``True`` or ``False.
Returns ``True`` or ``False.
``existing_actions`` ``existing_actions``
A list of actions which already use a particular shortcut. A list of actions which already use a particular shortcut.
@ -419,28 +403,29 @@ class ActionList(object):
``action`` ``action``
The action which wants to use a particular shortcut. The action which wants to use a particular shortcut.
""" """
local = action.shortcutContext() in [QtCore.Qt.WindowShortcut, QtCore.Qt.ApplicationShortcut] global_context = action.shortcutContext() in [QtCore.Qt.WindowShortcut, QtCore.Qt.ApplicationShortcut]
affected_actions = filter(lambda a: isinstance(a, QtGui.QAction), affected_actions = []
self.getAllChildObjects(action.parent())) if local else [] 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: for existing_action in existing_actions:
if action is existing_action: if action is existing_action:
continue continue
if not local or existing_action in affected_actions: if existing_action in affected_actions:
return False return False
if existing_action.shortcutContext() in [QtCore.Qt.WindowShortcut, QtCore.Qt.ApplicationShortcut]: if existing_action.shortcutContext() in [QtCore.Qt.WindowShortcut, QtCore.Qt.ApplicationShortcut]:
return False return False
elif action in self.getAllChildObjects(existing_action.parent()): elif action in self.get_all_child_objects(existing_action.parent()):
return False return False
return True return True
def getAllChildObjects(self, qobject): def get_all_child_objects(self, qobject):
""" """
Goes recursively through the children of ``qobject`` and returns a list Goes recursively through the children of ``qobject`` and returns a list of all child objects.
of all child objects.
""" """
children = [child for child in qobject.children()] children = qobject.children()
for child in qobject.children(): # Append the children's children.
children.append(self.getAllChildObjects(child)) children.extend(map(self.get_all_child_objects, children))
return children return children
@ -448,5 +433,5 @@ class CategoryOrder(object):
""" """
An enumeration class for category weights. An enumeration class for category weights.
""" """
standardMenu = -20 standard_menu = -20
standardToolbar = -10 standard_toolbar = -10

View File

@ -0,0 +1,181 @@
# -*- 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
SharedData = 8
# 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 or dir_type == AppLocation.SharedData:
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 or dir_type == AppLocation.SharedData:
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 or dir_type == AppLocation.SharedData:
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')

View File

@ -150,8 +150,9 @@ class AlertsPlugin(Plugin):
self.toolsAlertItem = create_action(tools_menu, u'toolsAlertItem', self.toolsAlertItem = create_action(tools_menu, u'toolsAlertItem',
text=translate('AlertsPlugin', '&Alert'), icon=u':/plugins/plugin_alerts.png', text=translate('AlertsPlugin', '&Alert'), icon=u':/plugins/plugin_alerts.png',
statustip=translate('AlertsPlugin', 'Show an alert message.'), 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) self.main_window.tools_menu.addAction(self.toolsAlertItem)
def initialise(self): def initialise(self):
log.info(u'Alerts Initialising') log.info(u'Alerts Initialising')
@ -184,7 +185,7 @@ class AlertsPlugin(Plugin):
'<br />The alert plugin controls the displaying of nursery alerts on the display screen.') '<br />The alert plugin controls the displaying of nursery alerts on the display screen.')
return about_text return about_text
def setPluginTextStrings(self): def set_plugin_text_strings(self):
""" """
Called to define all translatable texts of the plugin Called to define all translatable texts of the plugin
""" """

View File

@ -164,7 +164,7 @@ class BiblePlugin(Plugin):
'verses from different sources during the service.') 'verses from different sources during the service.')
return about_text return about_text
def usesTheme(self, theme): def uses_theme(self, theme):
""" """
Called to find out if the bible plugin is currently using a theme. Called to find out if the bible plugin is currently using a theme.
Returns ``True`` if the theme is being used, otherwise returns Returns ``True`` if the theme is being used, otherwise returns
@ -172,7 +172,7 @@ class BiblePlugin(Plugin):
""" """
return unicode(self.settingsTab.bible_theme) == theme return unicode(self.settingsTab.bible_theme) == theme
def renameTheme(self, oldTheme, newTheme): def rename_theme(self, oldTheme, newTheme):
""" """
Rename the theme the bible plugin is using making the plugin use the Rename the theme the bible plugin is using making the plugin use the
new name. new name.
@ -187,7 +187,7 @@ class BiblePlugin(Plugin):
self.settingsTab.bible_theme = newTheme self.settingsTab.bible_theme = newTheme
self.settingsTab.save() self.settingsTab.save()
def setPluginTextStrings(self): def set_plugin_text_strings(self):
""" """
Called to define all translatable texts of the plugin Called to define all translatable texts of the plugin
""" """

View File

@ -30,7 +30,7 @@
import logging import logging
import os 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.core.utils import AppLocation, delete_file
from openlp.plugins.bibles.lib import parse_reference, get_reference_separator, LanguageSelection from openlp.plugins.bibles.lib import parse_reference, get_reference_separator, LanguageSelection
from openlp.plugins.bibles.lib.db import BibleDB, BibleMeta from openlp.plugins.bibles.lib.db import BibleDB, BibleMeta
@ -137,7 +137,7 @@ class BibleManager(object):
BibleDB class. BibleDB class.
""" """
log.debug(u'Reload bibles') 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: if u'alternative_book_names.sqlite' in files:
files.remove(u'alternative_book_names.sqlite') files.remove(u'alternative_book_names.sqlite')
log.debug(u'Bible Files %s', files) log.debug(u'Bible Files %s', files)

View File

@ -73,7 +73,7 @@ class CustomPlugin(Plugin):
'the same way songs are. This plugin provides greater freedom over the songs plugin.') 'the same way songs are. This plugin provides greater freedom over the songs plugin.')
return about_text return about_text
def usesTheme(self, theme): def uses_theme(self, theme):
""" """
Called to find out if the custom plugin is currently using a theme. Called to find out if the custom plugin is currently using a theme.
@ -83,7 +83,7 @@ class CustomPlugin(Plugin):
return True return True
return False return False
def renameTheme(self, oldTheme, newTheme): def rename_theme(self, oldTheme, newTheme):
""" """
Renames a theme the custom plugin is using making the plugin use the Renames a theme the custom plugin is using making the plugin use the
new name. new name.
@ -94,12 +94,12 @@ class CustomPlugin(Plugin):
``newTheme`` ``newTheme``
The new name the plugin should now use. The new name the plugin should now use.
""" """
customsUsingTheme = self.manager.get_all_objects(CustomSlide, CustomSlide.theme_name == oldTheme) customs_using_theme = self.manager.get_all_objects(CustomSlide, CustomSlide.theme_name == oldTheme)
for custom in customsUsingTheme: for custom in customs_using_theme:
custom.theme_name = newTheme custom.theme_name = newTheme
self.manager.save_object(custom) self.manager.save_object(custom)
def setPluginTextStrings(self): def set_plugin_text_strings(self):
""" """
Called to define all translatable texts of the plugin Called to define all translatable texts of the plugin
""" """

View File

@ -32,84 +32,86 @@ from PyQt4 import QtGui
from openlp.core.lib import UiStrings, build_icon, translate from openlp.core.lib import UiStrings, build_icon, translate
from openlp.core.lib.ui import create_button_box, create_button from openlp.core.lib.ui import create_button_box, create_button
class Ui_CustomEditDialog(object):
def setupUi(self, customEditDialog):
customEditDialog.setObjectName(u'customEditDialog')
customEditDialog.resize(450, 350)
customEditDialog.setWindowIcon(build_icon(u':/icon/openlp-logo-16x16.png'))
self.dialogLayout = QtGui.QVBoxLayout(customEditDialog)
self.dialogLayout.setObjectName(u'dialog_layout')
self.titleLayout = QtGui.QHBoxLayout()
self.titleLayout.setObjectName(u'titleLayout')
self.titleLabel = QtGui.QLabel(customEditDialog)
self.titleLabel.setObjectName(u'titleLabel')
self.titleLayout.addWidget(self.titleLabel)
self.titleEdit = QtGui.QLineEdit(customEditDialog)
self.titleLabel.setBuddy(self.titleEdit)
self.titleEdit.setObjectName(u'titleEdit')
self.titleLayout.addWidget(self.titleEdit)
self.dialogLayout.addLayout(self.titleLayout)
self.centralLayout = QtGui.QHBoxLayout()
self.centralLayout.setObjectName(u'centralLayout')
self.slideListView = QtGui.QListWidget(customEditDialog)
self.slideListView.setAlternatingRowColors(True)
self.slideListView.setObjectName(u'slideListView')
self.centralLayout.addWidget(self.slideListView)
self.buttonLayout = QtGui.QVBoxLayout()
self.buttonLayout.setObjectName(u'buttonLayout')
self.addButton = QtGui.QPushButton(customEditDialog)
self.addButton.setObjectName(u'addButton')
self.buttonLayout.addWidget(self.addButton)
self.editButton = QtGui.QPushButton(customEditDialog)
self.editButton.setEnabled(False)
self.editButton.setObjectName(u'editButton')
self.buttonLayout.addWidget(self.editButton)
self.editAllButton = QtGui.QPushButton(customEditDialog)
self.editAllButton.setObjectName(u'editAllButton')
self.buttonLayout.addWidget(self.editAllButton)
self.deleteButton = create_button(customEditDialog, u'deleteButton', role=u'delete',
click=customEditDialog.onDeleteButtonClicked)
self.deleteButton.setEnabled(False)
self.buttonLayout.addWidget(self.deleteButton)
self.buttonLayout.addStretch()
self.upButton = create_button(customEditDialog, u'upButton', role=u'up', enabled=False,
click=customEditDialog.onUpButtonClicked)
self.downButton = create_button(customEditDialog, u'downButton', role=u'down', enabled=False,
click=customEditDialog.onDownButtonClicked)
self.buttonLayout.addWidget(self.upButton)
self.buttonLayout.addWidget(self.downButton)
self.centralLayout.addLayout(self.buttonLayout)
self.dialogLayout.addLayout(self.centralLayout)
self.bottomFormLayout = QtGui.QFormLayout()
self.bottomFormLayout.setObjectName(u'bottomFormLayout')
self.themeLabel = QtGui.QLabel(customEditDialog)
self.themeLabel.setObjectName(u'themeLabel')
self.themeComboBox = QtGui.QComboBox(customEditDialog)
self.themeComboBox.setSizeAdjustPolicy(QtGui.QComboBox.AdjustToContents)
self.themeComboBox.setObjectName(u'themeComboBox')
self.themeLabel.setBuddy(self.themeComboBox)
self.bottomFormLayout.addRow(self.themeLabel, self.themeComboBox)
self.creditLabel = QtGui.QLabel(customEditDialog)
self.creditLabel.setObjectName(u'creditLabel')
self.creditEdit = QtGui.QLineEdit(customEditDialog)
self.creditEdit.setObjectName(u'creditEdit')
self.creditLabel.setBuddy(self.creditEdit)
self.bottomFormLayout.addRow(self.creditLabel, self.creditEdit)
self.dialogLayout.addLayout(self.bottomFormLayout)
self.previewButton = QtGui.QPushButton()
self.button_box = create_button_box(customEditDialog, u'button_box', [u'cancel', u'save'], [self.previewButton])
self.dialogLayout.addWidget(self.button_box)
self.retranslateUi(customEditDialog)
def retranslateUi(self, customEditDialog): class Ui_CustomEditDialog(object):
customEditDialog.setWindowTitle(translate('CustomPlugin.EditCustomForm', 'Edit Custom Slides')) def setupUi(self, custom_edit_dialog):
self.titleLabel.setText(translate('CustomPlugin.EditCustomForm', '&Title:')) custom_edit_dialog.setObjectName(u'custom_edit_dialog')
self.addButton.setText(UiStrings().Add) custom_edit_dialog.resize(450, 350)
self.addButton.setToolTip(translate('CustomPlugin.EditCustomForm', 'Add a new slide at bottom.')) custom_edit_dialog.setWindowIcon(build_icon(u':/icon/openlp-logo-16x16.png'))
self.editButton.setText(UiStrings().Edit) self.dialog_layout = QtGui.QVBoxLayout(custom_edit_dialog)
self.editButton.setToolTip(translate('CustomPlugin.EditCustomForm', 'Edit the selected slide.')) self.dialog_layout.setObjectName(u'dialog_layout')
self.editAllButton.setText(translate('CustomPlugin.EditCustomForm', 'Ed&it All')) self.title_layout = QtGui.QHBoxLayout()
self.editAllButton.setToolTip(translate('CustomPlugin.EditCustomForm', 'Edit all the slides at once.')) self.title_layout.setObjectName(u'title_layout')
self.themeLabel.setText(translate('CustomPlugin.EditCustomForm', 'The&me:')) self.title_label = QtGui.QLabel(custom_edit_dialog)
self.creditLabel.setText(translate('CustomPlugin.EditCustomForm', '&Credits:')) self.title_label.setObjectName(u'title_label')
self.previewButton.setText(UiStrings().SaveAndPreview) self.title_layout.addWidget(self.title_label)
self.title_edit = QtGui.QLineEdit(custom_edit_dialog)
self.title_label.setBuddy(self.title_edit)
self.title_edit.setObjectName(u'title_edit')
self.title_layout.addWidget(self.title_edit)
self.dialog_layout.addLayout(self.title_layout)
self.central_layout = QtGui.QHBoxLayout()
self.central_layout.setObjectName(u'central_layout')
self.slide_list_view = QtGui.QListWidget(custom_edit_dialog)
self.slide_list_view.setAlternatingRowColors(True)
self.slide_list_view.setObjectName(u'slide_list_view')
self.central_layout.addWidget(self.slide_list_view)
self.button_layout = QtGui.QVBoxLayout()
self.button_layout.setObjectName(u'button_layout')
self.add_button = QtGui.QPushButton(custom_edit_dialog)
self.add_button.setObjectName(u'add_button')
self.button_layout.addWidget(self.add_button)
self.edit_button = QtGui.QPushButton(custom_edit_dialog)
self.edit_button.setEnabled(False)
self.edit_button.setObjectName(u'edit_button')
self.button_layout.addWidget(self.edit_button)
self.edit_all_button = QtGui.QPushButton(custom_edit_dialog)
self.edit_all_button.setObjectName(u'edit_all_button')
self.button_layout.addWidget(self.edit_all_button)
self.delete_button = create_button(custom_edit_dialog, u'delete_button', role=u'delete',
click=custom_edit_dialog.on_delete_button_clicked)
self.delete_button.setEnabled(False)
self.button_layout.addWidget(self.delete_button)
self.button_layout.addStretch()
self.up_button = create_button(custom_edit_dialog, u'up_button', role=u'up', enabled=False,
click=custom_edit_dialog.on_up_button_clicked)
self.down_button = create_button(custom_edit_dialog, u'down_button', role=u'down', enabled=False,
click=custom_edit_dialog.on_down_button_clicked)
self.button_layout.addWidget(self.up_button)
self.button_layout.addWidget(self.down_button)
self.central_layout.addLayout(self.button_layout)
self.dialog_layout.addLayout(self.central_layout)
self.bottom_form_layout = QtGui.QFormLayout()
self.bottom_form_layout.setObjectName(u'bottom_form_layout')
self.theme_label = QtGui.QLabel(custom_edit_dialog)
self.theme_label.setObjectName(u'theme_label')
self.theme_combo_box = QtGui.QComboBox(custom_edit_dialog)
self.theme_combo_box.setSizeAdjustPolicy(QtGui.QComboBox.AdjustToContents)
self.theme_combo_box.setObjectName(u'theme_combo_box')
self.theme_label.setBuddy(self.theme_combo_box)
self.bottom_form_layout.addRow(self.theme_label, self.theme_combo_box)
self.credit_label = QtGui.QLabel(custom_edit_dialog)
self.credit_label.setObjectName(u'credit_label')
self.credit_edit = QtGui.QLineEdit(custom_edit_dialog)
self.credit_edit.setObjectName(u'credit_edit')
self.credit_label.setBuddy(self.credit_edit)
self.bottom_form_layout.addRow(self.credit_label, self.credit_edit)
self.dialog_layout.addLayout(self.bottom_form_layout)
self.preview_button = QtGui.QPushButton()
self.button_box = create_button_box(custom_edit_dialog, u'button_box', [u'cancel', u'save'],
[self.preview_button])
self.dialog_layout.addWidget(self.button_box)
self.retranslateUi(custom_edit_dialog)
def retranslateUi(self, custom_edit_dialog):
custom_edit_dialog.setWindowTitle(translate('CustomPlugin.EditCustomForm', 'Edit Custom Slides'))
self.title_label.setText(translate('CustomPlugin.EditCustomForm', '&Title:'))
self.add_button.setText(UiStrings().Add)
self.add_button.setToolTip(translate('CustomPlugin.EditCustomForm', 'Add a new slide at bottom.'))
self.edit_button.setText(UiStrings().Edit)
self.edit_button.setToolTip(translate('CustomPlugin.EditCustomForm', 'Edit the selected slide.'))
self.edit_all_button.setText(translate('CustomPlugin.EditCustomForm', 'Ed&it All'))
self.edit_all_button.setToolTip(translate('CustomPlugin.EditCustomForm', 'Edit all the slides at once.'))
self.theme_label.setText(translate('CustomPlugin.EditCustomForm', 'The&me:'))
self.credit_label.setText(translate('CustomPlugin.EditCustomForm', '&Credits:'))
self.preview_button.setText(UiStrings().SaveAndPreview)

View File

@ -29,7 +29,7 @@
import logging import logging
from PyQt4 import QtCore, QtGui from PyQt4 import QtGui
from openlp.core.lib import Registry, translate from openlp.core.lib import Registry, translate
from openlp.core.lib.ui import critical_error_message_box, find_and_set_in_combo_box from openlp.core.lib.ui import critical_error_message_box, find_and_set_in_combo_box
@ -56,14 +56,14 @@ class EditCustomForm(QtGui.QDialog, Ui_CustomEditDialog):
self.mediaitem = mediaitem self.mediaitem = mediaitem
self.setupUi(self) self.setupUi(self)
# Create other objects and forms. # Create other objects and forms.
self.editSlideForm = EditCustomSlideForm(self) self.edit_slide_form = EditCustomSlideForm(self)
# Connecting signals and slots # Connecting signals and slots
self.previewButton.clicked.connect(self.on_preview_button_clicked) self.preview_button.clicked.connect(self.on_preview_button_clicked)
self.addButton.clicked.connect(self.on_add_button_clicked) self.add_button.clicked.connect(self.on_add_button_clicked)
self.editButton.clicked.connect(self.on_edit_button_clicked) self.edit_button.clicked.connect(self.on_edit_button_clicked)
self.editAllButton.clicked.connect(self.on_edit_all_button_clicked) self.edit_all_button.clicked.connect(self.on_edit_all_button_clicked)
self.slideListView.currentRowChanged.connect(self.on_current_row_changed) self.slide_list_view.currentRowChanged.connect(self.on_current_row_changed)
self.slideListView.doubleClicked.connect(self.on_edit_button_clicked) self.slide_list_view.doubleClicked.connect(self.on_edit_button_clicked)
Registry().register_function(u'theme_update_list', self.load_themes) Registry().register_function(u'theme_update_list', self.load_themes)
def load_themes(self, theme_list): def load_themes(self, theme_list):
@ -73,11 +73,11 @@ class EditCustomForm(QtGui.QDialog, Ui_CustomEditDialog):
``theme_list`` ``theme_list``
The list of themes to load. The list of themes to load.
""" """
self.themeComboBox.clear() self.theme_combo_box.clear()
self.themeComboBox.addItem(u'') self.theme_combo_box.addItem(u'')
self.themeComboBox.addItems(theme_list) self.theme_combo_box.addItems(theme_list)
def loadCustom(self, id, preview=False): def load_custom(self, id, preview=False):
""" """
Called when editing or creating a new custom. Called when editing or creating a new custom.
@ -88,111 +88,111 @@ class EditCustomForm(QtGui.QDialog, Ui_CustomEditDialog):
States whether the custom is edited while being previewed in the States whether the custom is edited while being previewed in the
preview panel. preview panel.
""" """
self.slideListView.clear() self.slide_list_view.clear()
if id == 0: if id == 0:
self.customSlide = CustomSlide() self.custom_slide = CustomSlide()
self.titleEdit.setText(u'') self.title_edit.set_text(u'')
self.creditEdit.setText(u'') self.credit_edit.set_text(u'')
self.themeComboBox.setCurrentIndex(0) self.theme_combo_box.setCurrentIndex(0)
else: else:
self.customSlide = self.manager.get_object(CustomSlide, id) self.custom_slide = self.manager.get_object(CustomSlide, id)
self.titleEdit.setText(self.customSlide.title) self.title_edit.setText(self.custom_slide.title)
self.creditEdit.setText(self.customSlide.credits) self.credit_edit.setText(self.custom_slide.credits)
customXML = CustomXMLParser(self.customSlide.text) custom_XML = CustomXMLParser(self.custom_slide.text)
slideList = customXML.get_verses() slide_list = custom_XML.get_verses()
for slide in slideList: for slide in slide_list:
self.slideListView.addItem(slide[1]) self.slide_list_view.addItem(slide[1])
theme = self.customSlide.theme_name theme = self.custom_slide.theme_name
find_and_set_in_combo_box(self.themeComboBox, theme) find_and_set_in_combo_box(self.theme_combo_box, theme)
self.titleEdit.setFocus() self.title_edit.setFocus()
# If not preview hide the preview button. # If not preview hide the preview button.
self.previewButton.setVisible(preview) self.preview_button.setVisible(preview)
def accept(self): def accept(self):
""" """
Override the QDialog method to check if the custom slide has been saved before closing the dialog. Override the QDialog method to check if the custom slide has been saved before closing the dialog.
""" """
log.debug(u'accept') log.debug(u'accept')
if self.saveCustom(): if self.save_custom():
QtGui.QDialog.accept(self) QtGui.QDialog.accept(self)
def saveCustom(self): def save_custom(self):
""" """
Saves the custom. Saves the custom.
""" """
if not self._validate(): if not self._validate():
return False return False
sxml = CustomXMLBuilder() sxml = CustomXMLBuilder()
for count in range(self.slideListView.count()): for count in range(self.slide_list_view.count()):
sxml.add_verse_to_lyrics(u'custom', unicode(count + 1), self.slideListView.item(count).text()) sxml.add_verse_to_lyrics(u'custom', unicode(count + 1), self.slide_list_view.item(count).text())
self.customSlide.title = self.titleEdit.text() self.custom_slide.title = self.title_edit.text()
self.customSlide.text = unicode(sxml.extract_xml(), u'utf-8') self.custom_slide.text = unicode(sxml.extract_xml(), u'utf-8')
self.customSlide.credits = self.creditEdit.text() self.custom_slide.credits = self.credit_edit.text()
self.customSlide.theme_name = self.themeComboBox.currentText() self.custom_slide.theme_name = self.theme_combo_box.currentText()
success = self.manager.save_object(self.customSlide) success = self.manager.save_object(self.custom_slide)
self.mediaitem.autoSelectId = self.customSlide.id self.mediaitem.autoSelectId = self.custom_slide.id
return success return success
def onUpButtonClicked(self): def on_up_button_clicked(self):
""" """
Move a slide up in the list when the "Up" button is clicked. Move a slide up in the list when the "Up" button is clicked.
""" """
selectedRow = self.slideListView.currentRow() selectedRow = self.slide_list_view.currentRow()
if selectedRow != 0: if selectedRow != 0:
qw = self.slideListView.takeItem(selectedRow) qw = self.slide_list_view.takeItem(selectedRow)
self.slideListView.insertItem(selectedRow - 1, qw) self.slide_list_view.insertItem(selectedRow - 1, qw)
self.slideListView.setCurrentRow(selectedRow - 1) self.slide_list_view.setCurrentRow(selectedRow - 1)
def onDownButtonClicked(self): def on_down_button_clicked(self):
""" """
Move a slide down in the list when the "Down" button is clicked. Move a slide down in the list when the "Down" button is clicked.
""" """
selectedRow = self.slideListView.currentRow() selectedRow = self.slide_list_view.currentRow()
# zero base arrays # zero base arrays
if selectedRow != self.slideListView.count() - 1: if selectedRow != self.slide_list_view.count() - 1:
qw = self.slideListView.takeItem(selectedRow) qw = self.slide_list_view.takeItem(selectedRow)
self.slideListView.insertItem(selectedRow + 1, qw) self.slide_list_view.insertItem(selectedRow + 1, qw)
self.slideListView.setCurrentRow(selectedRow + 1) self.slide_list_view.setCurrentRow(selectedRow + 1)
def on_add_button_clicked(self): def on_add_button_clicked(self):
""" """
Add a new blank slide. Add a new blank slide.
""" """
self.editSlideForm.setText(u'') self.edit_slide_form.set_text(u'')
if self.editSlideForm.exec_(): if self.edit_slide_form.exec_():
self.slideListView.addItems(self.editSlideForm.getText()) self.slide_list_view.addItems(self.edit_slide_form.get_text())
def on_edit_button_clicked(self): def on_edit_button_clicked(self):
""" """
Edit the currently selected slide. Edit the currently selected slide.
""" """
self.editSlideForm.setText(self.slideListView.currentItem().text()) self.edit_slide_form.set_text(self.slide_list_view.currentItem().text())
if self.editSlideForm.exec_(): if self.edit_slide_form.exec_():
self.updateSlideList(self.editSlideForm.getText()) self.update_slide_list(self.edit_slide_form.get_text())
def on_edit_all_button_clicked(self): def on_edit_all_button_clicked(self):
""" """
Edits all slides. Edits all slides.
""" """
slide_text = u'' slide_text = u''
for row in range(self.slideListView.count()): for row in range(self.slide_list_view.count()):
item = self.slideListView.item(row) item = self.slide_list_view.item(row)
slide_text += item.text() slide_text += item.text()
if row != self.slideListView.count() - 1: if row != self.slide_list_view.count() - 1:
slide_text += u'\n[===]\n' slide_text += u'\n[===]\n'
self.editSlideForm.setText(slide_text) self.edit_slide_form.set_text(slide_text)
if self.editSlideForm.exec_(): if self.edit_slide_form.exec_():
self.updateSlideList(self.editSlideForm.getText(), True) self.update_slide_list(self.edit_slide_form.get_text(), True)
def on_preview_button_clicked(self): def on_preview_button_clicked(self):
""" """
Save the custom item and preview it. Save the custom item and preview it.
""" """
log.debug(u'onPreview') log.debug(u'onPreview')
if self.saveCustom(): if self.save_custom():
Registry().execute(u'custom_preview') Registry().execute(u'custom_preview')
def updateSlideList(self, slides, edit_all=False): def update_slide_list(self, slides, edit_all=False):
""" """
Updates the slide list after editing slides. Updates the slide list after editing slides.
@ -203,60 +203,59 @@ class EditCustomForm(QtGui.QDialog, Ui_CustomEditDialog):
Indicates if all slides or only one slide has been edited. Indicates if all slides or only one slide has been edited.
""" """
if edit_all: if edit_all:
self.slideListView.clear() self.slide_list_view.clear()
self.slideListView.addItems(slides) self.slide_list_view.addItems(slides)
else: else:
old_slides = [] old_slides = []
old_row = self.slideListView.currentRow() old_row = self.slide_list_view.currentRow()
# Create a list with all (old/unedited) slides. # Create a list with all (old/unedited) slides.
old_slides = [self.slideListView.item(row).text() for row in old_slides = [self.slide_list_view.item(row).text() for row in range(self.slide_list_view.count())]
range(self.slideListView.count())] self.slide_list_view.clear()
self.slideListView.clear()
old_slides.pop(old_row) old_slides.pop(old_row)
# Insert all slides to make the old_slides list complete. # Insert all slides to make the old_slides list complete.
for slide in slides: for slide in slides:
old_slides.insert(old_row, slide) old_slides.insert(old_row, slide)
self.slideListView.addItems(old_slides) self.slide_list_view.addItems(old_slides)
self.slideListView.repaint() self.slide_list_view.repaint()
def onDeleteButtonClicked(self): def on_delete_button_clicked(self):
""" """
Removes the current row from the list. Removes the current row from the list.
""" """
self.slideListView.takeItem(self.slideListView.currentRow()) self.slide_list_view.takeItem(self.slide_list_view.currentRow())
self.on_current_row_changed(self.slideListView.currentRow()) self.on_current_row_changed(self.slide_list_view.currentRow())
def on_current_row_changed(self, row): def on_current_row_changed(self, row):
""" """
Called when the *slideListView*'s current row has been changed. This Called when the *slide_list_view*'s current row has been changed. This
enables or disables buttons which require an slide to act on. enables or disables buttons which require an slide to act on.
``row`` ``row``
The row (int). If there is no current row, the value is -1. The row (int). If there is no current row, the value is -1.
""" """
if row == -1: if row == -1:
self.deleteButton.setEnabled(False) self.delete_button.setEnabled(False)
self.editButton.setEnabled(False) self.edit_button.setEnabled(False)
self.upButton.setEnabled(False) self.up_button.setEnabled(False)
self.downButton.setEnabled(False) self.down_button.setEnabled(False)
else: else:
self.deleteButton.setEnabled(True) self.delete_button.setEnabled(True)
self.editButton.setEnabled(True) self.edit_button.setEnabled(True)
# Decide if the up/down buttons should be enabled or not. # Decide if the up/down buttons should be enabled or not.
self.downButton.setEnabled(self.slideListView.count() - 1 != row) self.down_button.setEnabled(self.slide_list_view.count() - 1 != row)
self.upButton.setEnabled(row != 0) self.up_button.setEnabled(row != 0)
def _validate(self): def _validate(self):
""" """
Checks whether a custom is valid or not. Checks whether a custom is valid or not.
""" """
# We must have a title. # We must have a title.
if not self.titleEdit.displayText(): if not self.title_edit.displayText():
self.titleEdit.setFocus() self.title_edit.setFocus()
critical_error_message_box(message=translate('CustomPlugin.EditCustomForm', 'You need to type in a title.')) critical_error_message_box(message=translate('CustomPlugin.EditCustomForm', 'You need to type in a title.'))
return False return False
# We must have at least one slide. # We must have at least one slide.
if self.slideListView.count() == 0: if self.slide_list_view.count() == 0:
critical_error_message_box(message=translate('CustomPlugin.EditCustomForm', critical_error_message_box(message=translate('CustomPlugin.EditCustomForm',
'You need to add at least one slide')) 'You need to add at least one slide'))
return False return False

View File

@ -33,24 +33,25 @@ from openlp.core.lib import SpellTextEdit, UiStrings, translate
from openlp.core.lib.ui import create_button, create_button_box from openlp.core.lib.ui import create_button, create_button_box
class Ui_CustomSlideEditDialog(object): class Ui_CustomSlideEditDialog(object):
def setupUi(self, customSlideEditDialog): def setupUi(self, custom_slide_edit_dialog):
customSlideEditDialog.setObjectName(u'customSlideEditDialog') custom_slide_edit_dialog.setObjectName(u'custom_slide_edit_dialog')
customSlideEditDialog.resize(350, 300) custom_slide_edit_dialog.resize(350, 300)
self.dialogLayout = QtGui.QVBoxLayout(customSlideEditDialog) self.dialog_layout = QtGui.QVBoxLayout(custom_slide_edit_dialog)
self.slideTextEdit = SpellTextEdit(self) self.slide_text_edit = SpellTextEdit(self)
self.slideTextEdit.setObjectName(u'slideTextEdit') self.slide_text_edit.setObjectName(u'slide_text_edit')
self.dialogLayout.addWidget(self.slideTextEdit) self.dialog_layout.addWidget(self.slide_text_edit)
self.splitButton = create_button(customSlideEditDialog, u'splitButton', icon=u':/general/general_add.png') self.split_button = create_button(custom_slide_edit_dialog, u'splitButton', icon=u':/general/general_add.png')
self.insertButton = create_button(customSlideEditDialog, u'insertButton', icon=u':/general/general_add.png') self.insert_button = create_button(custom_slide_edit_dialog, u'insertButton',
self.button_box = create_button_box(customSlideEditDialog, u'button_box', [u'cancel', u'save'], icon=u':/general/general_add.png')
[self.splitButton, self.insertButton]) self.button_box = create_button_box(custom_slide_edit_dialog, u'button_box', [u'cancel', u'save'],
self.dialogLayout.addWidget(self.button_box) [self.split_button, self.insert_button])
self.retranslateUi(customSlideEditDialog) self.dialog_layout.addWidget(self.button_box)
self.retranslateUi(custom_slide_edit_dialog)
def retranslateUi(self, customSlideEditDialog): def retranslateUi(self, custom_slide_edit_dialog):
customSlideEditDialog.setWindowTitle(translate('CustomPlugin.EditVerseForm', 'Edit Slide')) custom_slide_edit_dialog.setWindowTitle(translate('CustomPlugin.EditVerseForm', 'Edit Slide'))
self.splitButton.setText(UiStrings().Split) self.split_button.setText(UiStrings().Split)
self.splitButton.setToolTip(UiStrings().SplitToolTip) self.split_button.setToolTip(UiStrings().SplitToolTip)
self.insertButton.setText(translate('CustomPlugin.EditCustomForm', 'Insert Slide')) self.insert_button.setText(translate('CustomPlugin.EditCustomForm', 'Insert Slide'))
self.insertButton.setToolTip(translate('CustomPlugin.EditCustomForm', self.insert_button.setToolTip(translate('CustomPlugin.EditCustomForm',
'Split a slide into two by inserting a slide splitter.')) 'Split a slide into two by inserting a slide splitter.'))

View File

@ -50,51 +50,49 @@ class EditCustomSlideForm(QtGui.QDialog, Ui_CustomSlideEditDialog):
super(EditCustomSlideForm, self).__init__(parent) super(EditCustomSlideForm, self).__init__(parent)
self.setupUi(self) self.setupUi(self)
# Connecting signals and slots # Connecting signals and slots
QtCore.QObject.connect(self.insertButton, QtCore.SIGNAL(u'clicked()'), self.onInsertButtonClicked) self.insert_button.clicked.connect(self.on_insert_button_clicked)
QtCore.QObject.connect(self.splitButton, QtCore.SIGNAL(u'clicked()'), self.onSplitButtonClicked) self.split_button.clicked.connect(self.on_split_button_clicked)
def setText(self, text): def set_text(self, text):
""" """
Set the text for slideTextEdit. Set the text for slide_text_edit.
``text`` ``text``
The text (unicode). The text (unicode).
""" """
self.slideTextEdit.clear() self.slide_text_edit.clear()
if text: if text:
self.slideTextEdit.setPlainText(text) self.slide_text_edit.setPlainText(text)
self.slideTextEdit.setFocus() self.slide_text_edit.setFocus()
def getText(self): def get_text(self):
""" """
Returns a list with all slides. Returns a list with all slides.
""" """
return self.slideTextEdit.toPlainText().split(u'\n[===]\n') return self.slide_text_edit.toPlainText().split(u'\n[===]\n')
def onInsertButtonClicked(self): def on_insert_button_clicked(self):
""" """
Adds a slide split at the cursor. Adds a slide split at the cursor.
""" """
self.insertSingleLineTextAtCursor(u'[===]') self.insert_single_line_text_at_cursor(u'[===]')
self.slideTextEdit.setFocus() self.slide_text_edit.setFocus()
def onSplitButtonClicked(self): def on_split_button_clicked(self):
""" """
Adds an optional split at cursor. Adds an optional split at cursor.
""" """
self.insertSingleLineTextAtCursor(u'[---]') self.insert_single_line_text_at_cursor(u'[---]')
self.slideTextEdit.setFocus() self.slide_text_edit.setFocus()
def insertSingleLineTextAtCursor(self, text): def insert_single_line_text_at_cursor(self, text):
""" """
Adds ``text`` in a single line at the cursor position. Adds ``text`` in a single line at the cursor position.
""" """
full_text = self.slideTextEdit.toPlainText() full_text = self.slide_text_edit.toPlainText()
position = self.slideTextEdit.textCursor().position() position = self.slide_text_edit.textCursor().position()
if position and full_text[position - 1] != u'\n': if position and full_text[position - 1] != u'\n':
text = u'\n' + text text = u'\n' + text
if position == len(full_text) or full_text[position] != u'\n': if position == len(full_text) or full_text[position] != u'\n':
text += u'\n' text += u'\n'
self.slideTextEdit.insertPlainText(text) self.slide_text_edit.insertPlainText(text)
#lint:enable

View File

@ -45,38 +45,36 @@ class CustomTab(SettingsTab):
def setupUi(self): def setupUi(self):
self.setObjectName(u'CustomTab') self.setObjectName(u'CustomTab')
SettingsTab.setupUi(self) SettingsTab.setupUi(self)
self.customModeGroupBox = QtGui.QGroupBox(self.leftColumn) self.custom_mode_group_box = QtGui.QGroupBox(self.leftColumn)
self.customModeGroupBox.setObjectName(u'customModeGroupBox') self.custom_mode_group_box.setObjectName(u'custom_mode_group_box')
self.customModeLayout = QtGui.QFormLayout(self.customModeGroupBox) self.custom_mode_layout = QtGui.QFormLayout(self.custom_mode_group_box)
self.customModeLayout.setObjectName(u'customModeLayout') self.custom_mode_layout.setObjectName(u'custom_mode_layout')
self.displayFooterCheckBox = QtGui.QCheckBox(self.customModeGroupBox) self.display_footer_check_box = QtGui.QCheckBox(self.custom_mode_group_box)
self.displayFooterCheckBox.setObjectName(u'displayFooterCheckBox') self.display_footer_check_box.setObjectName(u'display_footer_check_box')
self.customModeLayout.addRow(self.displayFooterCheckBox) self.custom_mode_layout.addRow(self.display_footer_check_box)
self.add_from_service_checkbox = QtGui.QCheckBox(self.customModeGroupBox) self.add_from_service_checkbox = QtGui.QCheckBox(self.custom_mode_group_box)
self.add_from_service_checkbox.setObjectName(u'add_from_service_checkbox') self.add_from_service_checkbox.setObjectName(u'add_from_service_checkbox')
self.customModeLayout.addRow(self.add_from_service_checkbox) self.custom_mode_layout.addRow(self.add_from_service_checkbox)
self.leftLayout.addWidget(self.customModeGroupBox) self.leftLayout.addWidget(self.custom_mode_group_box)
self.leftLayout.addStretch() self.leftLayout.addStretch()
self.rightLayout.addStretch() self.rightLayout.addStretch()
QtCore.QObject.connect(self.displayFooterCheckBox, QtCore.SIGNAL(u'stateChanged(int)'), self.display_footer_check_box.stateChanged.connect(self.on_display_footer_check_box_changed)
self.onDisplayFooterCheckBoxChanged) self.add_from_service_checkbox.stateChanged.connect(self.on_add_from_service_check_box_changed)
QtCore.QObject.connect(self.add_from_service_checkbox, QtCore.SIGNAL(u'stateChanged(int)'),
self.on_add_from_service_check_box_changed)
def retranslateUi(self): def retranslateUi(self):
self.customModeGroupBox.setTitle(translate('CustomPlugin.CustomTab', 'Custom Display')) self.custom_mode_group_box.setTitle(translate('CustomPlugin.CustomTab', 'Custom Display'))
self.displayFooterCheckBox.setText(translate('CustomPlugin.CustomTab', 'Display footer')) self.display_footer_check_box.setText(translate('CustomPlugin.CustomTab', 'Display footer'))
self.add_from_service_checkbox.setText(translate('CustomPlugin.CustomTab', self.add_from_service_checkbox.setText(translate('CustomPlugin.CustomTab',
'Import missing custom slides from service files')) 'Import missing custom slides from service files'))
def onDisplayFooterCheckBoxChanged(self, check_state): def on_display_footer_check_box_changed(self, check_state):
""" """
Toggle the setting for displaying the footer. Toggle the setting for displaying the footer.
""" """
self.displayFooter = False self.display_footer = False
# we have a set value convert to True/False # we have a set value convert to True/False
if check_state == QtCore.Qt.Checked: if check_state == QtCore.Qt.Checked:
self.displayFooter = True self.display_footer = True
def on_add_from_service_check_box_changed(self, check_state): def on_add_from_service_check_box_changed(self, check_state):
self.update_load = (check_state == QtCore.Qt.Checked) self.update_load = (check_state == QtCore.Qt.Checked)
@ -84,15 +82,15 @@ class CustomTab(SettingsTab):
def load(self): def load(self):
settings = Settings() settings = Settings()
settings.beginGroup(self.settingsSection) settings.beginGroup(self.settingsSection)
self.displayFooter = settings.value(u'display footer') self.display_footer = settings.value(u'display footer')
self.update_load = settings.value(u'add custom from service') self.update_load = settings.value(u'add custom from service')
self.displayFooterCheckBox.setChecked(self.displayFooter) self.display_footer_check_box.setChecked(self.display_footer)
self.add_from_service_checkbox.setChecked(self.update_load) self.add_from_service_checkbox.setChecked(self.update_load)
settings.endGroup() settings.endGroup()
def save(self): def save(self):
settings = Settings() settings = Settings()
settings.beginGroup(self.settingsSection) settings.beginGroup(self.settingsSection)
settings.setValue(u'display footer', self.displayFooter) settings.setValue(u'display footer', self.display_footer)
settings.setValue(u'add custom from service', self.update_load) settings.setValue(u'add custom from service', self.update_load)
settings.endGroup() settings.endGroup()

View File

@ -114,7 +114,7 @@ class CustomMediaItem(MediaManagerItem):
# active trigger it and clean up so it will not update again. # active trigger it and clean up so it will not update again.
def onNewClick(self): def onNewClick(self):
self.edit_custom_form.loadCustom(0) self.edit_custom_form.load_custom(0)
self.edit_custom_form.exec_() self.edit_custom_form.exec_()
self.onClearTextButtonClick() self.onClearTextButtonClick()
self.onSelectionChange() self.onSelectionChange()
@ -128,7 +128,7 @@ class CustomMediaItem(MediaManagerItem):
custom_id = int(custom_id) custom_id = int(custom_id)
valid = self.manager.get_object(CustomSlide, custom_id) valid = self.manager.get_object(CustomSlide, custom_id)
if valid: if valid:
self.edit_custom_form.loadCustom(custom_id, preview) self.edit_custom_form.load_custom(custom_id, preview)
if self.edit_custom_form.exec_() == QtGui.QDialog.Accepted: if self.edit_custom_form.exec_() == QtGui.QDialog.Accepted:
self.remoteTriggered = True self.remoteTriggered = True
self.remoteCustom = custom_id self.remoteCustom = custom_id
@ -148,7 +148,7 @@ class CustomMediaItem(MediaManagerItem):
if check_item_selected(self.listView, UiStrings().SelectEdit): if check_item_selected(self.listView, UiStrings().SelectEdit):
item = self.listView.currentItem() item = self.listView.currentItem()
item_id = item.data(QtCore.Qt.UserRole) item_id = item.data(QtCore.Qt.UserRole)
self.edit_custom_form.loadCustom(item_id, False) self.edit_custom_form.load_custom(item_id, False)
self.edit_custom_form.exec_() self.edit_custom_form.exec_()
self.autoSelectId = -1 self.autoSelectId = -1
self.onSearchTextButtonClicked() self.onSearchTextButtonClicked()

View File

@ -65,7 +65,7 @@ class ImagePlugin(Plugin):
'provided by the theme.') 'provided by the theme.')
return about_text return about_text
def setPluginTextStrings(self): def set_plugin_text_strings(self):
""" """
Called to define all translatable texts of the plugin Called to define all translatable texts of the plugin
""" """

View File

@ -32,9 +32,8 @@ import os
from PyQt4 import QtCore, QtGui from PyQt4 import QtCore, QtGui
from openlp.core.lib import MediaManagerItem, ItemCapabilities, Registry, SettingsManager, ServiceItemContext, \ from openlp.core.lib import MediaManagerItem, ItemCapabilities, Registry, ServiceItemContext, Settings, UiStrings, \
Settings, UiStrings, build_icon, check_item_selected, check_directory_exists, create_thumb, translate, \ build_icon, check_item_selected, check_directory_exists, create_thumb, translate, validate_thumb
validate_thumb
from openlp.core.lib.ui import critical_error_message_box from openlp.core.lib.ui import critical_error_message_box
from openlp.core.utils import AppLocation, delete_file, locale_compare, get_images_filter 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())) delete_file(os.path.join(self.servicePath, text.text()))
self.listView.takeItem(row) self.listView.takeItem(row)
self.main_window.incrementProgressBar() 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.main_window.finishedProgressBar()
self.application.set_normal_cursor() self.application.set_normal_cursor()
self.listView.blockSignals(False) self.listView.blockSignals(False)
@ -192,7 +191,7 @@ class ImageMediaItem(MediaManagerItem):
Called to reset the Live background with the image selected, Called to reset the Live background with the image selected,
""" """
self.resetAction.setVisible(False) self.resetAction.setVisible(False)
self.live_controller.display.resetImage() self.live_controller.display.reset_image()
def live_theme_changed(self): def live_theme_changed(self):
""" """
@ -211,7 +210,7 @@ class ImageMediaItem(MediaManagerItem):
bitem = self.listView.item(item.row()) bitem = self.listView.item(item.row())
filename = bitem.data(QtCore.Qt.UserRole) filename = bitem.data(QtCore.Qt.UserRole)
if os.path.exists(filename): if os.path.exists(filename):
if self.live_controller.display.directImage(filename, background): if self.live_controller.display.direct_image(filename, background):
self.resetAction.setVisible(True) self.resetAction.setVisible(True)
else: else:
critical_error_message_box(UiStrings().LiveBGError, critical_error_message_box(UiStrings().LiveBGError,

View File

@ -61,16 +61,16 @@ class MediaMediaItem(MediaManagerItem):
self.singleServiceItem = False self.singleServiceItem = False
self.hasSearch = True self.hasSearch = True
self.mediaObject = None self.mediaObject = None
self.displayController = DisplayController(parent) self.display_controller = DisplayController(parent)
self.displayController.controllerLayout = QtGui.QVBoxLayout() self.display_controller.controller_layout = QtGui.QVBoxLayout()
self.media_controller.register_controller(self.displayController) self.media_controller.register_controller(self.display_controller)
self.media_controller.set_controls_visible(self.displayController, False) self.media_controller.set_controls_visible(self.display_controller, False)
self.displayController.previewDisplay = Display(self.displayController, False, self.displayController) self.display_controller.preview_display = Display(self.display_controller, False, self.display_controller)
self.displayController.previewDisplay.hide() self.display_controller.preview_display.hide()
self.displayController.previewDisplay.setGeometry(QtCore.QRect(0, 0, 300, 300)) self.display_controller.preview_display.setGeometry(QtCore.QRect(0, 0, 300, 300))
self.displayController.previewDisplay.screen = {u'size':self.displayController.previewDisplay.geometry()} self.display_controller.preview_display.screen = {u'size': self.display_controller.preview_display.geometry()}
self.displayController.previewDisplay.setup() self.display_controller.preview_display.setup()
self.media_controller.setup_display(self.displayController.previewDisplay, False) self.media_controller.setup_display(self.display_controller.preview_display, False)
Registry().register_function(u'video_background_replaced', self.video_background_replaced) Registry().register_function(u'video_background_replaced', self.video_background_replaced)
Registry().register_function(u'mediaitem_media_rebuild', self.rebuild_players) Registry().register_function(u'mediaitem_media_rebuild', self.rebuild_players)
Registry().register_function(u'config_screen_changed', self.display_setup) Registry().register_function(u'config_screen_changed', self.display_setup)
@ -214,7 +214,7 @@ class MediaMediaItem(MediaManagerItem):
u' '.join(self.media_controller.audio_extensions_list), UiStrings().AllFiles) u' '.join(self.media_controller.audio_extensions_list), UiStrings().AllFiles)
def display_setup(self): def display_setup(self):
self.media_controller.setup_display(self.displayController.previewDisplay, False) self.media_controller.setup_display(self.display_controller.previewDisplay, False)
def populateDisplayTypes(self): def populateDisplayTypes(self):
""" """
@ -226,11 +226,11 @@ class MediaMediaItem(MediaManagerItem):
self.displayTypeComboBox.blockSignals(True) self.displayTypeComboBox.blockSignals(True)
self.displayTypeComboBox.clear() self.displayTypeComboBox.clear()
usedPlayers, overridePlayer = get_media_players() usedPlayers, overridePlayer = get_media_players()
mediaPlayers = self.media_controller.mediaPlayers media_players = self.media_controller.media_players
currentIndex = 0 currentIndex = 0
for player in usedPlayers: for player in usedPlayers:
# load the drop down selection # load the drop down selection
self.displayTypeComboBox.addItem(mediaPlayers[player].original_name) self.displayTypeComboBox.addItem(media_players[player].original_name)
if overridePlayer == player: if overridePlayer == player:
currentIndex = len(self.displayTypeComboBox) currentIndex = len(self.displayTypeComboBox)
if self.displayTypeComboBox.count() > 1: if self.displayTypeComboBox.count() > 1:

View File

@ -66,7 +66,7 @@ class MediaPlugin(Plugin):
'<br />The media plugin provides playback of audio and video.') '<br />The media plugin provides playback of audio and video.')
return about_text return about_text
def setPluginTextStrings(self): def set_plugin_text_strings(self):
""" """
Called to define all translatable texts of the plugin Called to define all translatable texts of the plugin
""" """

View File

@ -156,7 +156,7 @@ class PresentationPlugin(Plugin):
'available to the user in a drop down box.') 'available to the user in a drop down box.')
return about_text return about_text
def setPluginTextStrings(self): def set_plugin_text_strings(self):
""" """
Called to define all translatable texts of the plugin Called to define all translatable texts of the plugin
""" """

View File

@ -130,7 +130,6 @@ from openlp.plugins.remotes.lib.httpauth import AuthController, require_auth
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
class HttpServer(object): class HttpServer(object):
""" """
Ability to control OpenLP via a web browser. Ability to control OpenLP via a web browser.
@ -400,9 +399,9 @@ class HttpConnection(object):
u'slide': self.parent.current_slide or 0, u'slide': self.parent.current_slide or 0,
u'item': self.parent.current_item.unique_identifier if self.parent.current_item else u'', u'item': self.parent.current_item.unique_identifier if self.parent.current_item else u'',
u'twelve': Settings().value(u'remotes/twelve hour'), u'twelve': Settings().value(u'remotes/twelve hour'),
u'blank': self.live_controller.blankScreen.isChecked(), u'blank': self.live_controller.blank_screen.isChecked(),
u'theme': self.live_controller.themeScreen.isChecked(), u'theme': self.live_controller.theme_screen.isChecked(),
u'display': self.live_controller.desktopScreen.isChecked() u'display': self.live_controller.desktop_screen.isChecked()
} }
cherrypy.response.headers['Content-Type'] = u'application/json' cherrypy.response.headers['Content-Type'] = u'application/json'
return json.dumps({u'results': result}) return json.dumps({u'results': result})
@ -437,18 +436,17 @@ class HttpConnection(object):
cherrypy.response.headers['Content-Type'] = u'application/json' cherrypy.response.headers['Content-Type'] = u'application/json'
return json.dumps({u'results': {u'success': success}}) return json.dumps({u'results': {u'success': success}})
def controller(self, type, action): def controller(self, display_type, action):
""" """
Perform an action on the slide controller. Perform an action on the slide controller.
``type`` ``display_type``
This is the type of slide controller, either ``preview`` or This is the type of slide controller, either ``preview`` or ``live``.
``live``.
``action`` ``action``
The action to perform. The action to perform.
""" """
event = u'slidecontroller_%s_%s' % (type, action) event = u'slidecontroller_%s_%s' % (display_type, action)
if action == u'text': if action == u'text':
current_item = self.parent.current_item current_item = self.parent.current_item
data = [] data = []
@ -489,7 +487,10 @@ class HttpConnection(object):
def service(self, action): def service(self, action):
""" """
List details of the Service and update the UI Handles requests for service items
``action``
The action to perform.
""" """
event = u'servicemanager_%s' % action event = u'servicemanager_%s' % action
if action == u'list': if action == u'list':
@ -524,11 +525,11 @@ class HttpConnection(object):
cherrypy.response.headers['Content-Type'] = u'application/json' cherrypy.response.headers['Content-Type'] = u'application/json'
return json.dumps({u'results': {u'items': searches}}) return json.dumps({u'results': {u'items': searches}})
def search(self, type): def search(self, plugin_name):
""" """
Return a list of items that match the search text. Return a list of items that match the search text.
``type`` ``plugin``
The plugin name to search in. The plugin name to search in.
""" """
try: try:
@ -536,7 +537,7 @@ class HttpConnection(object):
except KeyError, ValueError: except KeyError, ValueError:
return self._http_bad_request() return self._http_bad_request()
text = urllib.unquote(text) text = urllib.unquote(text)
plugin = self.plugin_manager.get_plugin_by_name(type) plugin = self.plugin_manager.get_plugin_by_name(plugin_name)
if plugin.status == PluginStatus.Active and plugin.mediaItem and plugin.mediaItem.hasSearch: if plugin.status == PluginStatus.Active and plugin.mediaItem and plugin.mediaItem.hasSearch:
results = plugin.mediaItem.search(text, False) results = plugin.mediaItem.search(text, False)
else: else:
@ -544,9 +545,9 @@ class HttpConnection(object):
cherrypy.response.headers['Content-Type'] = u'application/json' cherrypy.response.headers['Content-Type'] = u'application/json'
return json.dumps({u'results': {u'items': results}}) return json.dumps({u'results': {u'items': results}})
def go_live(self, type): def go_live(self, plugin_name):
""" """
Go live on an item of type ``type``. Go live on an item of type ``plugin``.
""" """
try: try:
id = json.loads(self.url_params[u'data'][0])[u'request'][u'id'] id = json.loads(self.url_params[u'data'][0])[u'request'][u'id']
@ -557,9 +558,9 @@ class HttpConnection(object):
plugin.mediaItem.goLive(id, remote=True) plugin.mediaItem.goLive(id, remote=True)
return self._http_success() return self._http_success()
def add_to_service(self, type): def add_to_service(self, plugin_name):
""" """
Add item of type ``type`` to the end of the service. Add item of type ``plugin_name`` to the end of the service.
""" """
try: try:
id = json.loads(self.url_params[u'data'][0])[u'request'][u'id'] id = json.loads(self.url_params[u'data'][0])[u'request'][u'id']

View File

@ -56,6 +56,7 @@ class RemoteTab(SettingsTab):
self.address_label.setObjectName(u'address_label') self.address_label.setObjectName(u'address_label')
self.address_edit = QtGui.QLineEdit(self.server_settings_group_box) self.address_edit = QtGui.QLineEdit(self.server_settings_group_box)
self.address_edit.setSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Fixed) self.address_edit.setSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Fixed)
self.address_edit.setValidator(QtGui.QRegExpValidator(QtCore.QRegExp(u'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}'), self.address_edit.setValidator(QtGui.QRegExpValidator(QtCore.QRegExp(u'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}'),
self)) self))
self.address_edit.setObjectName(u'address_edit') self.address_edit.setObjectName(u'address_edit')
@ -63,6 +64,7 @@ class RemoteTab(SettingsTab):
self.twelve_hour_check_box = QtGui.QCheckBox(self.server_settings_group_box) self.twelve_hour_check_box = QtGui.QCheckBox(self.server_settings_group_box)
self.twelve_hour_check_box.setObjectName(u'twelve_hour_check_box') self.twelve_hour_check_box.setObjectName(u'twelve_hour_check_box')
self.server_settings_layout.addRow(self.twelve_hour_check_box) self.server_settings_layout.addRow(self.twelve_hour_check_box)
self.leftLayout.addWidget(self.server_settings_group_box) self.leftLayout.addWidget(self.server_settings_group_box)
self.http_settings_group_box = QtGui.QGroupBox(self.leftColumn) self.http_settings_group_box = QtGui.QGroupBox(self.leftColumn)
self.http_settings_group_box.setObjectName(u'http_settings_group_box') self.http_settings_group_box.setObjectName(u'http_settings_group_box')
@ -73,6 +75,7 @@ class RemoteTab(SettingsTab):
self.port_spin_box = QtGui.QSpinBox(self.http_settings_group_box) self.port_spin_box = QtGui.QSpinBox(self.http_settings_group_box)
self.port_spin_box.setMaximum(32767) self.port_spin_box.setMaximum(32767)
self.port_spin_box.setObjectName(u'port_spin_box') self.port_spin_box.setObjectName(u'port_spin_box')
self.http_setting_layout.addRow(self.port_label, self.port_spin_box) self.http_setting_layout.addRow(self.port_label, self.port_spin_box)
self.remote_url_label = QtGui.QLabel(self.http_settings_group_box) self.remote_url_label = QtGui.QLabel(self.http_settings_group_box)
self.remote_url_label.setObjectName(u'remote_url_label') self.remote_url_label.setObjectName(u'remote_url_label')
@ -180,7 +183,7 @@ class RemoteTab(SettingsTab):
self.password_label.setText(translate('RemotePlugin.RemoteTab', 'Password:')) self.password_label.setText(translate('RemotePlugin.RemoteTab', 'Password:'))
def set_urls(self): def set_urls(self):
ipAddress = u'localhost' ip_address = u'localhost'
if self.address_edit.text() == ZERO_URL: if self.address_edit.text() == ZERO_URL:
interfaces = QtNetwork.QNetworkInterface.allInterfaces() interfaces = QtNetwork.QNetworkInterface.allInterfaces()
for interface in interfaces: for interface in interfaces:
@ -191,12 +194,12 @@ class RemoteTab(SettingsTab):
for address in interface.addressEntries(): for address in interface.addressEntries():
ip = address.ip() ip = address.ip()
if ip.protocol() == 0 and ip != QtNetwork.QHostAddress.LocalHost: if ip.protocol() == 0 and ip != QtNetwork.QHostAddress.LocalHost:
ipAddress = ip ip_address = ip
break break
else: else:
ipAddress = self.address_edit.text() ip_address = self.address_edit.text()
http_url = u'http://%s:%s/' % (ipAddress, self.port_spin_box.value()) http_url = u'http://%s:%s/' % (ip_address, self.port_spin_box.value())
https_url = u'https://%s:%s/' % (ipAddress, self.https_port_spin_box.value()) https_url = u'https://%s:%s/' % (ip_address, self.https_port_spin_box.value())
self.remote_url.setText(u'<a href="%s">%s</a>' % (http_url, http_url)) self.remote_url.setText(u'<a href="%s">%s</a>' % (http_url, http_url))
self.remote_https_url.setText(u'<a href="%s">%s</a>' % (https_url, https_url)) self.remote_https_url.setText(u'<a href="%s">%s</a>' % (https_url, https_url))
http_url += u'stage' http_url += u'stage'
@ -243,6 +246,7 @@ class RemoteTab(SettingsTab):
if changed: if changed:
Registry().register_function(u'remotes_config_updated') Registry().register_function(u'remotes_config_updated')
def on_twelve_hour_check_box_changed(self, check_state): def on_twelve_hour_check_box_changed(self, check_state):
self.twelve_hour = False self.twelve_hour = False
# we have a set value convert to True/False # we have a set value convert to True/False

View File

@ -86,7 +86,7 @@ class RemotesPlugin(Plugin):
'browser or through the remote API.') 'browser or through the remote API.')
return about_text return about_text
def setPluginTextStrings(self): def set_plugin_text_strings(self):
""" """
Called to define all translatable texts of the plugin Called to define all translatable texts of the plugin
""" """

View File

@ -291,7 +291,7 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
verse_tags_translated = True verse_tags_translated = True
if index is None: if index is None:
index = VerseType.from_tag(verse_tag) 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'': if verse[0][u'label'] == u'':
verse[0][u'label'] = u'1' verse[0][u'label'] = u'1'
verse_def = u'%s%s' % (verse[0][u'type'], verse[0][u'label']) 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): for count, verse in enumerate(verses):
self.verseListWidget.setRowCount(self.verseListWidget.rowCount() + 1) self.verseListWidget.setRowCount(self.verseListWidget.rowCount() + 1)
item = QtGui.QTableWidgetItem(verse) 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) item.setData(QtCore.Qt.UserRole, verse_def)
self.verseListWidget.setItem(count, 0, item) self.verseListWidget.setItem(count, 0, item)
if self.song.verse_order: 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) verse_index = VerseType.from_translated_tag(verse_def[0], None)
if verse_index is None: if verse_index is None:
verse_index = VerseType.from_tag(verse_def[0]) 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:])) translated.append(u'%s%s' % (verse_tag, verse_def[1:]))
self.verseOrderEdit.setText(u' '.join(translated)) self.verseOrderEdit.setText(u' '.join(translated))
else: else:
@ -547,7 +547,7 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
verse_name = parts verse_name = parts
verse_num = u'1' verse_num = u'1'
verse_index = VerseType.from_loose_input(verse_name) 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. # Later we need to handle v1a as well.
#regex = re.compile(r'(\d+\w.)') #regex = re.compile(r'(\d+\w.)')
regex = re.compile(r'\D*(\d+)\D*') regex = re.compile(r'\D*(\d+)\D*')
@ -599,7 +599,7 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
if len(item) == 1: if len(item) == 1:
verse_index = VerseType.from_translated_tag(item, None) verse_index = VerseType.from_translated_tag(item, None)
if verse_index is not None: if verse_index is not None:
order.append(VerseType.Tags[verse_index] + u'1') order.append(VerseType.tags[verse_index] + u'1')
else: else:
# it matches no verses anyway # it matches no verses anyway
order.append(u'') order.append(u'')
@ -609,7 +609,7 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
# it matches no verses anyway # it matches no verses anyway
order.append(u'') order.append(u'')
else: else:
verse_tag = VerseType.Tags[verse_index] verse_tag = VerseType.tags[verse_index]
verse_num = item[1:].lower() verse_num = item[1:].lower()
order.append(verse_tag + verse_num) order.append(verse_tag + verse_num)
return order return order
@ -831,7 +831,7 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
ordertext = self.verseOrderEdit.text() ordertext = self.verseOrderEdit.text()
order = [] order = []
for item in ordertext.split(): 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() verse_num = item[1:].lower()
order.append(u'%s%s' % (verse_tag, verse_num)) order.append(u'%s%s' % (verse_tag, verse_num))
self.song.verse_order = u' '.join(order) self.song.verse_order = u' '.join(order)
@ -923,6 +923,7 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
self.song.verse_order) self.song.verse_order)
except: except:
log.exception(u'Problem processing song Lyrics \n%s', sxml.dump_xml()) log.exception(u'Problem processing song Lyrics \n%s', sxml.dump_xml())
raise
def _get_plugin_manager(self): def _get_plugin_manager(self):
""" """

View File

@ -74,13 +74,13 @@ class Ui_EditVerseDialog(object):
def retranslateUi(self, editVerseDialog): def retranslateUi(self, editVerseDialog):
editVerseDialog.setWindowTitle(translate('SongsPlugin.EditVerseForm', 'Edit Verse')) editVerseDialog.setWindowTitle(translate('SongsPlugin.EditVerseForm', 'Edit Verse'))
self.verseTypeLabel.setText(translate('SongsPlugin.EditVerseForm', '&Verse type:')) self.verseTypeLabel.setText(translate('SongsPlugin.EditVerseForm', '&Verse type:'))
self.verseTypeComboBox.setItemText(VerseType.Verse, VerseType.TranslatedNames[VerseType.Verse]) self.verseTypeComboBox.setItemText(VerseType.Verse, VerseType.translated_names[VerseType.Verse])
self.verseTypeComboBox.setItemText(VerseType.Chorus, VerseType.TranslatedNames[VerseType.Chorus]) self.verseTypeComboBox.setItemText(VerseType.Chorus, VerseType.translated_names[VerseType.Chorus])
self.verseTypeComboBox.setItemText(VerseType.Bridge, VerseType.TranslatedNames[VerseType.Bridge]) self.verseTypeComboBox.setItemText(VerseType.Bridge, VerseType.translated_names[VerseType.Bridge])
self.verseTypeComboBox.setItemText(VerseType.PreChorus, VerseType.TranslatedNames[VerseType.PreChorus]) self.verseTypeComboBox.setItemText(VerseType.PreChorus, VerseType.translated_names[VerseType.PreChorus])
self.verseTypeComboBox.setItemText(VerseType.Intro, VerseType.TranslatedNames[VerseType.Intro]) self.verseTypeComboBox.setItemText(VerseType.Intro, VerseType.translated_names[VerseType.Intro])
self.verseTypeComboBox.setItemText(VerseType.Ending, VerseType.TranslatedNames[VerseType.Ending]) self.verseTypeComboBox.setItemText(VerseType.Ending, VerseType.translated_names[VerseType.Ending])
self.verseTypeComboBox.setItemText(VerseType.Other, VerseType.TranslatedNames[VerseType.Other]) self.verseTypeComboBox.setItemText(VerseType.Other, VerseType.translated_names[VerseType.Other])
self.splitButton.setText(UiStrings().Split) self.splitButton.setText(UiStrings().Split)
self.splitButton.setToolTip(UiStrings().SplitToolTip) self.splitButton.setToolTip(UiStrings().SplitToolTip)
self.insertButton.setText(translate('SongsPlugin.EditVerseForm', '&Insert')) self.insertButton.setText(translate('SongsPlugin.EditVerseForm', '&Insert'))

View File

@ -82,8 +82,7 @@ class EditVerseForm(QtGui.QDialog, Ui_EditVerseDialog):
def onInsertButtonClicked(self): def onInsertButtonClicked(self):
verse_type_index = self.verseTypeComboBox.currentIndex() verse_type_index = self.verseTypeComboBox.currentIndex()
self.insertVerse(VerseType.Tags[verse_type_index], self.insertVerse(VerseType.tags[verse_type_index], self.verseNumberBox.value())
self.verseNumberBox.value())
def onVerseTypeComboBoxChanged(self): def onVerseTypeComboBoxChanged(self):
self.updateSuggestedVerseNumber() self.updateSuggestedVerseNumber()
@ -93,12 +92,11 @@ class EditVerseForm(QtGui.QDialog, Ui_EditVerseDialog):
def updateSuggestedVerseNumber(self): def updateSuggestedVerseNumber(self):
""" """
Adjusts the verse number SpinBox in regard to the selected verse type Adjusts the verse number SpinBox in regard to the selected verse type and the cursor's position.
and the cursor's position.
""" """
position = self.verseTextEdit.textCursor().position() position = self.verseTextEdit.textCursor().position()
text = self.verseTextEdit.toPlainText() text = self.verseTextEdit.toPlainText()
verse_name = VerseType.TranslatedNames[ verse_name = VerseType.translated_names[
self.verseTypeComboBox.currentIndex()] self.verseTypeComboBox.currentIndex()]
if not text: if not text:
return return
@ -120,8 +118,7 @@ class EditVerseForm(QtGui.QDialog, Ui_EditVerseDialog):
verse_num = 1 verse_num = 1
self.verseNumberBox.setValue(verse_num) self.verseNumberBox.setValue(verse_num)
def setVerse(self, text, single=False, def setVerse(self, text, single=False, tag=u'%s1' % VerseType.tags[VerseType.Verse]):
tag=u'%s1' % VerseType.Tags[VerseType.Verse]):
self.hasSingleVerse = single self.hasSingleVerse = single
if single: if single:
verse_type_index = VerseType.from_tag(tag[0], None) verse_type_index = VerseType.from_tag(tag[0], None)
@ -132,7 +129,7 @@ class EditVerseForm(QtGui.QDialog, Ui_EditVerseDialog):
self.insertButton.setVisible(False) self.insertButton.setVisible(False)
else: else:
if not text: 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.verseTypeComboBox.setCurrentIndex(0)
self.verseNumberBox.setValue(1) self.verseNumberBox.setValue(1)
self.insertButton.setVisible(True) self.insertButton.setVisible(True)
@ -141,12 +138,12 @@ class EditVerseForm(QtGui.QDialog, Ui_EditVerseDialog):
self.verseTextEdit.moveCursor(QtGui.QTextCursor.End) self.verseTextEdit.moveCursor(QtGui.QTextCursor.End)
def getVerse(self): 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()) unicode(self.verseNumberBox.value())
def getVerseAll(self): def getVerseAll(self):
text = self.verseTextEdit.toPlainText() text = self.verseTextEdit.toPlainText()
if not text.startswith(u'---['): if not text.startswith(u'---['):
text = u'---[%s:1]---\n%s' % (VerseType.TranslatedNames[VerseType.Verse], text) text = u'---[%s:1]---\n%s' % (VerseType.translated_names[VerseType.Verse], text)
return text return text

View File

@ -35,7 +35,7 @@ import os
from PyQt4 import QtCore, QtGui from PyQt4 import QtCore, QtGui
from openlp.core.lib import Settings, UiStrings, translate from openlp.core.lib import Registry, Settings, UiStrings, translate
from openlp.core.lib.ui import critical_error_message_box from openlp.core.lib.ui import critical_error_message_box
from openlp.core.ui.wizard import OpenLPWizard, WizardStrings from openlp.core.ui.wizard import OpenLPWizard, WizardStrings
from openlp.plugins.songs.lib.importer import SongFormat, SongFormatSelect from openlp.plugins.songs.lib.importer import SongFormat, SongFormatSelect
@ -489,6 +489,16 @@ class SongImportForm(OpenLPWizard):
self.formatWidgets[this_format][u'importWidget'] = importWidget self.formatWidgets[this_format][u'importWidget'] = importWidget
return importWidget return importWidget
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)
class SongImportSourcePage(QtGui.QWizardPage): class SongImportSourcePage(QtGui.QWizardPage):
""" """

View File

@ -37,8 +37,7 @@ from ui import SongStrings
WHITESPACE = re.compile(r'[\W_]+', re.UNICODE) WHITESPACE = re.compile(r'[\W_]+', re.UNICODE)
APOSTROPHE = re.compile(u'[\'`ʻ]', re.UNICODE) APOSTROPHE = re.compile(u'[\'`ʻ]', re.UNICODE)
PATTERN = re.compile(r"\\([a-z]{1,32})(-?\d{1,10})?[ ]?|\\'" PATTERN = re.compile(r"\\([a-z]{1,32})(-?\d{1,10})?[ ]?|\\'([0-9a-f]{2})|\\([^a-z])|([{}])|[\r\n]+|(.)", re.I)
r"([0-9a-f]{2})|\\([^a-z])|([{}])|[\r\n]+|(.)", re.I)
# RTF control words which specify a "destination" to be ignored. # RTF control words which specify a "destination" to be ignored.
DESTINATIONS = frozenset(( DESTINATIONS = frozenset((
u'aftncn', u'aftnsep', u'aftnsepc', u'annotation', u'atnauthor', u'aftncn', u'aftnsep', u'aftnsepc', u'annotation', u'atnauthor',
@ -138,8 +137,7 @@ CHARSET_MAPPING = {
class VerseType(object): class VerseType(object):
""" """
VerseType provides an enumeration for the tags that may be associated VerseType provides an enumeration for the tags that may be associated with verses in songs.
with verses in songs.
""" """
Verse = 0 Verse = 0
Chorus = 1 Chorus = 1
@ -149,7 +147,7 @@ class VerseType(object):
Ending = 5 Ending = 5
Other = 6 Other = 6
Names = [ names = [
u'Verse', u'Verse',
u'Chorus', u'Chorus',
u'Bridge', u'Bridge',
@ -157,9 +155,9 @@ class VerseType(object):
u'Intro', u'Intro',
u'Ending', u'Ending',
u'Other'] 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', 'Verse'),
translate('SongsPlugin.VerseType', 'Chorus'), translate('SongsPlugin.VerseType', 'Chorus'),
translate('SongsPlugin.VerseType', 'Bridge'), translate('SongsPlugin.VerseType', 'Bridge'),
@ -167,13 +165,12 @@ class VerseType(object):
translate('SongsPlugin.VerseType', 'Intro'), translate('SongsPlugin.VerseType', 'Intro'),
translate('SongsPlugin.VerseType', 'Ending'), translate('SongsPlugin.VerseType', 'Ending'),
translate('SongsPlugin.VerseType', 'Other')] translate('SongsPlugin.VerseType', 'Other')]
TranslatedTags = [name[0].lower() for name in TranslatedNames] translated_tags = [name[0].lower() for name in translated_names]
@staticmethod @staticmethod
def translated_tag(verse_tag, default=Other): def translated_tag(verse_tag, default=Other):
""" """
Return the translated UPPERCASE tag for a given tag, Return the translated UPPERCASE tag for a given tag, used to show translated verse tags in UI
used to show translated verse tags in UI
``verse_tag`` ``verse_tag``
The string to return a VerseType for The string to return a VerseType for
@ -182,11 +179,11 @@ class VerseType(object):
Default return value if no matching tag is found Default return value if no matching tag is found
""" """
verse_tag = verse_tag[0].lower() verse_tag = verse_tag[0].lower()
for num, tag in enumerate(VerseType.Tags): for num, tag in enumerate(VerseType.tags):
if verse_tag == tag: if verse_tag == tag:
return VerseType.TranslatedTags[num].upper() return VerseType.translated_tags[num].upper()
if default in VerseType.TranslatedTags: if default in VerseType.translated_tags:
return VerseType.TranslatedTags[default].upper() return VerseType.translated_tags[default].upper()
@staticmethod @staticmethod
def translated_name(verse_tag, default=Other): def translated_name(verse_tag, default=Other):
@ -200,11 +197,11 @@ class VerseType(object):
Default return value if no matching tag is found Default return value if no matching tag is found
""" """
verse_tag = verse_tag[0].lower() verse_tag = verse_tag[0].lower()
for num, tag in enumerate(VerseType.Tags): for num, tag in enumerate(VerseType.tags):
if verse_tag == tag: if verse_tag == tag:
return VerseType.TranslatedNames[num] return VerseType.translated_names[num]
if default in VerseType.TranslatedNames: if default in VerseType.translated_names:
return VerseType.TranslatedNames[default] return VerseType.translated_names[default]
@staticmethod @staticmethod
def from_tag(verse_tag, default=Other): def from_tag(verse_tag, default=Other):
@ -218,7 +215,7 @@ class VerseType(object):
Default return value if no matching tag is found Default return value if no matching tag is found
""" """
verse_tag = verse_tag[0].lower() verse_tag = verse_tag[0].lower()
for num, tag in enumerate(VerseType.Tags): for num, tag in enumerate(VerseType.tags):
if verse_tag == tag: if verse_tag == tag:
return num return num
return default return default
@ -235,7 +232,7 @@ class VerseType(object):
Default return value if no matching tag is found Default return value if no matching tag is found
""" """
verse_tag = verse_tag[0].lower() 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: if verse_tag == tag:
return num return num
return default return default
@ -252,7 +249,7 @@ class VerseType(object):
Default return value if no matching tag is found Default return value if no matching tag is found
""" """
verse_name = verse_name.lower() verse_name = verse_name.lower()
for num, name in enumerate(VerseType.Names): for num, name in enumerate(VerseType.names):
if verse_name == name.lower(): if verse_name == name.lower():
return num return num
return default return default
@ -266,7 +263,7 @@ class VerseType(object):
The string to return a VerseType for The string to return a VerseType for
""" """
verse_name = verse_name.lower() 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(): if verse_name == translation.lower():
return num return num
@ -296,13 +293,11 @@ class VerseType(object):
def retrieve_windows_encoding(recommendation=None): def retrieve_windows_encoding(recommendation=None):
""" """
Determines which encoding to use on an information source. The process uses Determines which encoding to use on an information source. The process uses both automated detection, which is
both automated detection, which is passed to this method as a passed to this method as a recommendation, and user confirmation to return an encoding.
recommendation, and user confirmation to return an encoding.
``recommendation`` ``recommendation``
A recommended encoding discovered programmatically for the user to A recommended encoding discovered programmatically for the user to confirm.
confirm.
""" """
# map chardet result to compatible windows standard code page # map chardet result to compatible windows standard code page
codepage_mapping = {'IBM866': u'cp866', 'TIS-620': u'cp874', codepage_mapping = {'IBM866': u'cp866', 'TIS-620': u'cp874',
@ -355,24 +350,22 @@ def retrieve_windows_encoding(recommendation=None):
def clean_string(string): 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() return WHITESPACE.sub(u' ', APOSTROPHE.sub(u'', string)).lower()
def clean_title(title): def clean_title(title):
""" """
Cleans the song title by removing Unicode control chars groups C0 & C1, Cleans the song title by removing Unicode control chars groups C0 & C1, as well as any trailing spaces.
as well as any trailing spaces
""" """
return CONTROL_CHARS.sub(u'', title).rstrip() return CONTROL_CHARS.sub(u'', title).rstrip()
def clean_song(manager, song): def clean_song(manager, song):
""" """
Cleans the search title, rebuilds the search lyrics, adds a default author Cleans the search title, rebuilds the search lyrics, adds a default author if the song does not have one and other
if the song does not have one and other clean ups. This should always clean ups. This should always called when a new song is added or changed.
called when a new song is added or changed.
``manager`` ``manager``
The song's 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) 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). # Only do this, if we the song is a 1.9.4 song (or older).
if song.lyrics.find(u'<lyrics language="en">') != -1: if song.lyrics.find(u'<lyrics language="en">') != -1:
# Remove the old "language" attribute from lyrics tag (prior to 1.9.5). # Remove the old "language" attribute from lyrics tag (prior to 1.9.5). This is not very important, but this
# This is not very important, but this keeps the database clean. This # keeps the database clean. This can be removed when everybody has cleaned his songs.
# can be removed when everybody has cleaned his songs.
song.lyrics = song.lyrics.replace(u'<lyrics language="en">', u'<lyrics>') song.lyrics = song.lyrics.replace(u'<lyrics language="en">', u'<lyrics>')
verses = SongXML().get_verses(song.lyrics) verses = SongXML().get_verses(song.lyrics)
song.search_lyrics = u' '.join([clean_string(verse[1]) song.search_lyrics = u' '.join([clean_string(verse[1])
for verse in verses]) for verse in verses])
# We need a new and clean SongXML instance. # We need a new and clean SongXML instance.
sxml = SongXML() sxml = SongXML()
# Rebuild the song's verses, to remove any wrong verse names (for # Rebuild the song's verses, to remove any wrong verse names (for example translated ones), which might have
# example translated ones), which might have been added prior to 1.9.5. # been added prior to 1.9.5.
# List for later comparison. # List for later comparison.
compare_order = [] compare_order = []
for verse in verses: 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( sxml.add_verse_to_lyrics(
verse_type, verse_type,
verse[0][u'label'], verse[0][u'label'],
@ -422,15 +414,14 @@ def clean_song(manager, song):
if verse[0][u'label'] == u'1': if verse[0][u'label'] == u'1':
compare_order.append(verse_type.upper()) compare_order.append(verse_type.upper())
song.lyrics = unicode(sxml.extract_xml(), u'utf-8') song.lyrics = unicode(sxml.extract_xml(), u'utf-8')
# Rebuild the verse order, to convert translated verse tags, which might # Rebuild the verse order, to convert translated verse tags, which might have been added prior to 1.9.5.
# have been added prior to 1.9.5.
if song.verse_order: if song.verse_order:
order = CONTROL_CHARS.sub(u'', song.verse_order).strip().split() order = CONTROL_CHARS.sub(u'', song.verse_order).strip().split()
else: else:
order = [] order = []
new_order = [] new_order = []
for verse_def in order: for verse_def in order:
verse_type = VerseType.Tags[ verse_type = VerseType.tags[
VerseType.from_loose_input(verse_def[0])] VerseType.from_loose_input(verse_def[0])]
if len(verse_def) > 1: if len(verse_def) > 1:
new_order.append((u'%s%s' % (verse_type, verse_def[1:])).upper()) new_order.append((u'%s%s' % (verse_type, verse_def[1:])).upper())
@ -589,8 +580,7 @@ def strip_rtf(text, default_encoding=None):
def natcmp(a, b): def natcmp(a, b):
""" """
Natural string comparison which mimics the behaviour of Python's internal Natural string comparison which mimics the behaviour of Python's internal cmp function.
cmp function.
""" """
if len(a) <= len(b): if len(a) <= len(b):
for i, key in enumerate(a): for i, key in enumerate(a):

View File

@ -188,13 +188,13 @@ class CCLIFileImport(SongImport):
words_list = song_words.split(u'/t') words_list = song_words.split(u'/t')
for counter in range(len(field_list)): for counter in range(len(field_list)):
if field_list[counter].startswith(u'Ver'): 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'): 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'): elif field_list[counter].startswith(u'Br'):
verse_type = VerseType.Tags[VerseType.Bridge] verse_type = VerseType.tags[VerseType.Bridge]
else: else:
verse_type = VerseType.Tags[VerseType.Other] verse_type = VerseType.tags[VerseType.Other]
check_first_verse_line = True check_first_verse_line = True
verse_text = unicode(words_list[counter]) verse_text = unicode(words_list[counter])
verse_text = verse_text.replace(u'/n', u'\n') verse_text = verse_text.replace(u'/n', u'\n')
@ -202,15 +202,15 @@ class CCLIFileImport(SongImport):
verse_lines = verse_text.split(u'\n', 1) verse_lines = verse_text.split(u'\n', 1)
if check_first_verse_line: if check_first_verse_line:
if verse_lines[0].startswith(u'(PRE-CHORUS'): 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]) log.debug(u'USR verse PRE-CHORUS: %s', verse_lines[0])
verse_text = verse_lines[1] verse_text = verse_lines[1]
elif verse_lines[0].startswith(u'(BRIDGE'): 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') log.debug(u'USR verse BRIDGE')
verse_text = verse_lines[1] verse_text = verse_lines[1]
elif verse_lines[0].startswith(u'('): elif verse_lines[0].startswith(u'('):
verse_type = VerseType.Tags[VerseType.Other] verse_type = VerseType.tags[VerseType.Other]
verse_text = verse_lines[1] verse_text = verse_lines[1]
if verse_text: if verse_text:
self.addVerse(verse_text, verse_type) self.addVerse(verse_text, verse_type)
@ -292,31 +292,31 @@ class CCLIFileImport(SongImport):
verse_desc_parts = clean_line.split(u' ') verse_desc_parts = clean_line.split(u' ')
if len(verse_desc_parts) == 2: if len(verse_desc_parts) == 2:
if verse_desc_parts[0].startswith(u'Ver'): 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'): 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'): elif verse_desc_parts[0].startswith(u'Br'):
verse_type = VerseType.Tags[VerseType.Bridge] verse_type = VerseType.tags[VerseType.Bridge]
else: else:
# we need to analyse the next line for # we need to analyse the next line for
# verse type, so set flag # verse type, so set flag
verse_type = VerseType.Tags[VerseType.Other] verse_type = VerseType.tags[VerseType.Other]
check_first_verse_line = True check_first_verse_line = True
verse_number = verse_desc_parts[1] verse_number = verse_desc_parts[1]
else: else:
verse_type = VerseType.Tags[VerseType.Other] verse_type = VerseType.tags[VerseType.Other]
verse_number = 1 verse_number = 1
verse_start = True verse_start = True
else: else:
# check first line for verse type # check first line for verse type
if check_first_verse_line: if check_first_verse_line:
if line.startswith(u'(PRE-CHORUS'): if line.startswith(u'(PRE-CHORUS'):
verse_type = VerseType.Tags[VerseType.PreChorus] verse_type = VerseType.tags[VerseType.PreChorus]
elif line.startswith(u'(BRIDGE'): elif line.startswith(u'(BRIDGE'):
verse_type = VerseType.Tags[VerseType.Bridge] verse_type = VerseType.tags[VerseType.Bridge]
# Handle all other misc types # Handle all other misc types
elif line.startswith(u'('): elif line.startswith(u'('):
verse_type = VerseType.Tags[VerseType.Other] verse_type = VerseType.tags[VerseType.Other]
else: else:
verse_text = verse_text + line verse_text = verse_text + line
check_first_verse_line = False check_first_verse_line = False

View File

@ -175,12 +175,12 @@ class EasySlidesImport(SongImport):
# if the regions are inside verses # if the regions are inside verses
regionsInVerses = (regions and regionlines[regionlines.keys()[0]] > 1) regionsInVerses = (regions and regionlines[regionlines.keys()[0]] > 1)
MarkTypes = { MarkTypes = {
u'CHORUS': VerseType.Tags[VerseType.Chorus], u'CHORUS': VerseType.tags[VerseType.Chorus],
u'VERSE': VerseType.Tags[VerseType.Verse], u'VERSE': VerseType.tags[VerseType.Verse],
u'INTRO': VerseType.Tags[VerseType.Intro], u'INTRO': VerseType.tags[VerseType.Intro],
u'ENDING': VerseType.Tags[VerseType.Ending], u'ENDING': VerseType.tags[VerseType.Ending],
u'BRIDGE': VerseType.Tags[VerseType.Bridge], u'BRIDGE': VerseType.tags[VerseType.Bridge],
u'PRECHORUS': VerseType.Tags[VerseType.PreChorus] u'PRECHORUS': VerseType.tags[VerseType.PreChorus]
} }
verses = {} verses = {}
# list as [region, versetype, versenum, instance] # list as [region, versetype, versenum, instance]

View File

@ -178,7 +178,7 @@ class EasyWorshipSongImport(SongImport):
if result is None: if result is None:
return return
words, self.encoding = result words, self.encoding = result
verse_type = VerseType.Tags[VerseType.Verse] verse_type = VerseType.tags[VerseType.Verse]
for verse in SLIDE_BREAK_REGEX.split(words): for verse in SLIDE_BREAK_REGEX.split(words):
verse = verse.strip() verse = verse.strip()
if not verse: if not verse:
@ -187,17 +187,17 @@ class EasyWorshipSongImport(SongImport):
first_line_is_tag = False first_line_is_tag = False
# EW tags: verse, chorus, pre-chorus, bridge, tag, # EW tags: verse, chorus, pre-chorus, bridge, tag,
# intro, ending, slide # intro, ending, slide
for type in VerseType.Names+[u'tag', u'slide']: for tag in VerseType.tags + [u'tag', u'slide']:
type = type.lower() tag = tag.lower()
ew_tag = verse_split[0].strip().lower() ew_tag = verse_split[0].strip().lower()
if ew_tag.startswith(type): if ew_tag.startswith(tag):
verse_type = type[0] verse_type = tag[0]
if type == u'tag' or type == u'slide': if tag == u'tag' or tag == u'slide':
verse_type = VerseType.Tags[VerseType.Other] verse_type = VerseType.tags[VerseType.Other]
first_line_is_tag = True first_line_is_tag = True
number_found = False number_found = False
# check if tag is followed by number and/or note # 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) match = NUMBER_REGEX.search(ew_tag)
if match: if match:
number = match.group() number = match.group()
@ -209,10 +209,7 @@ class EasyWorshipSongImport(SongImport):
if not number_found: if not number_found:
verse_type += u'1' verse_type += u'1'
break break
self.addVerse( self.addVerse(verse_split[-1].strip() if first_line_is_tag else verse, verse_type)
verse_split[-1].strip() \
if first_line_is_tag else verse,
verse_type)
if len(self.comments) > 5: if len(self.comments) > 5:
self.comments += unicode(translate('SongsPlugin.EasyWorshipSongImport', self.comments += unicode(translate('SongsPlugin.EasyWorshipSongImport',
'\n[above are Song Tags with notes imported from EasyWorship]')) '\n[above are Song Tags with notes imported from EasyWorship]'))
@ -224,8 +221,7 @@ class EasyWorshipSongImport(SongImport):
self.memoFile.close() self.memoFile.close()
def findField(self, field_name): def findField(self, field_name):
return [i for i, x in enumerate(self.fieldDescs) return [i for i, x in enumerate(self.fieldDescs) if x.name == field_name][0]
if x.name == field_name][0]
def setRecordStruct(self, field_descs): def setRecordStruct(self, field_descs):
# Begin with empty field struct list # Begin with empty field struct list

View File

@ -412,13 +412,13 @@ class FoilPresenter(object):
temp_sortnr_backup = 1 temp_sortnr_backup = 1
temp_sortnr_liste = [] temp_sortnr_liste = []
verse_count = { verse_count = {
VerseType.Tags[VerseType.Verse]: 1, VerseType.tags[VerseType.Verse]: 1,
VerseType.Tags[VerseType.Chorus]: 1, VerseType.tags[VerseType.Chorus]: 1,
VerseType.Tags[VerseType.Bridge]: 1, VerseType.tags[VerseType.Bridge]: 1,
VerseType.Tags[VerseType.Ending]: 1, VerseType.tags[VerseType.Ending]: 1,
VerseType.Tags[VerseType.Other]: 1, VerseType.tags[VerseType.Other]: 1,
VerseType.Tags[VerseType.Intro]: 1, VerseType.tags[VerseType.Intro]: 1,
VerseType.Tags[VerseType.PreChorus]: 1 VerseType.tags[VerseType.PreChorus]: 1
} }
for strophe in foilpresenterfolie.strophen.strophe: for strophe in foilpresenterfolie.strophen.strophe:
text = self._child(strophe.text_) if hasattr(strophe, u'text_') else u'' 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 = re.compile(u'[0-9].*').sub(u'', verse_name)
temp_verse_name = temp_verse_name[:3].lower() temp_verse_name = temp_verse_name[:3].lower()
if temp_verse_name == u'ref': if temp_verse_name == u'ref':
verse_type = VerseType.Tags[VerseType.Chorus] verse_type = VerseType.tags[VerseType.Chorus]
elif temp_verse_name == u'r': elif temp_verse_name == u'r':
verse_type = VerseType.Tags[VerseType.Chorus] verse_type = VerseType.tags[VerseType.Chorus]
elif temp_verse_name == u'': elif temp_verse_name == u'':
verse_type = VerseType.Tags[VerseType.Verse] verse_type = VerseType.tags[VerseType.Verse]
elif temp_verse_name == u'v': elif temp_verse_name == u'v':
verse_type = VerseType.Tags[VerseType.Verse] verse_type = VerseType.tags[VerseType.Verse]
elif temp_verse_name == u'bri': elif temp_verse_name == u'bri':
verse_type = VerseType.Tags[VerseType.Bridge] verse_type = VerseType.tags[VerseType.Bridge]
elif temp_verse_name == u'cod': elif temp_verse_name == u'cod':
verse_type = VerseType.Tags[VerseType.Ending] verse_type = VerseType.tags[VerseType.Ending]
elif temp_verse_name == u'sch': elif temp_verse_name == u'sch':
verse_type = VerseType.Tags[VerseType.Ending] verse_type = VerseType.tags[VerseType.Ending]
elif temp_verse_name == u'pre': elif temp_verse_name == u'pre':
verse_type = VerseType.Tags[VerseType.PreChorus] verse_type = VerseType.tags[VerseType.PreChorus]
elif temp_verse_name == u'int': elif temp_verse_name == u'int':
verse_type = VerseType.Tags[VerseType.Intro] verse_type = VerseType.tags[VerseType.Intro]
else: 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) verse_number = re.compile(u'[a-zA-Z.+-_ ]*').sub(u'', verse_name)
# Foilpresenter allows e. g. "C", but we need "C1". # Foilpresenter allows e. g. "C", but we need "C1".
if not verse_number: if not verse_number:
@ -469,7 +469,7 @@ class FoilPresenter(object):
if value == u''.join((verse_type, verse_number)): if value == u''.join((verse_type, verse_number)):
verse_number = unicode(int(verse_number) + 1) verse_number = unicode(int(verse_number) + 1)
verse_type_index = VerseType.from_tag(verse_type[0]) 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], temp_verse_order[verse_sortnr] = u''.join((verse_type[0],
verse_number)) verse_number))
temp_verse_order_backup.append(u''.join((verse_type[0], temp_verse_order_backup.append(u''.join((verse_type[0],

View File

@ -430,7 +430,7 @@ class SongMediaItem(MediaManagerItem):
verse_index = VerseType.from_string(verse_tag, None) verse_index = VerseType.from_string(verse_tag, None)
if verse_index is None: if verse_index is None:
verse_index = VerseType.from_tag(verse_tag) 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']) verse_def = u'%s%s' % (verse_tag, verse[0][u'label'])
service_item.add_from_text(unicode(verse[1]), verse_def) service_item.add_from_text(unicode(verse[1]), verse_def)
else: else:
@ -445,7 +445,7 @@ class SongMediaItem(MediaManagerItem):
verse_index = VerseType.from_translated_tag(verse[0][u'type']) verse_index = VerseType.from_translated_tag(verse[0][u'type'])
else: else:
verse_index = VerseType.from_tag(verse[0][u'type']) 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']) verse_def = u'%s%s' % (verse_tag, verse[0][u'label'])
service_item.add_from_text(verse[1], verse_def) service_item.add_from_text(verse[1], verse_def)
else: else:

View File

@ -160,7 +160,7 @@ class OpenSongImport(SongImport):
# keep track of verses appearance order # keep track of verses appearance order
our_verse_order = [] our_verse_order = []
# default verse # default verse
verse_tag = VerseType.Tags[VerseType.Verse] verse_tag = VerseType.tags[VerseType.Verse]
verse_num = u'1' verse_num = u'1'
# for the case where song has several sections with same marker # for the case where song has several sections with same marker
inst = 1 inst = 1
@ -184,21 +184,18 @@ class OpenSongImport(SongImport):
# drop the square brackets # drop the square brackets
right_bracket = this_line.find(u']') right_bracket = this_line.find(u']')
content = this_line[1:right_bracket].lower() content = this_line[1:right_bracket].lower()
# have we got any digits? # have we got any digits? If so, verse number is everything from the digits to the end (openlp does not
# If so, verse number is everything from the digits # have concept of part verses, so just ignore any non integers on the end (including floats))
# 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) match = re.match(u'(\D*)(\d+)', content)
if match is not None: if match is not None:
verse_tag = match.group(1) verse_tag = match.group(1)
verse_num = match.group(2) verse_num = match.group(2)
else: else:
# otherwise we assume number 1 and take the whole prefix as # otherwise we assume number 1 and take the whole prefix as the verse tag
# the verse tag
verse_tag = content verse_tag = content
verse_num = u'1' verse_num = u'1'
verse_index = VerseType.from_loose_input(verse_tag) if verse_tag else 0 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 inst = 1
if [verse_tag, verse_num, inst] in our_verse_order and verse_num in verses.get(verse_tag, {}): 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 inst = len(verses[verse_tag][verse_num]) + 1
@ -236,8 +233,8 @@ class OpenSongImport(SongImport):
# figure out the presentation order, if present # figure out the presentation order, if present
if u'presentation' in fields and root.presentation: if u'presentation' in fields and root.presentation:
order = unicode(root.presentation) order = unicode(root.presentation)
# We make all the tags in the lyrics lower case, so match that here # We make all the tags in the lyrics lower case, so match that here and then split into a list on the
# and then split into a list on the whitespace # whitespace.
order = order.lower().split() order = order.lower().split()
for verse_def in order: for verse_def in order:
match = re.match(u'(\D*)(\d+.*)', verse_def) match = re.match(u'(\D*)(\d+.*)', verse_def)
@ -245,7 +242,7 @@ class OpenSongImport(SongImport):
verse_tag = match.group(1) verse_tag = match.group(1)
verse_num = match.group(2) verse_num = match.group(2)
if not verse_tag: if not verse_tag:
verse_tag = VerseType.Tags[VerseType.Verse] verse_tag = VerseType.tags[VerseType.Verse]
else: else:
# Assume it's no.1 if there are no digits # Assume it's no.1 if there are no digits
verse_tag = verse_def verse_tag = verse_def

View File

@ -27,8 +27,7 @@
# Temple Place, Suite 330, Boston, MA 02111-1307 USA # # Temple Place, Suite 330, Boston, MA 02111-1307 USA #
############################################################################### ###############################################################################
""" """
The :mod:`songbeamerimport` module provides the functionality for importing The :mod:`songbeamerimport` module provides the functionality for importing SongBeamer songs into the OpenLP database.
SongBeamer songs into the OpenLP database.
""" """
import chardet import chardet
import codecs import codecs
@ -43,32 +42,31 @@ log = logging.getLogger(__name__)
class SongBeamerTypes(object): class SongBeamerTypes(object):
MarkTypes = { MarkTypes = {
u'Refrain': VerseType.Tags[VerseType.Chorus], u'Refrain': VerseType.tags[VerseType.Chorus],
u'Chorus': VerseType.Tags[VerseType.Chorus], u'Chorus': VerseType.tags[VerseType.Chorus],
u'Vers': VerseType.Tags[VerseType.Verse], u'Vers': VerseType.tags[VerseType.Verse],
u'Verse': VerseType.Tags[VerseType.Verse], u'Verse': VerseType.tags[VerseType.Verse],
u'Strophe': VerseType.Tags[VerseType.Verse], u'Strophe': VerseType.tags[VerseType.Verse],
u'Intro': VerseType.Tags[VerseType.Intro], u'Intro': VerseType.tags[VerseType.Intro],
u'Coda': VerseType.Tags[VerseType.Ending], u'Coda': VerseType.tags[VerseType.Ending],
u'Ending': VerseType.Tags[VerseType.Ending], u'Ending': VerseType.tags[VerseType.Ending],
u'Bridge': VerseType.Tags[VerseType.Bridge], u'Bridge': VerseType.tags[VerseType.Bridge],
u'Interlude': VerseType.Tags[VerseType.Bridge], u'Interlude': VerseType.tags[VerseType.Bridge],
u'Zwischenspiel': VerseType.Tags[VerseType.Bridge], u'Zwischenspiel': VerseType.tags[VerseType.Bridge],
u'Pre-Chorus': VerseType.Tags[VerseType.PreChorus], u'Pre-Chorus': VerseType.tags[VerseType.PreChorus],
u'Pre-Refrain': VerseType.Tags[VerseType.PreChorus], u'Pre-Refrain': VerseType.tags[VerseType.PreChorus],
u'Pre-Bridge': VerseType.Tags[VerseType.Other], u'Pre-Bridge': VerseType.tags[VerseType.Other],
u'Pre-Coda': VerseType.Tags[VerseType.Other], u'Pre-Coda': VerseType.tags[VerseType.Other],
u'Unbekannt': VerseType.Tags[VerseType.Other], u'Unbekannt': VerseType.tags[VerseType.Other],
u'Unknown': VerseType.Tags[VerseType.Other], u'Unknown': VerseType.tags[VerseType.Other],
u'Unbenannt': VerseType.Tags[VerseType.Other] u'Unbenannt': VerseType.tags[VerseType.Other]
} }
class SongBeamerImport(SongImport): class SongBeamerImport(SongImport):
""" """
Import Song Beamer files(s) Import Song Beamer files(s). Song Beamer file format is text based in the beginning are one or more control tags
Song Beamer file format is text based written.
in the beginning are one or more control tags written
""" """
HTML_TAG_PAIRS = [ HTML_TAG_PAIRS = [
(re.compile(u'<b>'), u'{st}'), (re.compile(u'<b>'), u'{st}'),
@ -113,7 +111,7 @@ class SongBeamerImport(SongImport):
return return
self.setDefaults() self.setDefaults()
self.currentVerse = u'' self.currentVerse = u''
self.currentVerseType = VerseType.Tags[VerseType.Verse] self.currentVerseType = VerseType.tags[VerseType.Verse]
read_verses = False read_verses = False
file_name = os.path.split(file)[1] file_name = os.path.split(file)[1]
if os.path.isfile(file): if os.path.isfile(file):
@ -137,7 +135,7 @@ class SongBeamerImport(SongImport):
self.replaceHtmlTags() self.replaceHtmlTags()
self.addVerse(self.currentVerse, self.currentVerseType) self.addVerse(self.currentVerse, self.currentVerseType)
self.currentVerse = u'' self.currentVerse = u''
self.currentVerseType = VerseType.Tags[VerseType.Verse] self.currentVerseType = VerseType.tags[VerseType.Verse]
read_verses = True read_verses = True
verse_start = True verse_start = True
elif read_verses: elif read_verses:
@ -155,8 +153,7 @@ class SongBeamerImport(SongImport):
def replaceHtmlTags(self): def replaceHtmlTags(self):
""" """
This can be called to replace SongBeamer's specific (html) tags with This can be called to replace SongBeamer's specific (html) tags with OpenLP's specific (html) tags.
OpenLP's specific (html) tags.
""" """
for pair in SongBeamerImport.HTML_TAG_PAIRS: for pair in SongBeamerImport.HTML_TAG_PAIRS:
self.currentVerse = pair[0].sub(pair[1], self.currentVerse) self.currentVerse = pair[0].sub(pair[1], self.currentVerse)
@ -166,8 +163,7 @@ class SongBeamerImport(SongImport):
Parses a meta data line. Parses a meta data line.
``line`` ``line``
The line in the file. It should consist of a tag and a value The line in the file. It should consist of a tag and a value for this tag (unicode)::
for this tag (unicode)::
u'#Title=Nearer my God to Thee' u'#Title=Nearer my God to Thee'
""" """
@ -272,8 +268,8 @@ class SongBeamerImport(SongImport):
def checkVerseMarks(self, line): def checkVerseMarks(self, line):
""" """
Check and add the verse's MarkType. Returns ``True`` if the given line Check and add the verse's MarkType. Returns ``True`` if the given linE contains a correct verse mark otherwise
contains a correct verse mark otherwise ``False``. ``False``.
``line`` ``line``
The line to check for marks (unicode). The line to check for marks (unicode).

View File

@ -303,13 +303,13 @@ class SongImport(QtCore.QObject):
sxml = SongXML() sxml = SongXML()
other_count = 1 other_count = 1
for (verse_def, verse_text, lang) in self.verses: 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() verse_tag = verse_def[0].lower()
else: 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 verses_changed_to_other[verse_def] = new_verse_def
other_count += 1 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) log.info(u'Versetype %s changing to %s', verse_def, new_verse_def)
verse_def = new_verse_def verse_def = new_verse_def
sxml.add_verse_to_lyrics(verse_tag, verse_def[1:], verse_text, lang) sxml.add_verse_to_lyrics(verse_tag, verse_def[1:], verse_text, lang)

View File

@ -152,11 +152,11 @@ class SongShowPlusImport(SongImport):
elif block_key == CCLI_NO: elif block_key == CCLI_NO:
self.ccliNumber = int(data) self.ccliNumber = int(data)
elif block_key == VERSE: 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: 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: 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: elif block_key == TOPIC:
self.topics.append(unicode(data, u'cp1252')) self.topics.append(unicode(data, u'cp1252'))
elif block_key == COMMENTS: elif block_key == COMMENTS:
@ -192,19 +192,19 @@ class SongShowPlusImport(SongImport):
verse_number = "1" verse_number = "1"
verse_type = verse_type.lower() verse_type = verse_type.lower()
if verse_type == "verse": if verse_type == "verse":
verse_tag = VerseType.Tags[VerseType.Verse] verse_tag = VerseType.tags[VerseType.Verse]
elif verse_type == "chorus": elif verse_type == "chorus":
verse_tag = VerseType.Tags[VerseType.Chorus] verse_tag = VerseType.tags[VerseType.Chorus]
elif verse_type == "bridge": elif verse_type == "bridge":
verse_tag = VerseType.Tags[VerseType.Bridge] verse_tag = VerseType.tags[VerseType.Bridge]
elif verse_type == "pre-chorus": elif verse_type == "pre-chorus":
verse_tag = VerseType.Tags[VerseType.PreChorus] verse_tag = VerseType.tags[VerseType.PreChorus]
else: else:
if verse_name not in self.otherList: if verse_name not in self.otherList:
if ignore_unique: if ignore_unique:
return None return None
self.otherCount += 1 self.otherCount += 1
self.otherList[verse_name] = str(self.otherCount) 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] verse_number = self.otherList[verse_name]
return verse_tag + verse_number return verse_tag + verse_number

View File

@ -52,8 +52,7 @@ class SundayPlusImport(SongImport):
""" """
Import Sunday Plus songs Import Sunday Plus songs
The format examples can be found attached to bug report at The format examples can be found attached to bug report at <http://support.openlp.org/issues/395>
<http://support.openlp.org/issues/395>
""" """
def __init__(self, manager, **kwargs): def __init__(self, manager, **kwargs):
@ -90,7 +89,7 @@ class SundayPlusImport(SongImport):
self.logError(u'File is malformed') self.logError(u'File is malformed')
return False return False
i = 1 i = 1
verse_type = VerseType.Tags[VerseType.Verse] verse_type = VerseType.tags[VerseType.Verse]
while i < len(data): while i < len(data):
# Data is held as #name: value pairs inside groups marked as []. # Data is held as #name: value pairs inside groups marked as [].
# Now we are looking for the name. # Now we are looking for the name.
@ -137,8 +136,7 @@ class SundayPlusImport(SongImport):
if name == 'MARKER_NAME': if name == 'MARKER_NAME':
value = value.strip() value = value.strip()
if len(value): if len(value):
verse_type = VerseType.Tags[ verse_type = VerseType.tags[VerseType.from_loose_input(value[0])]
VerseType.from_loose_input(value[0])]
if len(value) >= 2 and value[-1] in ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']: 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]) verse_type = "%s%s" % (verse_type, value[-1])
elif name == 'Hotkey': elif name == 'Hotkey':
@ -168,8 +166,7 @@ class SundayPlusImport(SongImport):
self.copyright = u'Public Domain' self.copyright = u'Public Domain'
continue continue
processed_lines.append(line) processed_lines.append(line)
self.addVerse('\n'.join(processed_lines).strip(), self.addVerse('\n'.join(processed_lines).strip(), verse_type)
verse_type)
if end == -1: if end == -1:
break break
i = end + 1 i = end + 1

View File

@ -97,10 +97,8 @@ class SongXML(object):
Add a verse to the ``<lyrics>`` tag. Add a verse to the ``<lyrics>`` tag.
``type`` ``type``
A string denoting the type of verse. Possible values are *v*, A string denoting the type of verse. Possible values are *v*, *c*, *b*, *p*, *i*, *e* and *o*. Any other
*c*, *b*, *p*, *i*, *e* and *o*. type is **not** allowed, this also includes translated types.
Any other type is **not** allowed, this also includes translated
types.
``number`` ``number``
An integer denoting the number of the item, for example: verse 1. 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. The actual text of the verse to be stored.
``lang`` ``lang``
The verse's language code (ISO-639). This is not required, but The verse's language code (ISO-639). This is not required, but should be added if available.
should be added if available.
""" """
verse = etree.Element(u'verse', type=unicode(type), verse = etree.Element(u'verse', type=unicode(type),
label=unicode(number)) label=unicode(number))
@ -128,24 +125,21 @@ class SongXML(object):
def get_verses(self, xml): def get_verses(self, xml):
""" """
Iterates through the verses in the XML and returns a list of verses Iterates through the verses in the XML and returns a list of verses and their attributes.
and their attributes.
``xml`` ``xml``
The XML of the song to be parsed. The XML of the song to be parsed.
The returned list has the following format:: The returned list has the following format::
[[{'type': 'v', 'label': '1'}, [[{'type': 'v', 'label': '1'}, u"optional slide split 1[---]optional slide split 2"],
u"optional slide split 1[---]optional slide split 2"],
[{'lang': 'en', 'type': 'c', 'label': '1'}, u"English chorus"]] [{'lang': 'en', 'type': 'c', 'label': '1'}, u"English chorus"]]
""" """
self.song_xml = None self.song_xml = None
verse_list = [] verse_list = []
if not xml.startswith(u'<?xml') and not xml.startswith(u'<song'): 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 # This is an old style song, without XML. Let's handle it correctly by iterating through the verses, and
# by iterating through the verses, and then recreating the internal # then recreating the internal xml object as well.
# xml object as well.
self.song_xml = objectify.fromstring(u'<song version="1.0" />') self.song_xml = objectify.fromstring(u'<song version="1.0" />')
self.lyrics = etree.SubElement(self.song_xml, u'lyrics') self.lyrics = etree.SubElement(self.song_xml, u'lyrics')
verses = xml.split(u'\n\n') verses = xml.split(u'\n\n')
@ -176,11 +170,10 @@ class SongXML(object):
class OpenLyrics(object): class OpenLyrics(object):
""" """
This class represents the converter for OpenLyrics XML (version 0.8) This class represents the converter for OpenLyrics XML (version 0.8) to/from a song.
to/from a song.
As OpenLyrics has a rich set of different features, we cannot support them As OpenLyrics has a rich set of different features, we cannot support them all. The following features are
all. The following features are supported by the :class:`OpenLyrics` class: supported by the :class:`OpenLyrics` class:
``<authors>`` ``<authors>``
OpenLP does not support the attribute *type* and *lang*. OpenLP does not support the attribute *type* and *lang*.
@ -189,8 +182,7 @@ class OpenLyrics(object):
This property is not supported. This property is not supported.
``<comments>`` ``<comments>``
The ``<comments>`` property is fully supported. But comments in lyrics The ``<comments>`` property is fully supported. But comments in lyrics are not supported.
are not supported.
``<copyright>`` ``<copyright>``
This property is fully supported. This property is fully supported.
@ -208,23 +200,20 @@ class OpenLyrics(object):
This property is not supported. This property is not supported.
``<lines>`` ``<lines>``
The attribute *part* is not supported. The *break* attribute is The attribute *part* is not supported. The *break* attribute is supported.
supported.
``<publisher>`` ``<publisher>``
This property is not supported. This property is not supported.
``<songbooks>`` ``<songbooks>``
As OpenLP does only support one songbook, we cannot consider more than As OpenLP does only support one songbook, we cannot consider more than one songbook.
one songbook.
``<tempo>`` ``<tempo>``
This property is not supported. This property is not supported.
``<themes>`` ``<themes>``
Topics, as they are called in OpenLP, are fully supported, whereby only Topics, as they are called in OpenLP, are fully supported, whereby only the topic text (e. g. Grace) is
the topic text (e. g. Grace) is considered, but neither the *id* nor considered, but neither the *id* nor *lang*.
*lang*.
``<transposition>`` ``<transposition>``
This property is not supported. This property is not supported.
@ -233,9 +222,8 @@ class OpenLyrics(object):
This property is not supported. This property is not supported.
``<verse name="v1a" lang="he" translit="en">`` ``<verse name="v1a" lang="he" translit="en">``
The attribute *translit* is not supported. Note, the attribute *lang* is The attribute *translit* is not supported. Note, the attribute *lang* is considered, but there is not further
considered, but there is not further functionality implemented yet. The functionality implemented yet. The following verse "types" are supported by OpenLP:
following verse "types" are supported by OpenLP:
* v * v
* c * c
@ -245,13 +233,10 @@ class OpenLyrics(object):
* e * e
* o * o
The verse "types" stand for *Verse*, *Chorus*, *Bridge*, *Pre-Chorus*, The verse "types" stand for *Verse*, *Chorus*, *Bridge*, *Pre-Chorus*, *Intro*, *Ending* and *Other*. Any
*Intro*, *Ending* and *Other*. Any numeric value is allowed after the numeric value is allowed after the verse type. The complete verse name in OpenLP always consists of the verse
verse type. The complete verse name in OpenLP always consists of the type and the verse number. If not number is present *1* is assumed. OpenLP will merge verses which are split
verse type and the verse number. If not number is present *1* is up by appending a letter to the verse name, such as *v1a*.
assumed.
OpenLP will merge verses which are split up by appending a letter to the
verse name, such as *v1a*.
``<verseOrder>`` ``<verseOrder>``
OpenLP supports this property. OpenLP supports this property.
@ -359,17 +344,14 @@ class OpenLyrics(object):
def _get_missing_tags(self, text): def _get_missing_tags(self, text):
""" """
Tests the given text for not closed formatting tags and returns a tuple Tests the given text for not closed formatting tags and returns a tuple consisting of two unicode strings::
consisting of two unicode strings::
(u'{st}{r}', u'{/r}{/st}') (u'{st}{r}', u'{/r}{/st}')
The first unicode string are the start tags (for the next slide). The The first unicode string are the start tags (for the next slide). The second unicode string are the end tags.
second unicode string are the end tags.
``text`` ``text``
The text to test. The text must **not** contain html tags, only The text to test. The text must **not** contain html tags, only OpenLP formatting tags are allowed::
OpenLP formatting tags are allowed::
{st}{r}Text text text {st}{r}Text text text
""" """
@ -379,9 +361,8 @@ class OpenLyrics(object):
continue continue
if text.count(tag[u'start tag']) != text.count(tag[u'end tag']): 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'])) 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 # Sort the lists, so that the tags which were opened first on the first slide (the text we are checking) will
# slide (the text we are checking) will be opened first on the next # be opened first on the next slide as well.
# slide as well.
tags.sort(key=lambda tag: tag[0]) tags.sort(key=lambda tag: tag[0])
end_tags = [] end_tags = []
start_tags = [] start_tags = []
@ -393,16 +374,15 @@ class OpenLyrics(object):
def xml_to_song(self, xml, parse_and_temporary_save=False): def xml_to_song(self, xml, parse_and_temporary_save=False):
""" """
Create and save a song from OpenLyrics format xml to the database. Since Create and save a song from OpenLyrics format xml to the database. Since we also export XML from external
we also export XML from external sources (e. g. OpenLyrics import), we sources (e. g. OpenLyrics import), we cannot ensure, that it completely conforms to the OpenLyrics standard.
cannot ensure, that it completely conforms to the OpenLyrics standard.
``xml`` ``xml``
The XML to parse (unicode). The XML to parse (unicode).
``parse_and_temporary_save`` ``parse_and_temporary_save``
Switch to skip processing the whole song and storing the songs in Switch to skip processing the whole song and storing the songs in the database with a temporary flag.
the database with a temporary flag. Defaults to ``False``. Defaults to ``False``.
""" """
# No xml get out of here. # No xml get out of here.
if not xml: if not xml:
@ -448,8 +428,7 @@ class OpenLyrics(object):
def _add_tag_to_formatting(self, tag_name, tags_element): def _add_tag_to_formatting(self, tag_name, tags_element):
""" """
Add new formatting tag to the element ``<format>`` if the tag is not Add new formatting tag to the element ``<format>`` if the tag is not present yet.
present yet.
""" """
available_tags = FormattingTags.get_html_tags() available_tags = FormattingTags.get_html_tags()
start_tag = '{%s}' % tag_name 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): def _add_text_with_tags_to_lines(self, verse_element, text, tags_element):
""" """
Convert text with formatting tags from OpenLP format to OpenLyrics Convert text with formatting tags from OpenLP format to OpenLyrics format and append it to element ``<lines>``.
format and append it to element ``<lines>``.
""" """
start_tags = OpenLyrics.START_TAGS_REGEX.findall(text) start_tags = OpenLyrics.START_TAGS_REGEX.findall(text)
end_tags = OpenLyrics.END_TAGS_REGEX.findall(text) end_tags = OpenLyrics.END_TAGS_REGEX.findall(text)
@ -478,8 +456,7 @@ class OpenLyrics(object):
for tag in start_tags: for tag in start_tags:
# Tags already converted to xml structure. # Tags already converted to xml structure.
xml_tags = tags_element.xpath(u'tag/attribute::name') xml_tags = tags_element.xpath(u'tag/attribute::name')
# Some formatting tag has only starting part e.g. <br>. # Some formatting tag has only starting part e.g. <br>. Handle this case.
# Handle this case.
if tag in end_tags: if tag in end_tags:
text = text.replace(u'{%s}' % tag, u'<tag name="%s">' % tag) text = text.replace(u'{%s}' % tag, u'<tag name="%s">' % tag)
else: else:
@ -586,8 +563,8 @@ class OpenLyrics(object):
def _process_formatting_tags(self, song_xml, temporary): def _process_formatting_tags(self, song_xml, temporary):
""" """
Process the formatting tags from the song and either add missing tags Process the formatting tags from the song and either add missing tags temporary or permanently to the
temporary or permanently to the formatting tag list. formatting tag list.
""" """
if not hasattr(song_xml, u'format'): if not hasattr(song_xml, u'format'):
return return
@ -608,8 +585,8 @@ class OpenLyrics(object):
u'end html': tag.close.text if hasattr(tag, 'close') else u'', u'end html': tag.close.text if hasattr(tag, 'close') else u'',
u'protected': False, u'protected': False,
} }
# Add 'temporary' key in case the formatting tag should not be # Add 'temporary' key in case the formatting tag should not be saved otherwise it is supposed that
# saved otherwise it is supposed that formatting tag is permanent. # formatting tag is permanent.
if temporary: if temporary:
openlp_tag[u'temporary'] = temporary openlp_tag[u'temporary'] = temporary
found_tags.append(openlp_tag) found_tags.append(openlp_tag)
@ -620,15 +597,14 @@ class OpenLyrics(object):
def _process_lines_mixed_content(self, element, newlines=True): def _process_lines_mixed_content(self, element, newlines=True):
""" """
Converts the xml text with mixed content to OpenLP representation. Converts the xml text with mixed content to OpenLP representation. Chords are skipped and formatting tags are
Chords are skipped and formatting tags are converted. converted.
``element`` ``element``
The property object (lxml.etree.Element). The property object (lxml.etree.Element).
``newlines`` ``newlines``
The switch to enable/disable processing of line breaks <br/>. The switch to enable/disable processing of line breaks <br/>. The <br/> is used since OpenLyrics 0.8.
The <br/> is used since OpenLyrics 0.8.
""" """
text = u'' text = u''
use_endtag = True use_endtag = True
@ -684,12 +660,10 @@ class OpenLyrics(object):
lines = etree.tostring(lines) lines = etree.tostring(lines)
element = etree.XML(lines) element = etree.XML(lines)
# OpenLyrics 0.8 uses <br/> for new lines. # OpenLyrics 0.8 uses <br/> for new lines. Append text from "lines" element to verse text.
# Append text from "lines" element to verse text.
if version > '0.7': if version > '0.7':
text = self._process_lines_mixed_content(element) text = self._process_lines_mixed_content(element)
# OpenLyrics version <= 0.7 contais <line> elements to represent lines. # OpenLyrics version <= 0.7 contais <line> elements to represent lines. First child element is tested.
# First child element is tested.
else: else:
# Loop over the "line" elements removing comments and chords. # Loop over the "line" elements removing comments and chords.
for line in element: for line in element:
@ -742,16 +716,15 @@ class OpenLyrics(object):
text += u'\n[---]' text += u'\n[---]'
verse_def = verse.get(u'name', u' ').lower() verse_def = verse.get(u'name', u' ').lower()
verse_tag, verse_number, verse_part = OpenLyrics.VERSE_TAG_SPLITTER.search(verse_def).groups() verse_tag, verse_number, verse_part = OpenLyrics.VERSE_TAG_SPLITTER.search(verse_def).groups()
if verse_tag not in VerseType.Tags: if verse_tag not in VerseType.tags:
verse_tag = VerseType.Tags[VerseType.Other] verse_tag = VerseType.tags[VerseType.Other]
# OpenLyrics allows e. g. "c", but we need "c1". However, this does # OpenLyrics allows e. g. "c", but we need "c1". However, this does not correct the verse order.
# not correct the verse order.
if not verse_number: if not verse_number:
verse_number = u'1' verse_number = u'1'
lang = verse.get(u'lang') lang = verse.get(u'lang')
translit = verse.get(u'translit') translit = verse.get(u'translit')
# In OpenLP 1.9.6 we used v1a, v1b ... to represent visual slide # In OpenLP 1.9.6 we used v1a, v1b ... to represent visual slide breaks. In OpenLyrics 0.7 an attribute has
# breaks. In OpenLyrics 0.7 an attribute has been added. # been added.
if song_xml.get(u'modifiedIn') in (u'1.9.6', u'OpenLP 1.9.6') and \ 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: 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 verses[(verse_tag, verse_number, lang, translit, None)] += u'\n[---]\n' + text

View File

@ -176,7 +176,7 @@ class SongsPlugin(Plugin):
return translate('SongsPlugin', '<strong>Songs Plugin</strong>' return translate('SongsPlugin', '<strong>Songs Plugin</strong>'
'<br />The songs plugin provides the ability to display and manage songs.') '<br />The songs plugin provides the ability to display and manage songs.')
def usesTheme(self, theme): def uses_theme(self, theme):
""" """
Called to find out if the song plugin is currently using a theme. Called to find out if the song plugin is currently using a theme.
@ -186,7 +186,7 @@ class SongsPlugin(Plugin):
return True return True
return False return False
def renameTheme(self, oldTheme, newTheme): def rename_theme(self, oldTheme, newTheme):
""" """
Renames a theme the song plugin is using making the plugin use the new Renames a theme the song plugin is using making the plugin use the new
name. name.
@ -209,7 +209,7 @@ class SongsPlugin(Plugin):
importer.register(self.mediaItem.importWizard) importer.register(self.mediaItem.importWizard)
return importer return importer
def setPluginTextStrings(self): def set_plugin_text_strings(self):
""" """
Called to define all translatable texts of the plugin Called to define all translatable texts of the plugin
""" """

View File

@ -99,7 +99,7 @@ class SongUsagePlugin(Plugin):
self.song_usage_status = create_action(tools_menu, u'songUsageStatus', self.song_usage_status = create_action(tools_menu, u'songUsageStatus',
text=translate('SongUsagePlugin', 'Toggle Tracking'), text=translate('SongUsagePlugin', 'Toggle Tracking'),
statustip=translate('SongUsagePlugin', 'Toggle the tracking of song usage.'), checked=False, statustip=translate('SongUsagePlugin', 'Toggle the tracking of song usage.'), checked=False,
shortcuts=[QtCore.Qt.Key_F4], triggers=self.toggle_song_usage_state) can_shortcuts=True, triggers=self.toggle_song_usage_state)
# Add Menus together # Add Menus together
self.toolsMenu.addAction(self.song_usage_menu.menuAction()) self.toolsMenu.addAction(self.song_usage_menu.menuAction())
self.song_usage_menu.addAction(self.song_usage_status) self.song_usage_menu.addAction(self.song_usage_status)
@ -219,7 +219,7 @@ class SongUsagePlugin(Plugin):
'</strong><br />This plugin tracks the usage of songs in services.') '</strong><br />This plugin tracks the usage of songs in services.')
return about_text return about_text
def setPluginTextStrings(self): def set_plugin_text_strings(self):
""" """
Called to define all translatable texts of the plugin Called to define all translatable texts of the plugin
""" """

View File

@ -92,6 +92,7 @@ OPTIONAL_MODULES = [
('MySQLdb', ' (MySQL support)'), ('MySQLdb', ' (MySQL support)'),
('psycopg2', ' (PostgreSQL support)'), ('psycopg2', ' (PostgreSQL support)'),
('nose', ' (testing framework)'), ('nose', ' (testing framework)'),
('mock', ' (testing module)'),
] ]
w = sys.stdout.write w = sys.stdout.write

View File

@ -45,8 +45,8 @@ class TestFormattingTags(TestCase):
FormattingTags.load_tags() FormattingTags.load_tags()
new_tags_list = FormattingTags.get_html_tags() new_tags_list = FormattingTags.get_html_tags()
# THEN: Lists should be identically. # THEN: Lists should be identical.
assert old_tags_list == new_tags_list, u'The formatting tag lists should be identically.' assert old_tags_list == new_tags_list, u'The formatting tag lists should be identical.'
def get_html_tags_with_user_tags_test(self): def get_html_tags_with_user_tags_test(self):
""" """
@ -69,16 +69,16 @@ class TestFormattingTags(TestCase):
FormattingTags.add_html_tags([TAG]) FormattingTags.add_html_tags([TAG])
new_tags_list = copy.deepcopy(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.' assert old_tags_list != new_tags_list, u'The lists should be different.'
# THEN: Added tag and last tag should be the same. # THEN: Added tag and last tag should be the same.
new_tag = new_tags_list.pop() 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. # WHEN: Remove the new tag.
FormattingTags.remove_html_tag(len(new_tags_list)) FormattingTags.remove_html_tag(len(new_tags_list))
# THEN: The lists should now be identically. # THEN: The lists should now be identical.
assert old_tags_list == FormattingTags.get_html_tags(), u'The lists should be identically.' assert old_tags_list == FormattingTags.get_html_tags(), u'The lists should be identical.'

View File

@ -7,7 +7,7 @@ from datetime import datetime, timedelta
from mock import MagicMock, patch from mock import MagicMock, patch
from openlp.core.lib import str_to_bool, translate, check_directory_exists, get_text_file_string, build_icon, \ from openlp.core.lib import str_to_bool, translate, check_directory_exists, get_text_file_string, build_icon, \
image_to_byte, check_item_selected, validate_thumb, create_separated_list image_to_byte, check_item_selected, validate_thumb, create_separated_list, expand_tags
class TestLib(TestCase): class TestLib(TestCase):
@ -299,6 +299,45 @@ class TestLib(TestCase):
MockedQtGui.QMessageBox.information.assert_called_with(u'parent', u'mocked translate', 'message') MockedQtGui.QMessageBox.information.assert_called_with(u'parent', u'mocked translate', 'message')
assert not result, u'The result should be False' assert not result, u'The result should be False'
def expand_tags_test(self):
"""
Test the expand_tags() method.
"""
with patch(u'openlp.core.lib.FormattingTags.get_html_tags') as mocked_get_tags:
# GIVEN: Mocked get_html_tags() method.
mocked_get_tags.return_value = [
{
u'desc': u'Black',
u'start tag': u'{b}',
u'start html': u'<span style="-webkit-text-fill-color:black">',
u'end tag': u'{/b}', u'end html': u'</span>', u'protected': True,
u'temporary': False
},
{
u'desc': u'Yellow',
u'start tag': u'{y}',
u'start html': u'<span style="-webkit-text-fill-color:yellow">',
u'end tag': u'{/y}', u'end html': u'</span>', u'protected': True,
u'temporary': False
},
{
u'desc': u'Green',
u'start tag': u'{g}',
u'start html': u'<span style="-webkit-text-fill-color:green">',
u'end tag': u'{/g}', u'end html': u'</span>', u'protected': True,
u'temporary': False
}
]
string_to_pass = u'{b}black{/b}{y}yellow{/y}'
wanted_string = u'<span style="-webkit-text-fill-color:black">black</span>' + \
'<span style="-webkit-text-fill-color:yellow">yellow</span>'
# WHEN: Replace the tags.
result_string = expand_tags(string_to_pass)
# THEN: The strings should be identical.
assert result_string == wanted_string, u'The strings should be identical.'
def validate_thumb_file_does_not_exist_test(self): def validate_thumb_file_does_not_exist_test(self):
""" """
Test the validate_thumb() function when the thumbnail does not exist Test the validate_thumb() function when the thumbnail does not exist

View File

@ -18,8 +18,15 @@ class TestPluginManager(TestCase):
""" """
Some pre-test setup required. Some pre-test setup required.
""" """
self.mocked_main_window = MagicMock()
self.mocked_main_window.file_import_menu.return_value = None
self.mocked_main_window.file_export_menu.return_value = None
self.mocked_main_window.file_export_menu.return_value = None
self.mocked_settings_form = MagicMock()
Registry.create() Registry.create()
Registry().register(u'service_list', MagicMock()) Registry().register(u'service_list', MagicMock())
Registry().register(u'main_window', self.mocked_main_window)
Registry().register(u'settings_form', self.mocked_settings_form)
def hook_media_manager_with_disabled_plugin_test(self): def hook_media_manager_with_disabled_plugin_test(self):
""" """
@ -78,17 +85,41 @@ class TestPluginManager(TestCase):
# GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Disabled # GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Disabled
mocked_plugin = MagicMock() mocked_plugin = MagicMock()
mocked_plugin.status = PluginStatus.Disabled mocked_plugin.status = PluginStatus.Disabled
mocked_settings_form = MagicMock()
plugin_manager = PluginManager() plugin_manager = PluginManager()
plugin_manager.plugins = [mocked_plugin] plugin_manager.plugins = [mocked_plugin]
mocked_settings_form = MagicMock()
# Replace the autoloaded plugin with the version for testing in real code this would error
mocked_settings_form.plugin_manager = plugin_manager
# WHEN: We run hook_settings_tabs() # WHEN: We run hook_settings_tabs()
plugin_manager.hook_settings_tabs(mocked_settings_form) plugin_manager.hook_settings_tabs()
# THEN: The createSettingsTab() method should not have been called, but the plugins lists should be the same # THEN: The createSettingsTab() method should not have been called, but the plugins lists should be the same
assert mocked_plugin.createSettingsTab.call_count == 0, \ assert mocked_plugin.createSettingsTab.call_count == 0, \
u'The createMediaManagerItem() method should not have been called.' u'The createMediaManagerItem() method should not have been called.'
self.assertEqual(mocked_settings_form.plugins, plugin_manager.plugins, self.assertEqual(mocked_settings_form.plugin_manager.plugins, plugin_manager.plugins,
u'The plugins on the settings form should be the same as the plugins in the plugin manager')
def hook_settings_tabs_with_active_plugin_and_mocked_form_test(self):
"""
Test running the hook_settings_tabs() method with an active plugin and a mocked settings form
"""
# GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Active
mocked_plugin = MagicMock()
mocked_plugin.status = PluginStatus.Active
plugin_manager = PluginManager()
plugin_manager.plugins = [mocked_plugin]
mocked_settings_form = MagicMock()
# Replace the autoloaded plugin with the version for testing in real code this would error
mocked_settings_form.plugin_manager = plugin_manager
# WHEN: We run hook_settings_tabs()
plugin_manager.hook_settings_tabs()
# THEN: The createMediaManagerItem() method should have been called with the mocked settings form
assert mocked_plugin.createSettingsTab.call_count == 1, \
u'The createMediaManagerItem() method should have been called once.'
self.assertEqual(mocked_settings_form.plugin_manager.plugins, plugin_manager.plugins,
u'The plugins on the settings form should be the same as the plugins in the plugin manager') u'The plugins on the settings form should be the same as the plugins in the plugin manager')
def hook_settings_tabs_with_active_plugin_and_no_form_test(self): def hook_settings_tabs_with_active_plugin_and_no_form_test(self):
@ -105,26 +136,7 @@ class TestPluginManager(TestCase):
plugin_manager.hook_settings_tabs() plugin_manager.hook_settings_tabs()
# THEN: The createSettingsTab() method should have been called # THEN: The createSettingsTab() method should have been called
mocked_plugin.createSettingsTab.assert_called_with(None) mocked_plugin.createSettingsTab.assert_called_with(self.mocked_settings_form)
def hook_settings_tabs_with_active_plugin_and_mocked_form_test(self):
"""
Test running the hook_settings_tabs() method with an active plugin and a mocked settings form
"""
# GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Active
mocked_plugin = MagicMock()
mocked_plugin.status = PluginStatus.Active
mocked_settings_form = MagicMock()
plugin_manager = PluginManager()
plugin_manager.plugins = [mocked_plugin]
# WHEN: We run hook_settings_tabs()
plugin_manager.hook_settings_tabs(mocked_settings_form)
# THEN: The createMediaManagerItem() method should have been called with the mocked settings form
mocked_plugin.createSettingsTab.assert_called_with(mocked_settings_form)
self.assertEqual(mocked_settings_form.plugins, plugin_manager.plugins,
u'The plugins on the settings form should be the same as the plugins in the plugin manager')
def hook_import_menu_with_disabled_plugin_test(self): def hook_import_menu_with_disabled_plugin_test(self):
""" """
@ -133,12 +145,11 @@ class TestPluginManager(TestCase):
# GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Disabled # GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Disabled
mocked_plugin = MagicMock() mocked_plugin = MagicMock()
mocked_plugin.status = PluginStatus.Disabled mocked_plugin.status = PluginStatus.Disabled
mocked_import_menu = MagicMock()
plugin_manager = PluginManager() plugin_manager = PluginManager()
plugin_manager.plugins = [mocked_plugin] plugin_manager.plugins = [mocked_plugin]
# WHEN: We run hook_import_menu() # WHEN: We run hook_import_menu()
plugin_manager.hook_import_menu(mocked_import_menu) plugin_manager.hook_import_menu()
# THEN: The createMediaManagerItem() method should have been called # THEN: The createMediaManagerItem() method should have been called
assert mocked_plugin.addImportMenuItem.call_count == 0, \ assert mocked_plugin.addImportMenuItem.call_count == 0, \
@ -151,15 +162,14 @@ class TestPluginManager(TestCase):
# GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Active # GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Active
mocked_plugin = MagicMock() mocked_plugin = MagicMock()
mocked_plugin.status = PluginStatus.Active mocked_plugin.status = PluginStatus.Active
mocked_import_menu = MagicMock()
plugin_manager = PluginManager() plugin_manager = PluginManager()
plugin_manager.plugins = [mocked_plugin] plugin_manager.plugins = [mocked_plugin]
# WHEN: We run hook_import_menu() # WHEN: We run hook_import_menu()
plugin_manager.hook_import_menu(mocked_import_menu) plugin_manager.hook_import_menu()
# THEN: The addImportMenuItem() method should have been called # THEN: The addImportMenuItem() method should have been called
mocked_plugin.addImportMenuItem.assert_called_with(mocked_import_menu) mocked_plugin.addImportMenuItem.assert_called_with(self.mocked_main_window.file_import_menu)
def hook_export_menu_with_disabled_plugin_test(self): def hook_export_menu_with_disabled_plugin_test(self):
""" """
@ -168,12 +178,11 @@ class TestPluginManager(TestCase):
# GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Disabled # GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Disabled
mocked_plugin = MagicMock() mocked_plugin = MagicMock()
mocked_plugin.status = PluginStatus.Disabled mocked_plugin.status = PluginStatus.Disabled
mocked_export_menu = MagicMock()
plugin_manager = PluginManager() plugin_manager = PluginManager()
plugin_manager.plugins = [mocked_plugin] plugin_manager.plugins = [mocked_plugin]
# WHEN: We run hook_export_menu() # WHEN: We run hook_export_menu()
plugin_manager.hook_export_menu(mocked_export_menu) plugin_manager.hook_export_menu()
# THEN: The addExportMenuItem() method should have been called # THEN: The addExportMenuItem() method should have been called
assert mocked_plugin.addExportMenuItem.call_count == 0, \ assert mocked_plugin.addExportMenuItem.call_count == 0, \
@ -186,15 +195,14 @@ class TestPluginManager(TestCase):
# GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Active # GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Active
mocked_plugin = MagicMock() mocked_plugin = MagicMock()
mocked_plugin.status = PluginStatus.Active mocked_plugin.status = PluginStatus.Active
mocked_export_menu = MagicMock()
plugin_manager = PluginManager() plugin_manager = PluginManager()
plugin_manager.plugins = [mocked_plugin] plugin_manager.plugins = [mocked_plugin]
# WHEN: We run hook_export_menu() # WHEN: We run hook_export_menu()
plugin_manager.hook_export_menu(mocked_export_menu) plugin_manager.hook_export_menu()
# THEN: The addExportMenuItem() method should have been called # THEN: The addExportMenuItem() method should have been called
mocked_plugin.addExportMenuItem.assert_called_with(mocked_export_menu) mocked_plugin.addExportMenuItem.assert_called_with(self.mocked_main_window.file_export_menu)
def hook_tools_menu_with_disabled_plugin_test(self): def hook_tools_menu_with_disabled_plugin_test(self):
""" """
@ -203,12 +211,11 @@ class TestPluginManager(TestCase):
# GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Disabled # GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Disabled
mocked_plugin = MagicMock() mocked_plugin = MagicMock()
mocked_plugin.status = PluginStatus.Disabled mocked_plugin.status = PluginStatus.Disabled
mocked_tools_menu = MagicMock()
plugin_manager = PluginManager() plugin_manager = PluginManager()
plugin_manager.plugins = [mocked_plugin] plugin_manager.plugins = [mocked_plugin]
# WHEN: We run hook_tools_menu() # WHEN: We run hook_tools_menu()
plugin_manager.hook_tools_menu(mocked_tools_menu) plugin_manager.hook_tools_menu()
# THEN: The addToolsMenuItem() method should have been called # THEN: The addToolsMenuItem() method should have been called
assert mocked_plugin.addToolsMenuItem.call_count == 0, \ assert mocked_plugin.addToolsMenuItem.call_count == 0, \
@ -221,15 +228,14 @@ class TestPluginManager(TestCase):
# GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Active # GIVEN: A PluginManager instance and a list with a mocked up plugin whose status is set to Active
mocked_plugin = MagicMock() mocked_plugin = MagicMock()
mocked_plugin.status = PluginStatus.Active mocked_plugin.status = PluginStatus.Active
mocked_tools_menu = MagicMock()
plugin_manager = PluginManager() plugin_manager = PluginManager()
plugin_manager.plugins = [mocked_plugin] plugin_manager.plugins = [mocked_plugin]
# WHEN: We run hook_tools_menu() # WHEN: We run hook_tools_menu()
plugin_manager.hook_tools_menu(mocked_tools_menu) plugin_manager.hook_tools_menu()
# THEN: The addToolsMenuItem() method should have been called # THEN: The addToolsMenuItem() method should have been called
mocked_plugin.addToolsMenuItem.assert_called_with(mocked_tools_menu) mocked_plugin.addToolsMenuItem.assert_called_with(self.mocked_main_window.tools_menu)
def initialise_plugins_with_disabled_plugin_test(self): def initialise_plugins_with_disabled_plugin_test(self):
""" """

View File

@ -54,5 +54,5 @@ class TestScreenList(TestCase):
new_screens = self.screens.screen_list new_screens = self.screens.screen_list
assert len(old_screens) + 1 == len(new_screens), u'The new_screens list should be bigger.' assert len(old_screens) + 1 == len(new_screens), u'The new_screens list should be bigger.'
# THEN: The screens should be identically. # THEN: The screens should be identical.
assert SCREEN == new_screens.pop(), u'The new screen should be identically to the screen defined above.' assert SCREEN == new_screens.pop(), u'The new screen should be identical to the screen defined above.'

View File

@ -216,12 +216,15 @@ class TestServiceItem(TestCase):
assert service_item.get_frame_path(0) == test_file, u'The frame path should match the full path to the image' assert service_item.get_frame_path(0) == test_file, u'The frame path should match the full path to the image'
assert service_item.get_frame_title(0) == image_name, u'The frame title should match the image name' assert service_item.get_frame_title(0) == image_name, u'The frame title should match the image name'
assert service_item.get_display_title() == image_name, u'The display title should match the first image name' assert service_item.get_display_title() == image_name, u'The display title should match the first image name'
assert service_item.is_image() is True, u'This service item is an Image' assert service_item.is_image() is True, u'This service item should be of an "image" type'
assert service_item.is_capable(ItemCapabilities.CanMaintain) is True, u'This service item can be Maintained' assert service_item.is_capable(ItemCapabilities.CanMaintain) is True, \
assert service_item.is_capable(ItemCapabilities.CanPreview) is True, u'This service item can be Previewed' u'This service item should be able to be Maintained'
assert service_item.is_capable(ItemCapabilities.CanLoop) is True, u'This service item can be made to Loop' assert service_item.is_capable(ItemCapabilities.CanPreview) is True, \
u'This service item should be able to be be Previewed'
assert service_item.is_capable(ItemCapabilities.CanLoop) is True, \
u'This service item should be able to be run in a can be made to Loop'
assert service_item.is_capable(ItemCapabilities.CanAppend) is True, \ assert service_item.is_capable(ItemCapabilities.CanAppend) is True, \
u'This service item can have new items added' u'This service item should be able to have new items added to it'
def serviceitem_load_image_from_local_service_test(self): def serviceitem_load_image_from_local_service_test(self):
""" """
@ -256,11 +259,14 @@ class TestServiceItem(TestCase):
assert service_item.get_display_title().lower() == service_item.name, \ assert service_item.get_display_title().lower() == service_item.name, \
u'The plugin name should match the display title, as there are > 1 Images' u'The plugin name should match the display title, as there are > 1 Images'
assert service_item.is_image() is True, u'This service item should be of an "image" type' assert service_item.is_image() is True, u'This service item should be of an "image" type'
assert service_item.is_capable(ItemCapabilities.CanMaintain) is True, u'This service item can be Maintained' assert service_item.is_capable(ItemCapabilities.CanMaintain) is True, \
assert service_item.is_capable(ItemCapabilities.CanPreview) is True, u'This service item can be Previewed' u'This service item should be able to be Maintained'
assert service_item.is_capable(ItemCapabilities.CanLoop) is True, u'This service item can be made to Loop' assert service_item.is_capable(ItemCapabilities.CanPreview) is True, \
u'This service item should be able to be be Previewed'
assert service_item.is_capable(ItemCapabilities.CanLoop) is True, \
u'This service item should be able to be run in a can be made to Loop'
assert service_item.is_capable(ItemCapabilities.CanAppend) is True, \ assert service_item.is_capable(ItemCapabilities.CanAppend) is True, \
u'This service item can have new items added' u'This service item should be able to have new items added to it'
def convert_file_service_item(self, name): def convert_file_service_item(self, name):
service_file = os.path.join(TEST_PATH, name) service_file = os.path.join(TEST_PATH, name)

View File

@ -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.'

View File

@ -1,12 +1,17 @@
""" """
Functional tests to test the AppLocation class and related methods. Functional tests to test the AppLocation class and related methods.
""" """
import copy
from unittest import TestCase from unittest import TestCase
from mock import patch from mock import patch
from openlp.core.utils import AppLocation 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): class TestAppLocation(TestCase):
""" """
A test suite to test out various methods around the AppLocation class. 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 Test the AppLocation.get_data_path() method
""" """
with patch(u'openlp.core.utils.Settings') as mocked_class, \ 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.get_directory') as mocked_get_directory, \
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, \
patch(u'openlp.core.utils.os') as mocked_os: patch(u'openlp.core.utils.applocation.os') as mocked_os:
# GIVEN: A mocked out Settings class and a mocked out AppLocation.get_directory() # GIVEN: A mocked out Settings class and a mocked out AppLocation.get_directory()
mocked_settings = mocked_class.return_value mocked_settings = mocked_class.return_value
mocked_settings.contains.return_value = False 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 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,\ with patch(u'openlp.core.utils.applocation.Settings') as mocked_class,\
patch(u'openlp.core.utils.os') as mocked_os: patch(u'openlp.core.utils.applocation.os') as mocked_os:
# GIVEN: A mocked out Settings class which returns a custom data location # GIVEN: A mocked out Settings class which returns a custom data location
mocked_settings = mocked_class.return_value mocked_settings = mocked_class.return_value
mocked_settings.contains.return_value = True mocked_settings.contains.return_value = True
@ -51,12 +56,47 @@ class TestAppLocation(TestCase):
mocked_settings.value.assert_called_with(u'advanced/data path') mocked_settings.value.assert_called_with(u'advanced/data path')
assert data_path == u'custom/dir', u'Result should be "custom/dir"' 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 section parameter was used correctly.
mocked_listdir.assert_called_with(u'test/dir/section')
# 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): def get_section_data_path_test(self):
""" """
Test the AppLocation.get_section_data_path() method Test the AppLocation.get_section_data_path() method
""" """
with patch(u'openlp.core.utils.AppLocation.get_data_path') as mocked_get_data_path, \ 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() # GIVEN: A mocked out AppLocation.get_data_path()
mocked_get_data_path.return_value = u'test/dir' mocked_get_data_path.return_value = u'test/dir'
mocked_check_directory_exists.return_value = True mocked_check_directory_exists.return_value = True
@ -70,7 +110,7 @@ class TestAppLocation(TestCase):
""" """
Test the AppLocation.get_directory() method for AppLocation.AppDir 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' mocked_get_frozen_path.return_value = u'app/dir'
# WHEN: We call AppLocation.get_directory # WHEN: We call AppLocation.get_directory
directory = AppLocation.get_directory(AppLocation.AppDir) directory = AppLocation.get_directory(AppLocation.AppDir)
@ -81,10 +121,10 @@ class TestAppLocation(TestCase):
""" """
Test the AppLocation.get_directory() method for AppLocation.PluginsDir Test the AppLocation.get_directory() method for AppLocation.PluginsDir
""" """
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, \
patch(u'openlp.core.utils.os.path.abspath') as mocked_abspath, \ patch(u'openlp.core.utils.applocation.os.path.abspath') as mocked_abspath, \
patch(u'openlp.core.utils.os.path.split') as mocked_split, \ patch(u'openlp.core.utils.applocation.os.path.split') as mocked_split, \
patch(u'openlp.core.utils.sys') as mocked_sys: patch(u'openlp.core.utils.applocation.sys') as mocked_sys:
mocked_abspath.return_value = u'plugins/dir' mocked_abspath.return_value = u'plugins/dir'
mocked_split.return_value = [u'openlp'] mocked_split.return_value = [u'openlp']
mocked_get_frozen_path.return_value = u'plugins/dir' mocked_get_frozen_path.return_value = u'plugins/dir'

View File

@ -21,15 +21,15 @@ class TestServiceManager(TestCase):
self.app = QtGui.QApplication.instance() self.app = QtGui.QApplication.instance()
ScreenList.create(self.app.desktop()) ScreenList.create(self.app.desktop())
Registry().register(u'application', MagicMock()) Registry().register(u'application', MagicMock())
#with patch(u'openlp.core.lib.PluginManager'): with patch(u'openlp.core.lib.PluginManager'):
# self.main_window = MainWindow() self.main_window = MainWindow()
#self.service_manager = Registry().get(u'service_manager') self.service_manager = Registry().get(u'service_manager')
def tearDown(self): def tearDown(self):
""" """
Delete all the C++ objects at the end so that we don't have a segfault Delete all the C++ objects at the end so that we don't have a segfault
""" """
#del self.main_window del self.main_window
del self.app del self.app
def basic_service_manager_test(self): def basic_service_manager_test(self):
@ -40,6 +40,5 @@ class TestServiceManager(TestCase):
# WHEN I have an empty display # WHEN I have an empty display
# THEN the count of items should be zero # THEN the count of items should be zero
#self.assertEqual(self.service_manager.service_manager_list.topLevelItemCount(), 0, self.assertEqual(self.service_manager.service_manager_list.topLevelItemCount(), 0,
# u'The service manager list should be empty ') u'The service manager list should be empty ')
pass