From 4213dad51c25746fd5b04d4bd5f171d484a970c0 Mon Sep 17 00:00:00 2001 From: Stevan Pettit Date: Tue, 7 Jun 2011 21:37:07 -0400 Subject: [PATCH 001/184] Confirm delete of Custom item --- openlp/plugins/custom/lib/customtab.py | 33 +++++++++++++++++++++++--- openlp/plugins/custom/lib/mediaitem.py | 14 +++++++++++ 2 files changed, 44 insertions(+), 3 deletions(-) diff --git a/openlp/plugins/custom/lib/customtab.py b/openlp/plugins/custom/lib/customtab.py index fb83fab81..7aabe7dda 100644 --- a/openlp/plugins/custom/lib/customtab.py +++ b/openlp/plugins/custom/lib/customtab.py @@ -47,17 +47,32 @@ class CustomTab(SettingsTab): self.displayFooterCheckBox.setObjectName(u'displayFooterCheckBox') self.customModeLayout.addRow(self.displayFooterCheckBox) self.leftLayout.addWidget(self.customModeGroupBox) - self.leftLayout.addStretch() - self.rightLayout.addStretch() QtCore.QObject.connect(self.displayFooterCheckBox, QtCore.SIGNAL(u'stateChanged(int)'), self.onDisplayFooterCheckBoxChanged) - + self.customUIGroupBox = QtGui.QGroupBox(self.leftColumn) + self.customUIGroupBox.setObjectName(u'customUIGroupBox') + self.customUILayout = QtGui.QFormLayout(self.customUIGroupBox) + self.customUILayout.setObjectName(u'customUILayout') + self.confirmDeleteCheckBox = QtGui.QCheckBox(self.customUIGroupBox) + self.confirmDeleteCheckBox.setObjectName(u'confirmDeleteCheckBox') + self.customUILayout.addRow(self.confirmDeleteCheckBox) + self.leftLayout.addWidget(self.customUIGroupBox) + QtCore.QObject.connect(self.confirmDeleteCheckBox, + QtCore.SIGNAL(u'stateChanged(int)'), + self.onConfirmDeleteCheckBoxChanged) + self.leftLayout.addStretch() + self.rightLayout.addStretch() + def retranslateUi(self): self.customModeGroupBox.setTitle(translate('CustomPlugin.CustomTab', 'Custom Display')) self.displayFooterCheckBox.setText( translate('CustomPlugin.CustomTab', 'Display footer')) + self.customUIGroupBox.setTitle(translate('CustomPlugin.CustomTab', + 'UI Settings')) + self.confirmDeleteCheckBox.setText( + translate('CustomPlugin.CustomTab', 'Confirm delete')) def onDisplayFooterCheckBoxChanged(self, check_state): self.displayFooter = False @@ -65,12 +80,24 @@ class CustomTab(SettingsTab): if check_state == QtCore.Qt.Checked: self.displayFooter = True + def onConfirmDeleteCheckBoxChanged(self, check_state): + self.confirmDelete = False + # we have a set value convert to True/False + if check_state == QtCore.Qt.Checked: + self.confirmDelete = True + def load(self): self.displayFooter = QtCore.QSettings().value( self.settingsSection + u'/display footer', QtCore.QVariant(True)).toBool() self.displayFooterCheckBox.setChecked(self.displayFooter) + self.confirmDelete = QtCore.QSettings().value( + self.settingsSection + u'/confirm delete', + QtCore.QVariant(True)).toBool() + self.confirmDeleteCheckBox.setChecked(self.confirmDelete) def save(self): QtCore.QSettings().setValue(self.settingsSection + u'/display footer', QtCore.QVariant(self.displayFooter)) + QtCore.QSettings().setValue(self.settingsSection + u'/confirm delete', + QtCore.QVariant(self.confirmDelete)) diff --git a/openlp/plugins/custom/lib/mediaitem.py b/openlp/plugins/custom/lib/mediaitem.py index 94ee6d94e..fec660360 100644 --- a/openlp/plugins/custom/lib/mediaitem.py +++ b/openlp/plugins/custom/lib/mediaitem.py @@ -200,6 +200,20 @@ class CustomMediaItem(MediaManagerItem): Remove a custom item from the list and database """ if check_item_selected(self.listView, UiStrings().SelectDelete): + self.confirmDelete = QtCore.QSettings().value( + self.settingsSection + u'/confirm delete', + QtCore.QVariant(u'False')).toBool() + items = self.listView.selectedIndexes() + if self.confirmDelete: + if QtGui.QMessageBox.question(self, + translate('CustomPlugin.MediaItem', 'Delete Custom(s)?'), + translate('CustomPlugin.MediaItem', + 'Are you sure you want to delete the %n selected custom(s)?', '', + QtCore.QCoreApplication.CodecForTr, len(items)), + QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Ok | + QtGui.QMessageBox.Cancel), + QtGui.QMessageBox.Ok) == QtGui.QMessageBox.Cancel: + return row_list = [item.row() for item in self.listView.selectedIndexes()] row_list.sort(reverse=True) id_list = [(item.data(QtCore.Qt.UserRole)).toInt()[0] From 30b56d6fee78b2d205033f779249d4d6377a424b Mon Sep 17 00:00:00 2001 From: Stevan Pettit Date: Sat, 11 Jun 2011 08:48:11 -0400 Subject: [PATCH 002/184] Moved signals to end of SetupUI --- openlp/plugins/custom/lib/customtab.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/openlp/plugins/custom/lib/customtab.py b/openlp/plugins/custom/lib/customtab.py index 7aabe7dda..12acabd0b 100644 --- a/openlp/plugins/custom/lib/customtab.py +++ b/openlp/plugins/custom/lib/customtab.py @@ -47,9 +47,6 @@ class CustomTab(SettingsTab): self.displayFooterCheckBox.setObjectName(u'displayFooterCheckBox') self.customModeLayout.addRow(self.displayFooterCheckBox) self.leftLayout.addWidget(self.customModeGroupBox) - QtCore.QObject.connect(self.displayFooterCheckBox, - QtCore.SIGNAL(u'stateChanged(int)'), - self.onDisplayFooterCheckBoxChanged) self.customUIGroupBox = QtGui.QGroupBox(self.leftColumn) self.customUIGroupBox.setObjectName(u'customUIGroupBox') self.customUILayout = QtGui.QFormLayout(self.customUIGroupBox) @@ -58,12 +55,15 @@ class CustomTab(SettingsTab): self.confirmDeleteCheckBox.setObjectName(u'confirmDeleteCheckBox') self.customUILayout.addRow(self.confirmDeleteCheckBox) self.leftLayout.addWidget(self.customUIGroupBox) + self.leftLayout.addStretch() + self.rightLayout.addStretch() + QtCore.QObject.connect(self.displayFooterCheckBox, + QtCore.SIGNAL(u'stateChanged(int)'), + self.onDisplayFooterCheckBoxChanged) QtCore.QObject.connect(self.confirmDeleteCheckBox, QtCore.SIGNAL(u'stateChanged(int)'), self.onConfirmDeleteCheckBoxChanged) - self.leftLayout.addStretch() - self.rightLayout.addStretch() - + def retranslateUi(self): self.customModeGroupBox.setTitle(translate('CustomPlugin.CustomTab', 'Custom Display')) From 1550239f5e37d75cbfbe0226a9292bd067af72dd Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Sun, 12 Jun 2011 15:19:32 +0100 Subject: [PATCH 003/184] Add Lock Toolbar feature - Beta 3 --- openlp/core/lib/ui.py | 5 ++-- openlp/core/ui/mainwindow.py | 54 ++++++++++++++++++++++++++++++++---- 2 files changed, 52 insertions(+), 7 deletions(-) diff --git a/openlp/core/lib/ui.py b/openlp/core/lib/ui.py index c784a7b2b..69a4e51d1 100644 --- a/openlp/core/lib/ui.py +++ b/openlp/core/lib/ui.py @@ -323,8 +323,9 @@ def shortcut_action(parent, name, shortcuts, function, icon=None, checked=None, if checked is not None: action.setCheckable(True) action.setChecked(checked) - action.setShortcuts(shortcuts) - action.setShortcutContext(context) + if shortcuts: + action.setShortcuts(shortcuts) + action.setShortcutContext(context) action_list = ActionList.get_instance() action_list.add_action(action, category) QtCore.QObject.connect(action, QtCore.SIGNAL(u'triggered(bool)'), function) diff --git a/openlp/core/ui/mainwindow.py b/openlp/core/ui/mainwindow.py index 0dd4872fe..b7d63ae58 100644 --- a/openlp/core/ui/mainwindow.py +++ b/openlp/core/ui/mainwindow.py @@ -92,6 +92,8 @@ class Ui_MainWindow(object): self.previewController.panel.setVisible(previewVisible) liveVisible = QtCore.QSettings().value(u'user interface/live panel', QtCore.QVariant(True)).toBool() + panelLocked = QtCore.QSettings().value(u'user interface/lock panel', + QtCore.QVariant(False)).toBool() self.liveController.panel.setVisible(liveVisible) # Create menu self.menuBar = QtGui.QMenuBar(mainWindow) @@ -212,7 +214,11 @@ class Ui_MainWindow(object): self.viewLivePanel = shortcut_action(mainWindow, u'viewLivePanel', [QtGui.QKeySequence(u'F12')], self.setLivePanelVisibility, checked=liveVisible, category=UiStrings().View) - action_list.add_category(UiStrings().ViewMode, CategoryOrder.standardMenu) + self.lockPanel = shortcut_action(mainWindow, u'lockPanel', + None, self.setLockPanel, + checked=panelLocked, category=None) + action_list.add_category(UiStrings().ViewMode, + CategoryOrder.standardMenu) self.modeDefaultItem = checkable_action( mainWindow, u'modeDefaultItem', category=UiStrings().ViewMode) self.modeSetupItem = checkable_action( @@ -232,7 +238,8 @@ class Ui_MainWindow(object): category=UiStrings().Tools) self.updateThemeImages = base_action(mainWindow, u'updateThemeImages', category=UiStrings().Tools) - action_list.add_category(UiStrings().Settings, CategoryOrder.standardMenu) + action_list.add_category(UiStrings().Settings, + CategoryOrder.standardMenu) self.settingsPluginListItem = shortcut_action(mainWindow, u'settingsPluginListItem', [QtGui.QKeySequence(u'Alt+F7')], self.onPluginItemClicked, u':/system/settings_plugin_list.png', @@ -287,7 +294,7 @@ class Ui_MainWindow(object): add_actions(self.viewMenu, (self.viewModeMenu.menuAction(), None, self.viewMediaManagerItem, self.viewServiceManagerItem, self.viewThemeManagerItem, None, self.viewPreviewPanel, - self.viewLivePanel)) + self.viewLivePanel, None, self.lockPanel)) # i18n add Language Actions add_actions(self.settingsLanguageMenu, (self.autoLanguageItem, None)) add_actions(self.settingsLanguageMenu, self.languageGroup.actions()) @@ -316,6 +323,7 @@ class Ui_MainWindow(object): self.importLanguageItem.setVisible(False) self.exportLanguageItem.setVisible(False) self.helpDocumentationItem.setVisible(False) + self.setLockPanel(panelLocked) def retranslateUi(self, mainWindow): """ @@ -405,6 +413,10 @@ class Ui_MainWindow(object): translate('OpenLP.MainWindow', '&Live Panel')) self.viewLivePanel.setToolTip( translate('OpenLP.MainWindow', 'Toggle Live Panel')) + self.lockPanel.setText( + translate('OpenLP.MainWindow', 'L&ock Panels')) + self.lockPanel.setToolTip( + translate('OpenLP.MainWindow', 'Prevent Panels changing')) self.viewLivePanel.setStatusTip(translate('OpenLP.MainWindow', 'Toggle the visibility of the live panel.')) self.settingsPluginListItem.setText(translate('OpenLP.MainWindow', @@ -644,7 +656,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): QtCore.QVariant(False)).toBool(): self.serviceManagerContents.loadLastFile() view_mode = QtCore.QSettings().value(u'%s/view mode' % \ - self.generalSettingsSection, u'default') + self.generalSettingsSection, u'default').toString() if view_mode == u'default': self.modeDefaultItem.setChecked(True) elif view_mode == u'setup': @@ -927,7 +939,8 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): self.mediaManagerDock.setVisible(not self.mediaManagerDock.isVisible()) def toggleServiceManager(self): - self.serviceManagerDock.setVisible(not self.serviceManagerDock.isVisible()) + self.serviceManagerDock.setVisible( + not self.serviceManagerDock.isVisible()) def toggleThemeManager(self): self.themeManagerDock.setVisible(not self.themeManagerDock.isVisible()) @@ -947,6 +960,37 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): QtCore.QVariant(visible)) self.viewPreviewPanel.setChecked(visible) + def setLockPanel(self, lock): + """ + Sets the ability to stiop the toolbars being changed. + """ + if lock: + self.themeManagerDock.setFeatures( + QtGui.QDockWidget.NoDockWidgetFeatures) + self.serviceManagerDock.setFeatures( + QtGui.QDockWidget.NoDockWidgetFeatures) + self.mediaManagerDock.setFeatures( + QtGui.QDockWidget.NoDockWidgetFeatures) + self.viewMediaManagerItem.setEnabled(False) + self.viewServiceManagerItem.setEnabled(False) + self.viewThemeManagerItem.setEnabled(False) + self.viewPreviewPanel.setEnabled(False) + self.viewLivePanel.setEnabled(False) + else: + self.themeManagerDock.setFeatures( + QtGui.QDockWidget.AllDockWidgetFeatures) + self.serviceManagerDock.setFeatures( + QtGui.QDockWidget.AllDockWidgetFeatures) + self.mediaManagerDock.setFeatures( + QtGui.QDockWidget.AllDockWidgetFeatures) + self.viewMediaManagerItem.setEnabled(True) + self.viewServiceManagerItem.setEnabled(True) + self.viewThemeManagerItem.setEnabled(True) + self.viewPreviewPanel.setEnabled(True) + self.viewLivePanel.setEnabled(True) + QtCore.QSettings().setValue(u'user interface/lock panel', + QtCore.QVariant(lock)) + def setLivePanelVisibility(self, visible): """ Sets the visibility of the live panel including saving the setting and From 445c63ce8b848712e16efc72d444192e6971fab5 Mon Sep 17 00:00:00 2001 From: Andreas Preikschat Date: Sun, 12 Jun 2011 20:38:04 +0200 Subject: [PATCH 004/184] --- openlp/core/lib/renderer.py | 162 ++++++++++++++++++--------------- openlp/core/lib/serviceitem.py | 4 + 2 files changed, 95 insertions(+), 71 deletions(-) diff --git a/openlp/core/lib/renderer.py b/openlp/core/lib/renderer.py index f9af00f6e..decf30435 100644 --- a/openlp/core/lib/renderer.py +++ b/openlp/core/lib/renderer.py @@ -324,34 +324,28 @@ class Renderer(object): """ log.debug(u'_paginate_slide - Start') - line_end = u'' + line_end = u' ' if line_break: line_end = u'
' formatted = [] + raw_text = u'' html_text = u'' - styled_text = u'' - line_count = 0 - for line in lines: - if line_count != -1: - line_count += 1 - styled_line = expand_tags(line) + line_end - styled_text += styled_line - html = self.page_shell + styled_text + HTML_END - self.web.setHtml(html) - # Text too long so go to next page. - if self.web_frame.contentsSize().height() > self.page_height: - if force_page and line_count > 0: - Receiver.send_message(u'theme_line_count', line_count - 1) - line_count = -1 - while html_text.endswith(u'
'): - html_text = html_text[:-4] - formatted.append(html_text) - html_text = u'' - styled_text = styled_line - html_text += line + line_end - while html_text.endswith(u'
'): - html_text = html_text[:-4] - formatted.append(html_text) + html_words = map(expand_tags, lines) + html = self.page_shell + u''.join(html_words) + HTML_END + self.web.setHtml(html) + # Text too long so go to next page. + if self.web_frame.contentsSize().height() > self.page_height: + lines = [u'%s
' % line for line in lines] + html_text, raw_text, index = self._binary_chop( + formatted, html_text, raw_text, lines, line_end) + if force_page: + Receiver.send_message(u'theme_line_count', index + 1) + else: + formatted.append(line_end.join(html_words)) + while raw_text.endswith(u'
'): + raw_text = raw_text[:-4] + if raw_text: + formatted.append(raw_text) log.debug(u'_paginate_slide - End') return formatted @@ -408,53 +402,8 @@ class Renderer(object): # Figure out how many words of the line will fit on screen by # using the algorithm known as "binary chop". raw_words = self._words_split(line) - html_words = [expand_tags(word) for word in raw_words] - smallest_index = 0 - highest_index = len(html_words) - 1 - index = int(highest_index / 2) - while True: - html = self.page_shell + previous_html + \ - u''.join(html_words[:index + 1]).strip() + HTML_END - self.web.setHtml(html) - if self.web_frame.contentsSize().height() > \ - self.page_height: - # We know that it does not fit, so change/calculate the - # new index and highest_index accordingly. - highest_index = index - index = int(index - (index - smallest_index) / 2) - else: - smallest_index = index - index = int(index + (highest_index - index) / 2) - # We found the number of words which will fit. - if smallest_index == index or highest_index == index: - index = smallest_index - formatted.append(previous_raw.rstrip(u'
') + - u''.join(raw_words[:index + 1])) - previous_html = u'' - previous_raw = u'' - else: - continue - # Check if the rest of the line fits on the slide. If it - # does we do not have to do the much more intensive "word by - # word" checking. - html = self.page_shell + \ - u''.join(html_words[index + 1:]).strip() + HTML_END - self.web.setHtml(html) - if self.web_frame.contentsSize().height() <= \ - self.page_height: - previous_html = \ - u''.join(html_words[index + 1:]).strip() + line_end - previous_raw = \ - u''.join(raw_words[index + 1:]).strip() + line_end - break - else: - # The other words do not fit, thus reset the indexes, - # create a new list and continue with "word by word". - raw_words = raw_words[index + 1:] - html_words = html_words[index + 1:] - smallest_index = 0 - highest_index = len(html_words) - 1 - index = int(highest_index / 2) + previous_html, previous_raw, index = self._binary_chop( + formatted, previous_html, previous_raw, raw_words, line_end, u'
') else: previous_html += styled_line + line_end previous_raw += line + line_end @@ -464,6 +413,77 @@ class Renderer(object): log.debug(u'_paginate_slide_words - End') return formatted + def _binary_chop(self, formatted, previous_html, previous_raw, raw_text, + line_end): + """ + This implements the binary chop algorithm for faster rendering. However, + it is assumed that this method is **only** called, when the text to be + rendered does not fit as a whole. + + ``formatted`` + The list of slides. + + ``previous_html`` + The html text which is know to fit on a slide, but is not yet added + to the list of slides. + + ``previous_raw`` + The raw text (with display tags) which is know to fit on a slide, + but is not yet added to the list of slides. + + ``raw_text`` + The text which does not fit on a slide and needs to be processed + using the binary chop. The text can contain display tags. + + ``line_end`` + The + """ + html_words = map(expand_tags, raw_text) + smallest_index = 0 + highest_index = len(html_words) - 1 + index = int(highest_index / 2) + while True: + html = self.page_shell + previous_html + \ + separator.join(html_words[:index + 1]).strip() + HTML_END + self.web.setHtml(html) + if self.web_frame.contentsSize().height() > self.page_height: + # We know that it does not fit, so change/calculate the + # new index and highest_index accordingly. + highest_index = index + index = int(index - (index - smallest_index) / 2) + else: + smallest_index = index + index = int(index + (highest_index - index) / 2) + # We found the number of words which will fit. + if smallest_index == index or highest_index == index: + index = smallest_index + formatted.append(previous_raw.rstrip(u'
') + + u''.join(raw_text[:index + 1])) + previous_html = u'' + previous_raw = u'' + else: + continue + # Check if the rest of the line fits on the slide. If it + # does we do not have to do the much more intensive "word by + # word" checking. + html = self.page_shell + \ + u''.join(html_words[index + 1:]).strip() + HTML_END + self.web.setHtml(html) + if self.web_frame.contentsSize().height() <= self.page_height: + previous_html = \ + u''.join(html_words[index + 1:]).strip() + line_end + previous_raw = u''.join(raw_text[index + 1:]).strip() + line_end + break + else: + # The other words do not fit, thus reset the indexes, + # create a new list and continue with "word by word". + raw_text = raw_text[index + 1:] + html_words = html_words[index + 1:] + smallest_index = 0 + highest_index = len(html_words) - 1 + index = int(highest_index / 2) + return previous_html, previous_raw, index + def _words_split(self, line): """ Split the slide up by word so can wrap better diff --git a/openlp/core/lib/serviceitem.py b/openlp/core/lib/serviceitem.py index cf682abc6..62d29d8be 100644 --- a/openlp/core/lib/serviceitem.py +++ b/openlp/core/lib/serviceitem.py @@ -172,6 +172,9 @@ class ServiceItem(object): self.themedata = self.renderer.theme_data if self.service_item_type == ServiceItemType.Text: log.debug(u'Formatting slides') + import time + import datetime + start = time.time() for slide in self._raw_frames: formatted = self.renderer \ .format_slide(slide[u'raw_slide'], line_break, self) @@ -184,6 +187,7 @@ class ServiceItem(object): u'html': html.replace(u'&nbsp;', u' '), u'verseTag': slide[u'verseTag'] }) + print unicode(datetime.timedelta(seconds=time.time() - start)) elif self.service_item_type == ServiceItemType.Image or \ self.service_item_type == ServiceItemType.Command: pass From d7ea2183426fc5e437312a41014cf224412ffeac Mon Sep 17 00:00:00 2001 From: Andreas Preikschat Date: Mon, 13 Jun 2011 10:16:50 +0200 Subject: [PATCH 005/184] clean ups --- openlp/core/lib/renderer.py | 55 ++++++++++++++++------------------ openlp/core/lib/serviceitem.py | 6 ++-- 2 files changed, 27 insertions(+), 34 deletions(-) diff --git a/openlp/core/lib/renderer.py b/openlp/core/lib/renderer.py index 6d921f509..d25fb0aae 100644 --- a/openlp/core/lib/renderer.py +++ b/openlp/core/lib/renderer.py @@ -206,20 +206,24 @@ class Renderer(object): self._calculate_default(self.screens.current[u'size']) return preview - def format_slide(self, text, line_break, item): + def format_slide(self, text, item): """ Calculate how much text can fit on a slide. ``text`` The words to go on the slides. - ``line_break`` - Add line endings after each line of text used for bibles. + ``item`` + The service item object. """ log.debug(u'format slide') + # Add line endings after each line of text used for bibles. + line_end = u'
' + if item.is_capable(ItemCapabilities.NoLineBreaks): + line_end = u' ' # clean up line endings lines = self._lines_split(text) - pages = self._paginate_slide(lines, line_break, self.force_page) + pages = self._paginate_slide(lines, line_end) if len(pages) > 1: # Songs and Custom if item.is_capable(ItemCapabilities.AllowsVirtualSplit): @@ -228,12 +232,11 @@ class Renderer(object): pages = [] for slide in slides: lines = slide.strip(u'\n').split(u'\n') - new_pages = self._paginate_slide(lines, line_break, - self.force_page) + new_pages = self._paginate_slide(lines, line_end) pages.extend(new_pages) # Bibles elif item.is_capable(ItemCapabilities.AllowsWordSplit): - pages = self._paginate_slide_words(text, line_break) + pages = self._paginate_slide_words(text, line_end) return pages def _calculate_default(self, screen): @@ -241,7 +244,7 @@ class Renderer(object): Calculate the default dimentions of the screen. ``screen`` - The QSize of the screen. + The screen to calculate the default of. """ log.debug(u'_calculate default %s', screen) self.width = screen.width() @@ -308,25 +311,19 @@ class Renderer(object): (build_lyrics_format_css(self.theme_data, self.page_width, self.page_height), build_lyrics_outline_css(self.theme_data)) - def _paginate_slide(self, lines, line_break, force_page=False): + def _paginate_slide(self, lines, line_end): """ Figure out how much text can appear on a slide, using the current theme settings. ``lines`` - The words to be fitted on the slide split into lines. + The text to be fitted on the slide split into lines. - ``line_break`` + ``line_end`` Add line endings after each line of text (used for bibles). - - ``force_page`` - Flag to tell message lines in page. - """ log.debug(u'_paginate_slide - Start') - line_end = u'' - if line_break: - line_end = u'
' + #print line_end formatted = [] previous_html = u'' previous_raw = u'' @@ -336,11 +333,8 @@ class Renderer(object): self.web.setHtml(html) # Text too long so go to next page. if self.web_frame.contentsSize().height() > self.page_height: - html_text, previous_raw, index = self._binary_chop( - formatted, previous_html, previous_raw, html_lines, lines, - line_end) - if force_page: - Receiver.send_message(u'theme_line_count', index + 1) + html_text, previous_raw = self._binary_chop(formatted, + previous_html, previous_raw, html_lines, lines, line_end) else: previous_raw = u''.join(lines) while previous_raw.endswith(u'
'): @@ -350,7 +344,7 @@ class Renderer(object): log.debug(u'_paginate_slide - End') return formatted - def _paginate_slide_words(self, text, line_break): + def _paginate_slide_words(self, text, line_end): """ Figure out how much text can appear on a slide, using the current theme settings. This version is to handle text which needs to be split @@ -359,14 +353,11 @@ class Renderer(object): ``text`` The words to be fitted on the slide split into lines. - ``line_break`` + ``line_end`` Add line endings after each line of text used for bibles. """ log.debug(u'_paginate_slide_words - Start') - line_end = u' ' - if line_break: - line_end = u'
' formatted = [] previous_html = u'' previous_raw = u'' @@ -404,7 +395,7 @@ class Renderer(object): # using the algorithm known as "binary chop". raw_words = self._words_split(line) html_words = map(expand_tags, raw_text) - previous_html, previous_raw, index = self._binary_chop( + previous_html, previous_raw = self._binary_chop( formatted, previous_html, previous_raw, html_words, raw_words, line_end) else: @@ -466,6 +457,10 @@ class Renderer(object): u''.join(raw_list[:index + 1])) previous_html = u'' previous_raw = u'' + # Stop here as the theme line count was requested. + if self.force_page: + Receiver.send_message(u'theme_line_count', index + 1) + break else: continue # Check if the rest of the line fits on the slide. If it @@ -487,7 +482,7 @@ class Renderer(object): smallest_index = 0 highest_index = len(html_list) - 1 index = int(highest_index / 2) - return previous_html, previous_raw, index + return previous_html, previous_raw def _words_split(self, line): """ diff --git a/openlp/core/lib/serviceitem.py b/openlp/core/lib/serviceitem.py index 1eb1a908b..6a8ba81c4 100644 --- a/openlp/core/lib/serviceitem.py +++ b/openlp/core/lib/serviceitem.py @@ -165,7 +165,6 @@ class ServiceItem(object): log.debug(u'Render called') self._display_frames = [] self.bg_image_bytes = None - line_break = not self.is_capable(ItemCapabilities.NoLineBreaks) theme = self.theme if self.theme else None self.main, self.footer = \ self.renderer.set_override_theme(theme, use_override) @@ -176,9 +175,8 @@ class ServiceItem(object): import datetime start = time.time() for slide in self._raw_frames: - formatted = self.renderer \ - .format_slide(slide[u'raw_slide'], line_break, self) - for page in formatted: + pages = self.renderer.format_slide(slide[u'raw_slide'], self) + for page in pages: page = page.replace(u'
', u'{br}') html = expand_tags(cgi.escape(page.rstrip())) self._display_frames.append({ From ded49f74a3e7951a77e01460b17068ebd5919842 Mon Sep 17 00:00:00 2001 From: Andreas Preikschat Date: Mon, 13 Jun 2011 11:05:22 +0200 Subject: [PATCH 006/184] clean ups --- openlp/core/lib/renderer.py | 39 +++++++++++++++++-------------------- 1 file changed, 18 insertions(+), 21 deletions(-) diff --git a/openlp/core/lib/renderer.py b/openlp/core/lib/renderer.py index d25fb0aae..b6061d474 100644 --- a/openlp/core/lib/renderer.py +++ b/openlp/core/lib/renderer.py @@ -214,7 +214,7 @@ class Renderer(object): The words to go on the slides. ``item`` - The service item object. + The :class:`~openlp.core.lib.serviceitem` item object. """ log.debug(u'format slide') # Add line endings after each line of text used for bibles. @@ -232,12 +232,16 @@ class Renderer(object): pages = [] for slide in slides: lines = slide.strip(u'\n').split(u'\n') - new_pages = self._paginate_slide(lines, line_end) - pages.extend(new_pages) + pages.extend(self._paginate_slide(lines, line_end)) # Bibles elif item.is_capable(ItemCapabilities.AllowsWordSplit): pages = self._paginate_slide_words(text, line_end) - return pages + new_pages = [] + for page in pages: + while page.endswith(u'
'): + page = page[:-4] + new_pages.append(page) + return new_pages def _calculate_default(self, screen): """ @@ -320,10 +324,9 @@ class Renderer(object): The text to be fitted on the slide split into lines. ``line_end`` - Add line endings after each line of text (used for bibles). + The text added after each line. Either ``u' '`` or ``u'
``. """ log.debug(u'_paginate_slide - Start') - #print line_end formatted = [] previous_html = u'' previous_raw = u'' @@ -337,8 +340,6 @@ class Renderer(object): previous_html, previous_raw, html_lines, lines, line_end) else: previous_raw = u''.join(lines) - while previous_raw.endswith(u'
'): - previous_raw = previous_raw[:-4] if previous_raw: formatted.append(previous_raw) log.debug(u'_paginate_slide - End') @@ -354,8 +355,8 @@ class Renderer(object): The words to be fitted on the slide split into lines. ``line_end`` - Add line endings after each line of text used for bibles. - + The text added after each line. Either ``u' '`` or ``u'
``. This + is needed for bibles. """ log.debug(u'_paginate_slide_words - Start') formatted = [] @@ -364,8 +365,8 @@ class Renderer(object): lines = text.split(u'\n') for line in lines: line = line.strip() - styled_line = expand_tags(line) - html = self.page_shell + previous_html + styled_line + HTML_END + html_line = expand_tags(line) + html = self.page_shell + previous_html + html_line + HTML_END self.web.setHtml(html) # Text too long so go to next page. if self.web_frame.contentsSize().height() > self.page_height: @@ -376,33 +377,29 @@ class Renderer(object): self.web.setHtml(html) if self.web_frame.contentsSize().height() <= \ self.page_height: - while previous_raw.endswith(u'
'): - previous_raw = previous_raw[:-4] formatted.append(previous_raw) previous_html = u'' previous_raw = u'' - html = self.page_shell + styled_line + HTML_END + html = self.page_shell + html_line + HTML_END self.web.setHtml(html) # Now check if the current verse will fit, if it does # not we have to start to process the verse word by # word. if self.web_frame.contentsSize().height() <= \ self.page_height: - previous_html = styled_line + line_end + previous_html = html_line + line_end previous_raw = line + line_end continue - # Figure out how many words of the line will fit on screen by - # using the algorithm known as "binary chop". + # Figure out how many words of the line will fit on screen as + # the line will not fit as a whole. raw_words = self._words_split(line) html_words = map(expand_tags, raw_text) previous_html, previous_raw = self._binary_chop( formatted, previous_html, previous_raw, html_words, raw_words, line_end) else: - previous_html += styled_line + line_end + previous_html += html_line + line_end previous_raw += line + line_end - while previous_raw.endswith(u'
'): - previous_raw = previous_raw[:-4] formatted.append(previous_raw) log.debug(u'_paginate_slide_words - End') return formatted From 772c36ed19a0b26ae79fbf42987875b04be059ac Mon Sep 17 00:00:00 2001 From: Andreas Preikschat Date: Mon, 13 Jun 2011 11:47:18 +0200 Subject: [PATCH 007/184] more clean ups, doc --- openlp/core/lib/renderer.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/openlp/core/lib/renderer.py b/openlp/core/lib/renderer.py index b6061d474..28bd8c513 100644 --- a/openlp/core/lib/renderer.py +++ b/openlp/core/lib/renderer.py @@ -101,7 +101,7 @@ class Renderer(object): The global-level theme to be set. ``theme_level`` - Defaults to *``ThemeLevel.Global``*. The theme level, can be + Defaults to ``ThemeLevel.Global``. The theme level, can be ``ThemeLevel.Global``, ``ThemeLevel.Service`` or ``ThemeLevel.Song``. """ @@ -205,6 +205,7 @@ class Renderer(object): # Reset the real screen size for subsequent render requests self._calculate_default(self.screens.current[u'size']) return preview + self.force_page = False def format_slide(self, text, item): """ @@ -214,7 +215,7 @@ class Renderer(object): The words to go on the slides. ``item`` - The :class:`~openlp.core.lib.serviceitem` item object. + The :class:`~openlp.core.lib.serviceitem.ServiceItem` item object. """ log.debug(u'format slide') # Add line endings after each line of text used for bibles. @@ -423,14 +424,16 @@ class Renderer(object): but is not yet added to the list of slides. (unicode string) ``html_list`` - + The text which does not fit on a slide and needs to be processed + using the binary chop. The text contains html. ``raw_list`` The text which does not fit on a slide and needs to be processed using the binary chop. The text can contain display tags. ``line_end`` - The + The text added after each line. Either ``u' '`` or ``u'
``. This + is needed for bibles. """ smallest_index = 0 highest_index = len(html_list) - 1 From f4c00009ed7da61375a903d3831909f0c2e9d0b2 Mon Sep 17 00:00:00 2001 From: Andreas Preikschat Date: Mon, 13 Jun 2011 13:20:47 +0200 Subject: [PATCH 008/184] made _binary_shop less 'word by word' specific --- openlp/core/lib/renderer.py | 38 ++++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/openlp/core/lib/renderer.py b/openlp/core/lib/renderer.py index 28bd8c513..5c80ce71c 100644 --- a/openlp/core/lib/renderer.py +++ b/openlp/core/lib/renderer.py @@ -331,16 +331,16 @@ class Renderer(object): formatted = [] previous_html = u'' previous_raw = u'' - lines = [u'%s
' % line for line in lines] + separator = u'
' html_lines = map(expand_tags, lines) - html = self.page_shell + u''.join(html_lines) + HTML_END + html = self.page_shell + separator.join(html_lines) + HTML_END self.web.setHtml(html) # Text too long so go to next page. if self.web_frame.contentsSize().height() > self.page_height: html_text, previous_raw = self._binary_chop(formatted, - previous_html, previous_raw, html_lines, lines, line_end) + previous_html, previous_raw, html_lines, lines, separator, u'') else: - previous_raw = u''.join(lines) + previous_raw = separator.join(lines) if previous_raw: formatted.append(previous_raw) log.debug(u'_paginate_slide - End') @@ -394,10 +394,10 @@ class Renderer(object): # Figure out how many words of the line will fit on screen as # the line will not fit as a whole. raw_words = self._words_split(line) - html_words = map(expand_tags, raw_text) + html_words = map(expand_tags, raw_words) previous_html, previous_raw = self._binary_chop( formatted, previous_html, previous_raw, html_words, - raw_words, line_end) + raw_words, u' ', line_end) else: previous_html += html_line + line_end previous_raw += line + line_end @@ -406,7 +406,7 @@ class Renderer(object): return formatted def _binary_chop(self, formatted, previous_html, previous_raw, html_list, - raw_list, line_end): + raw_list, separator, line_end): """ This implements the binary chop algorithm for faster rendering. However, it is assumed that this method is **only** called, when the text to be @@ -431,16 +431,20 @@ class Renderer(object): The text which does not fit on a slide and needs to be processed using the binary chop. The text can contain display tags. + ``separator`` + The separator for the elements. For lines this is `u'
'`` and for + words this is u' '. + ``line_end`` - The text added after each line. Either ``u' '`` or ``u'
``. This - is needed for bibles. + The text added after each "element line". Either ``u' '`` or + ``u'
``. This is needed for bibles. """ smallest_index = 0 highest_index = len(html_list) - 1 index = int(highest_index / 2) while True: html = self.page_shell + previous_html + \ - u''.join(html_list[:index + 1]).strip() + HTML_END + separator.join(html_list[:index + 1]).strip() + HTML_END self.web.setHtml(html) if self.web_frame.contentsSize().height() > self.page_height: # We know that it does not fit, so change/calculate the @@ -454,7 +458,7 @@ class Renderer(object): if smallest_index == index or highest_index == index: index = smallest_index formatted.append(previous_raw.rstrip(u'
') + - u''.join(raw_list[:index + 1])) + separator.join(raw_list[:index + 1])) previous_html = u'' previous_raw = u'' # Stop here as the theme line count was requested. @@ -467,12 +471,13 @@ class Renderer(object): # does we do not have to do the much more intensive "word by # word" checking. html = self.page_shell + \ - u''.join(html_list[index + 1:]).strip() + HTML_END + separator.join(html_list[index + 1:]).strip() + HTML_END self.web.setHtml(html) if self.web_frame.contentsSize().height() <= self.page_height: - previous_html = \ - u''.join(html_list[index + 1:]).strip() + line_end - previous_raw = u''.join(raw_list[index + 1:]).strip() + line_end + previous_html = separator.join( + html_list[index + 1:]).strip() + line_end + previous_raw = separator.join( + raw_list[index + 1:]).strip() + line_end break else: # The other words do not fit, thus reset the indexes, @@ -490,8 +495,7 @@ class Renderer(object): """ # this parse we are to be wordy line = line.replace(u'\n', u' ') - words = line.split(u' ') - return [word + u' ' for word in words] + return line.split(u' ') def _lines_split(self, text): """ From f22e1385be9422e8178a6590d612522431f00a8d Mon Sep 17 00:00:00 2001 From: Andreas Preikschat Date: Mon, 13 Jun 2011 13:26:06 +0200 Subject: [PATCH 009/184] _paginate_slide_words detects long verses itself --- openlp/core/lib/renderer.py | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/openlp/core/lib/renderer.py b/openlp/core/lib/renderer.py index 5c80ce71c..a6db56614 100644 --- a/openlp/core/lib/renderer.py +++ b/openlp/core/lib/renderer.py @@ -222,21 +222,23 @@ class Renderer(object): line_end = u'
' if item.is_capable(ItemCapabilities.NoLineBreaks): line_end = u' ' - # clean up line endings - lines = self._lines_split(text) - pages = self._paginate_slide(lines, line_end) - if len(pages) > 1: - # Songs and Custom - if item.is_capable(ItemCapabilities.AllowsVirtualSplit): - # Do not forget the line breaks ! - slides = text.split(u'[---]') - pages = [] - for slide in slides: - lines = slide.strip(u'\n').split(u'\n') - pages.extend(self._paginate_slide(lines, line_end)) - # Bibles - elif item.is_capable(ItemCapabilities.AllowsWordSplit): - pages = self._paginate_slide_words(text, line_end) + # Bibles + if item.is_capable(ItemCapabilities.AllowsWordSplit): + pages = self._paginate_slide_words(text, line_end) + else: + # Clean up line endings. + lines = self._lines_split(text) + pages = self._paginate_slide(lines, line_end) + #TODO: Maybe move the detection to _paginate_slide. + if len(pages) > 1: + # Songs and Custom + if item.is_capable(ItemCapabilities.AllowsVirtualSplit): + # Do not forget the line breaks! + slides = text.split(u'[---]') + pages = [] + for slide in slides: + lines = slide.strip(u'\n').split(u'\n') + pages.extend(self._paginate_slide(lines, line_end)) new_pages = [] for page in pages: while page.endswith(u'
'): From 9b10c81e7b7afac4c17105f93fe8ea3dee2f0d78 Mon Sep 17 00:00:00 2001 From: Andreas Preikschat Date: Mon, 13 Jun 2011 14:59:52 +0200 Subject: [PATCH 010/184] comments --- openlp/core/lib/renderer.py | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/openlp/core/lib/renderer.py b/openlp/core/lib/renderer.py index a6db56614..04f8f0404 100644 --- a/openlp/core/lib/renderer.py +++ b/openlp/core/lib/renderer.py @@ -229,7 +229,6 @@ class Renderer(object): # Clean up line endings. lines = self._lines_split(text) pages = self._paginate_slide(lines, line_end) - #TODO: Maybe move the detection to _paginate_slide. if len(pages) > 1: # Songs and Custom if item.is_capable(ItemCapabilities.AllowsVirtualSplit): @@ -410,12 +409,13 @@ class Renderer(object): def _binary_chop(self, formatted, previous_html, previous_raw, html_list, raw_list, separator, line_end): """ - This implements the binary chop algorithm for faster rendering. However, - it is assumed that this method is **only** called, when the text to be - rendered does not fit as a whole. + This implements the binary chop algorithm for faster rendering. This + algorithm works line based (line by line) and word based (word by word). + It is assumed that this method is **only** called, when the lines/words to be + rendered do not fit as a whole. ``formatted`` - The list of slides. + The list to append any slides. ``previous_html`` The html text which is know to fit on a slide, but is not yet added @@ -426,12 +426,12 @@ class Renderer(object): but is not yet added to the list of slides. (unicode string) ``html_list`` - The text which does not fit on a slide and needs to be processed + The elements which do not fit on a slide and needs to be processed using the binary chop. The text contains html. ``raw_list`` - The text which does not fit on a slide and needs to be processed - using the binary chop. The text can contain display tags. + The elements which do not fit on a slide and needs to be processed + using the binary chop. The elements can contain display tags. ``separator`` The separator for the elements. For lines this is `u'
'`` and for @@ -469,9 +469,7 @@ class Renderer(object): break else: continue - # Check if the rest of the line fits on the slide. If it - # does we do not have to do the much more intensive "word by - # word" checking. + # Check if the remaining elements fit on the slide. html = self.page_shell + \ separator.join(html_list[index + 1:]).strip() + HTML_END self.web.setHtml(html) @@ -482,8 +480,8 @@ class Renderer(object): raw_list[index + 1:]).strip() + line_end break else: - # The other words do not fit, thus reset the indexes, - # create a new list and continue with "word by word". + # The remaining elements do not fit, thus reset the indexes, + # create a new list and continue. raw_list = raw_list[index + 1:] html_list = html_list[index + 1:] smallest_index = 0 From 24e737fa99d2d078c6154f15f2756d9983dbca0d Mon Sep 17 00:00:00 2001 From: Andreas Preikschat Date: Mon, 13 Jun 2011 16:36:18 +0200 Subject: [PATCH 011/184] fixed long line --- openlp/core/lib/renderer.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/openlp/core/lib/renderer.py b/openlp/core/lib/renderer.py index 04f8f0404..1ec6edfa6 100644 --- a/openlp/core/lib/renderer.py +++ b/openlp/core/lib/renderer.py @@ -73,6 +73,8 @@ class Renderer(object): self.screens = ScreenList.get_instance() self.service_theme = u'' self.theme_level = u'' + self._binary_chop( + ) self.override_background = None self.theme_data = None self.bg_frame = None @@ -411,8 +413,8 @@ class Renderer(object): """ This implements the binary chop algorithm for faster rendering. This algorithm works line based (line by line) and word based (word by word). - It is assumed that this method is **only** called, when the lines/words to be - rendered do not fit as a whole. + It is assumed that this method is **only** called, when the lines/words + to be rendered do not fit as a whole. ``formatted`` The list to append any slides. From 254cf20b9fbed6814b7e3eb11e08581e1429e64e Mon Sep 17 00:00:00 2001 From: Andreas Preikschat Date: Mon, 13 Jun 2011 16:41:52 +0200 Subject: [PATCH 012/184] fixed non sense --- openlp/core/lib/renderer.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/openlp/core/lib/renderer.py b/openlp/core/lib/renderer.py index 1ec6edfa6..696d49095 100644 --- a/openlp/core/lib/renderer.py +++ b/openlp/core/lib/renderer.py @@ -73,8 +73,6 @@ class Renderer(object): self.screens = ScreenList.get_instance() self.service_theme = u'' self.theme_level = u'' - self._binary_chop( - ) self.override_background = None self.theme_data = None self.bg_frame = None From 7d5e349602727d8ccfb9a3b47b37e2ada46a7cf5 Mon Sep 17 00:00:00 2001 From: Andreas Preikschat Date: Mon, 13 Jun 2011 17:19:49 +0200 Subject: [PATCH 013/184] removed test lines --- openlp/core/lib/serviceitem.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/openlp/core/lib/serviceitem.py b/openlp/core/lib/serviceitem.py index 6a8ba81c4..fa1b4b92b 100644 --- a/openlp/core/lib/serviceitem.py +++ b/openlp/core/lib/serviceitem.py @@ -171,9 +171,6 @@ class ServiceItem(object): self.themedata = self.renderer.theme_data if self.service_item_type == ServiceItemType.Text: log.debug(u'Formatting slides') - import time - import datetime - start = time.time() for slide in self._raw_frames: pages = self.renderer.format_slide(slide[u'raw_slide'], self) for page in pages: @@ -185,7 +182,6 @@ class ServiceItem(object): u'html': html.replace(u'&nbsp;', u' '), u'verseTag': slide[u'verseTag'] }) - print unicode(datetime.timedelta(seconds=time.time() - start)) elif self.service_item_type == ServiceItemType.Image or \ self.service_item_type == ServiceItemType.Command: pass From bd6733eef13f63e0d6a82aced981051ae0942cb5 Mon Sep 17 00:00:00 2001 From: Andreas Preikschat Date: Tue, 14 Jun 2011 08:58:49 +0200 Subject: [PATCH 014/184] we can replace before splitting --- openlp/core/lib/renderer.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openlp/core/lib/renderer.py b/openlp/core/lib/renderer.py index 696d49095..a8f4e842f 100644 --- a/openlp/core/lib/renderer.py +++ b/openlp/core/lib/renderer.py @@ -503,5 +503,5 @@ class Renderer(object): """ # this parse we do not want to use this so remove it text = text.replace(u'\n[---]', u'') - lines = text.split(u'\n') - return [line.replace(u'[---]', u'') for line in lines] + text = text.replace(u'[---]', u'') + return text.split(u'\n') From 2939151ff1e78841b361fe1090617ea07b13f6d5 Mon Sep 17 00:00:00 2001 From: Benny Date: Tue, 21 Jun 2011 07:40:53 +0200 Subject: [PATCH 015/184] EasyWorship importer: added conversion of Tags - basically working, but some issues remain --- openlp/plugins/songs/lib/ewimport.py | 728 ++++++++++++++------------- 1 file changed, 380 insertions(+), 348 deletions(-) diff --git a/openlp/plugins/songs/lib/ewimport.py b/openlp/plugins/songs/lib/ewimport.py index 09f84fbe2..2431743d6 100644 --- a/openlp/plugins/songs/lib/ewimport.py +++ b/openlp/plugins/songs/lib/ewimport.py @@ -1,348 +1,380 @@ -# -*- coding: utf-8 -*- -# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4 - -############################################################################### -# OpenLP - Open Source Lyrics Projection # -# --------------------------------------------------------------------------- # -# Copyright (c) 2008-2011 Raoul Snyman # -# Portions copyright (c) 2008-2011 Tim Bentley, Gerald Britton, Jonathan # -# Corwin, Michael Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, # -# Armin Köhler, Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias # -# Põldaru, Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, # -# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # -# --------------------------------------------------------------------------- # -# This program is free software; you can redistribute it and/or modify it # -# under the terms of the GNU General Public License as published by the Free # -# Software Foundation; version 2 of the License. # -# # -# This program is distributed in the hope that it will be useful, but WITHOUT # -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for # -# more details. # -# # -# You should have received a copy of the GNU General Public License along # -# with this program; if not, write to the Free Software Foundation, Inc., 59 # -# Temple Place, Suite 330, Boston, MA 02111-1307 USA # -############################################################################### -""" -The :mod:`ewimport` module provides the functionality for importing -EasyWorship song databases into the current installation database. -""" - -import os -import struct - -from openlp.core.lib import translate -from openlp.core.ui.wizard import WizardStrings -from openlp.plugins.songs.lib import VerseType -from openlp.plugins.songs.lib import retrieve_windows_encoding -from songimport import SongImport - -def strip_rtf(blob, encoding): - depth = 0 - control = False - clear_text = [] - control_word = [] - for c in blob: - if control: - # for delimiters, set control to False - if c == '{': - if len(control_word) > 0: - depth += 1 - control = False - elif c == '}': - if len(control_word) > 0: - depth -= 1 - control = False - elif c == '\\': - new_control = (len(control_word) > 0) - control = False - elif c.isspace(): - control = False - else: - control_word.append(c) - if len(control_word) == 3 and control_word[0] == '\'': - control = False - if not control: - if len(control_word) == 0: - if c == '{' or c == '}' or c == '\\': - clear_text.append(c) - else: - control_str = ''.join(control_word) - if control_str == 'par' or control_str == 'line': - clear_text.append(u'\n') - elif control_str == 'tab': - clear_text.append(u'\t') - # Prefer the encoding specified by the RTF data to that - # specified by the Paradox table header - # West European encoding - elif control_str == 'fcharset0': - encoding = u'cp1252' - # Greek encoding - elif control_str == 'fcharset161': - encoding = u'cp1253' - # Turkish encoding - elif control_str == 'fcharset162': - encoding = u'cp1254' - # Vietnamese encoding - elif control_str == 'fcharset163': - encoding = u'cp1258' - # Hebrew encoding - elif control_str == 'fcharset177': - encoding = u'cp1255' - # Arabic encoding - elif control_str == 'fcharset178': - encoding = u'cp1256' - # Baltic encoding - elif control_str == 'fcharset186': - encoding = u'cp1257' - # Cyrillic encoding - elif control_str == 'fcharset204': - encoding = u'cp1251' - # Thai encoding - elif control_str == 'fcharset222': - encoding = u'cp874' - # Central+East European encoding - elif control_str == 'fcharset238': - encoding = u'cp1250' - elif control_str[0] == '\'': - s = chr(int(control_str[1:3], 16)) - clear_text.append(s.decode(encoding)) - del control_word[:] - if c == '\\' and new_control: - control = True - elif c == '{': - depth += 1 - elif c == '}': - depth -= 1 - elif depth > 2: - continue - elif c == '\n' or c == '\r': - continue - elif c == '\\': - control = True - else: - clear_text.append(c) - return u''.join(clear_text) - -class FieldDescEntry: - def __init__(self, name, type, size): - self.name = name - self.type = type - self.size = size - - -class EasyWorshipSongImport(SongImport): - """ - The :class:`EasyWorshipSongImport` class provides OpenLP with the - ability to import EasyWorship song files. - """ - def __init__(self, manager, **kwargs): - SongImport.__init__(self, manager, **kwargs) - - def do_import(self): - # Open the DB and MB files if they exist - import_source_mb = self.import_source.replace('.DB', '.MB') - if not os.path.isfile(self.import_source): - return - if not os.path.isfile(import_source_mb): - return - db_size = os.path.getsize(self.import_source) - if db_size < 0x800: - return - db_file = open(self.import_source, 'rb') - self.memo_file = open(import_source_mb, 'rb') - # Don't accept files that are clearly not paradox files - record_size, header_size, block_size, first_block, num_fields \ - = struct.unpack(' 4: - db_file.close() - self.memo_file.close() - return - # Take a stab at how text is encoded - self.encoding = u'cp1252' - db_file.seek(106) - code_page, = struct.unpack(''] - for field_desc in field_descs: - if field_desc.type == 1: - # string - fsl.append('%ds' % field_desc.size) - elif field_desc.type == 3: - # 16-bit int - fsl.append('H') - elif field_desc.type == 4: - # 32-bit int - fsl.append('I') - elif field_desc.type == 9: - # Logical - fsl.append('B') - elif field_desc.type == 0x0c: - # Memo - fsl.append('%ds' % field_desc.size) - elif field_desc.type == 0x0d: - # Blob - fsl.append('%ds' % field_desc.size) - elif field_desc.type == 0x15: - # Timestamp - fsl.append('Q') - else: - fsl.append('%ds' % field_desc.size) - self.record_struct = struct.Struct(''.join(fsl)) - self.field_descs = field_descs - - def get_field(self, field_desc_index): - field = self.fields[field_desc_index] - field_desc = self.field_descs[field_desc_index] - # Return None in case of 'blank' entries - if isinstance(field, str): - if len(field.rstrip('\0')) == 0: - return None - elif field == 0: - return None - # Format the field depending on the field type - if field_desc.type == 1: - # string - return field.rstrip('\0').decode(self.encoding) - elif field_desc.type == 3: - # 16-bit int - return field ^ 0x8000 - elif field_desc.type == 4: - # 32-bit int - return field ^ 0x80000000 - elif field_desc.type == 9: - # Logical - return (field ^ 0x80 == 1) - elif field_desc.type == 0x0c or field_desc.type == 0x0d: - # Memo or Blob - block_start, blob_size = \ - struct.unpack_from(' 63: - return u'' - self.memo_file.seek(11 + (5 * sub_block), os.SEEK_CUR) - sub_block_start, = struct.unpack('B', self.memo_file.read(1)) - self.memo_file.seek(block_start + (sub_block_start * 16)) - else: - return u'' - return self.memo_file.read(blob_size) - else: - return 0 +# -*- coding: utf-8 -*- +# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4 + +############################################################################### +# OpenLP - Open Source Lyrics Projection # +# --------------------------------------------------------------------------- # +# Copyright (c) 2008-2011 Raoul Snyman # +# Portions copyright (c) 2008-2011 Tim Bentley, Gerald Britton, Jonathan # +# Corwin, Michael Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, # +# Armin Köhler, Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias # +# Põldaru, Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # +# --------------------------------------------------------------------------- # +# This program is free software; you can redistribute it and/or modify it # +# under the terms of the GNU General Public License as published by the Free # +# Software Foundation; version 2 of the License. # +# # +# This program is distributed in the hope that it will be useful, but WITHOUT # +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for # +# more details. # +# # +# You should have received a copy of the GNU General Public License along # +# with this program; if not, write to the Free Software Foundation, Inc., 59 # +# Temple Place, Suite 330, Boston, MA 02111-1307 USA # +############################################################################### +""" +The :mod:`ewimport` module provides the functionality for importing +EasyWorship song databases into the current installation database. +""" + +import os +import struct +import re + +from openlp.core.lib import translate +from openlp.core.ui.wizard import WizardStrings +from openlp.plugins.songs.lib import VerseType +from openlp.plugins.songs.lib import retrieve_windows_encoding +from songimport import SongImport + +def strip_rtf(blob, encoding): + depth = 0 + control = False + clear_text = [] + control_word = [] + for c in blob: + if control: + # for delimiters, set control to False + if c == '{': + if len(control_word) > 0: + depth += 1 + control = False + elif c == '}': + if len(control_word) > 0: + depth -= 1 + control = False + elif c == '\\': + new_control = (len(control_word) > 0) + control = False + elif c.isspace(): + control = False + else: + control_word.append(c) + if len(control_word) == 3 and control_word[0] == '\'': + control = False + if not control: + if len(control_word) == 0: + if c == '{' or c == '}' or c == '\\': + clear_text.append(c) + else: + control_str = ''.join(control_word) + if control_str == 'par' or control_str == 'line': + clear_text.append(u'\n') + elif control_str == 'tab': + clear_text.append(u'\t') + # Prefer the encoding specified by the RTF data to that + # specified by the Paradox table header + # West European encoding + elif control_str == 'fcharset0': + encoding = u'cp1252' + # Greek encoding + elif control_str == 'fcharset161': + encoding = u'cp1253' + # Turkish encoding + elif control_str == 'fcharset162': + encoding = u'cp1254' + # Vietnamese encoding + elif control_str == 'fcharset163': + encoding = u'cp1258' + # Hebrew encoding + elif control_str == 'fcharset177': + encoding = u'cp1255' + # Arabic encoding + elif control_str == 'fcharset178': + encoding = u'cp1256' + # Baltic encoding + elif control_str == 'fcharset186': + encoding = u'cp1257' + # Cyrillic encoding + elif control_str == 'fcharset204': + encoding = u'cp1251' + # Thai encoding + elif control_str == 'fcharset222': + encoding = u'cp874' + # Central+East European encoding + elif control_str == 'fcharset238': + encoding = u'cp1250' + elif control_str[0] == '\'': + s = chr(int(control_str[1:3], 16)) + clear_text.append(s.decode(encoding)) + del control_word[:] + if c == '\\' and new_control: + control = True + elif c == '{': + depth += 1 + elif c == '}': + depth -= 1 + elif depth > 2: + continue + elif c == '\n' or c == '\r': + continue + elif c == '\\': + control = True + else: + clear_text.append(c) + return u''.join(clear_text) + +class FieldDescEntry: + def __init__(self, name, type, size): + self.name = name + self.type = type + self.size = size + + +class EasyWorshipSongImport(SongImport): + """ + The :class:`EasyWorshipSongImport` class provides OpenLP with the + ability to import EasyWorship song files. + """ + def __init__(self, manager, **kwargs): + SongImport.__init__(self, manager, **kwargs) + + def do_import(self): + # Open the DB and MB files if they exist + import_source_mb = self.import_source.replace('.DB', '.MB') + if not os.path.isfile(self.import_source): + return + if not os.path.isfile(import_source_mb): + return + db_size = os.path.getsize(self.import_source) + if db_size < 0x800: + return + db_file = open(self.import_source, 'rb') + self.memo_file = open(import_source_mb, 'rb') + # Don't accept files that are clearly not paradox files + record_size, header_size, block_size, first_block, num_fields \ + = struct.unpack(' 4: + db_file.close() + self.memo_file.close() + return + # Take a stab at how text is encoded + self.encoding = u'cp1252' + db_file.seek(106) + code_page, = struct.unpack(' len(type): # tag is followed by number and/or note + p = re.compile(r'[0-9]+') + m = re.search(p, ew_tag) + if m: + number = m.group() + verse_type +=number + + p = re.compile(r'\(.*\)') + m = re.search(p, ew_tag) + if m: + self.comments += ew_tag+'\n' + break + + self.add_verse( + verse_split[-1].strip() if first_line_is_tag else verse.strip(), # TODO: hacky: -1 + verse_type) + if len(self.comments) > 5: + self.comments += unicode(translate('SongsPlugin.EasyWorshipSongImport', + '\n[above are Song Tags with notes imported from EasyWorship]')) + if self.stop_import_flag: + break + if not self.finish(): + self.log_error(self.import_source) + db_file.close() + self.memo_file.close() + + def find_field(self, field_name): + return [i for i, x in enumerate(self.field_descs) + if x.name == field_name][0] + + def set_record_struct(self, field_descs): + # Begin with empty field struct list + fsl = ['>'] + for field_desc in field_descs: + if field_desc.type == 1: + # string + fsl.append('%ds' % field_desc.size) + elif field_desc.type == 3: + # 16-bit int + fsl.append('H') + elif field_desc.type == 4: + # 32-bit int + fsl.append('I') + elif field_desc.type == 9: + # Logical + fsl.append('B') + elif field_desc.type == 0x0c: + # Memo + fsl.append('%ds' % field_desc.size) + elif field_desc.type == 0x0d: + # Blob + fsl.append('%ds' % field_desc.size) + elif field_desc.type == 0x15: + # Timestamp + fsl.append('Q') + else: + fsl.append('%ds' % field_desc.size) + self.record_struct = struct.Struct(''.join(fsl)) + self.field_descs = field_descs + + def get_field(self, field_desc_index): + field = self.fields[field_desc_index] + field_desc = self.field_descs[field_desc_index] + # Return None in case of 'blank' entries + if isinstance(field, str): + if len(field.rstrip('\0')) == 0: + return None + elif field == 0: + return None + # Format the field depending on the field type + if field_desc.type == 1: + # string + return field.rstrip('\0').decode(self.encoding) + elif field_desc.type == 3: + # 16-bit int + return field ^ 0x8000 + elif field_desc.type == 4: + # 32-bit int + return field ^ 0x80000000 + elif field_desc.type == 9: + # Logical + return (field ^ 0x80 == 1) + elif field_desc.type == 0x0c or field_desc.type == 0x0d: + # Memo or Blob + block_start, blob_size = \ + struct.unpack_from(' 63: + return u'' + self.memo_file.seek(11 + (5 * sub_block), os.SEEK_CUR) + sub_block_start, = struct.unpack('B', self.memo_file.read(1)) + self.memo_file.seek(block_start + (sub_block_start * 16)) + else: + return u'' + return self.memo_file.read(blob_size) + else: + return 0 From 31dd4945bae57b2aeaa2f0310290d40824413b6d Mon Sep 17 00:00:00 2001 From: Benny Date: Tue, 21 Jun 2011 07:55:11 +0200 Subject: [PATCH 016/184] fixed line endings --- openlp/plugins/songs/lib/ewimport.py | 759 +++++++++++++-------------- 1 file changed, 379 insertions(+), 380 deletions(-) diff --git a/openlp/plugins/songs/lib/ewimport.py b/openlp/plugins/songs/lib/ewimport.py index 2431743d6..fb82ab347 100644 --- a/openlp/plugins/songs/lib/ewimport.py +++ b/openlp/plugins/songs/lib/ewimport.py @@ -1,380 +1,379 @@ -# -*- coding: utf-8 -*- -# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4 - -############################################################################### -# OpenLP - Open Source Lyrics Projection # -# --------------------------------------------------------------------------- # -# Copyright (c) 2008-2011 Raoul Snyman # -# Portions copyright (c) 2008-2011 Tim Bentley, Gerald Britton, Jonathan # -# Corwin, Michael Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, # -# Armin Köhler, Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias # -# Põldaru, Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, # -# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # -# --------------------------------------------------------------------------- # -# This program is free software; you can redistribute it and/or modify it # -# under the terms of the GNU General Public License as published by the Free # -# Software Foundation; version 2 of the License. # -# # -# This program is distributed in the hope that it will be useful, but WITHOUT # -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for # -# more details. # -# # -# You should have received a copy of the GNU General Public License along # -# with this program; if not, write to the Free Software Foundation, Inc., 59 # -# Temple Place, Suite 330, Boston, MA 02111-1307 USA # -############################################################################### -""" -The :mod:`ewimport` module provides the functionality for importing -EasyWorship song databases into the current installation database. -""" - -import os -import struct -import re - -from openlp.core.lib import translate -from openlp.core.ui.wizard import WizardStrings -from openlp.plugins.songs.lib import VerseType -from openlp.plugins.songs.lib import retrieve_windows_encoding -from songimport import SongImport - -def strip_rtf(blob, encoding): - depth = 0 - control = False - clear_text = [] - control_word = [] - for c in blob: - if control: - # for delimiters, set control to False - if c == '{': - if len(control_word) > 0: - depth += 1 - control = False - elif c == '}': - if len(control_word) > 0: - depth -= 1 - control = False - elif c == '\\': - new_control = (len(control_word) > 0) - control = False - elif c.isspace(): - control = False - else: - control_word.append(c) - if len(control_word) == 3 and control_word[0] == '\'': - control = False - if not control: - if len(control_word) == 0: - if c == '{' or c == '}' or c == '\\': - clear_text.append(c) - else: - control_str = ''.join(control_word) - if control_str == 'par' or control_str == 'line': - clear_text.append(u'\n') - elif control_str == 'tab': - clear_text.append(u'\t') - # Prefer the encoding specified by the RTF data to that - # specified by the Paradox table header - # West European encoding - elif control_str == 'fcharset0': - encoding = u'cp1252' - # Greek encoding - elif control_str == 'fcharset161': - encoding = u'cp1253' - # Turkish encoding - elif control_str == 'fcharset162': - encoding = u'cp1254' - # Vietnamese encoding - elif control_str == 'fcharset163': - encoding = u'cp1258' - # Hebrew encoding - elif control_str == 'fcharset177': - encoding = u'cp1255' - # Arabic encoding - elif control_str == 'fcharset178': - encoding = u'cp1256' - # Baltic encoding - elif control_str == 'fcharset186': - encoding = u'cp1257' - # Cyrillic encoding - elif control_str == 'fcharset204': - encoding = u'cp1251' - # Thai encoding - elif control_str == 'fcharset222': - encoding = u'cp874' - # Central+East European encoding - elif control_str == 'fcharset238': - encoding = u'cp1250' - elif control_str[0] == '\'': - s = chr(int(control_str[1:3], 16)) - clear_text.append(s.decode(encoding)) - del control_word[:] - if c == '\\' and new_control: - control = True - elif c == '{': - depth += 1 - elif c == '}': - depth -= 1 - elif depth > 2: - continue - elif c == '\n' or c == '\r': - continue - elif c == '\\': - control = True - else: - clear_text.append(c) - return u''.join(clear_text) - -class FieldDescEntry: - def __init__(self, name, type, size): - self.name = name - self.type = type - self.size = size - - -class EasyWorshipSongImport(SongImport): - """ - The :class:`EasyWorshipSongImport` class provides OpenLP with the - ability to import EasyWorship song files. - """ - def __init__(self, manager, **kwargs): - SongImport.__init__(self, manager, **kwargs) - - def do_import(self): - # Open the DB and MB files if they exist - import_source_mb = self.import_source.replace('.DB', '.MB') - if not os.path.isfile(self.import_source): - return - if not os.path.isfile(import_source_mb): - return - db_size = os.path.getsize(self.import_source) - if db_size < 0x800: - return - db_file = open(self.import_source, 'rb') - self.memo_file = open(import_source_mb, 'rb') - # Don't accept files that are clearly not paradox files - record_size, header_size, block_size, first_block, num_fields \ - = struct.unpack(' 4: - db_file.close() - self.memo_file.close() - return - # Take a stab at how text is encoded - self.encoding = u'cp1252' - db_file.seek(106) - code_page, = struct.unpack(' len(type): # tag is followed by number and/or note - p = re.compile(r'[0-9]+') - m = re.search(p, ew_tag) - if m: - number = m.group() - verse_type +=number - - p = re.compile(r'\(.*\)') - m = re.search(p, ew_tag) - if m: - self.comments += ew_tag+'\n' - break - - self.add_verse( - verse_split[-1].strip() if first_line_is_tag else verse.strip(), # TODO: hacky: -1 - verse_type) - if len(self.comments) > 5: - self.comments += unicode(translate('SongsPlugin.EasyWorshipSongImport', - '\n[above are Song Tags with notes imported from EasyWorship]')) - if self.stop_import_flag: - break - if not self.finish(): - self.log_error(self.import_source) - db_file.close() - self.memo_file.close() - - def find_field(self, field_name): - return [i for i, x in enumerate(self.field_descs) - if x.name == field_name][0] - - def set_record_struct(self, field_descs): - # Begin with empty field struct list - fsl = ['>'] - for field_desc in field_descs: - if field_desc.type == 1: - # string - fsl.append('%ds' % field_desc.size) - elif field_desc.type == 3: - # 16-bit int - fsl.append('H') - elif field_desc.type == 4: - # 32-bit int - fsl.append('I') - elif field_desc.type == 9: - # Logical - fsl.append('B') - elif field_desc.type == 0x0c: - # Memo - fsl.append('%ds' % field_desc.size) - elif field_desc.type == 0x0d: - # Blob - fsl.append('%ds' % field_desc.size) - elif field_desc.type == 0x15: - # Timestamp - fsl.append('Q') - else: - fsl.append('%ds' % field_desc.size) - self.record_struct = struct.Struct(''.join(fsl)) - self.field_descs = field_descs - - def get_field(self, field_desc_index): - field = self.fields[field_desc_index] - field_desc = self.field_descs[field_desc_index] - # Return None in case of 'blank' entries - if isinstance(field, str): - if len(field.rstrip('\0')) == 0: - return None - elif field == 0: - return None - # Format the field depending on the field type - if field_desc.type == 1: - # string - return field.rstrip('\0').decode(self.encoding) - elif field_desc.type == 3: - # 16-bit int - return field ^ 0x8000 - elif field_desc.type == 4: - # 32-bit int - return field ^ 0x80000000 - elif field_desc.type == 9: - # Logical - return (field ^ 0x80 == 1) - elif field_desc.type == 0x0c or field_desc.type == 0x0d: - # Memo or Blob - block_start, blob_size = \ - struct.unpack_from(' 63: - return u'' - self.memo_file.seek(11 + (5 * sub_block), os.SEEK_CUR) - sub_block_start, = struct.unpack('B', self.memo_file.read(1)) - self.memo_file.seek(block_start + (sub_block_start * 16)) - else: - return u'' - return self.memo_file.read(blob_size) - else: - return 0 +# -*- coding: utf-8 -*- +# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4 + +############################################################################### +# OpenLP - Open Source Lyrics Projection # +# --------------------------------------------------------------------------- # +# Copyright (c) 2008-2011 Raoul Snyman # +# Portions copyright (c) 2008-2011 Tim Bentley, Gerald Britton, Jonathan # +# Corwin, Michael Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, # +# Armin Köhler, Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias # +# Põldaru, Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # +# --------------------------------------------------------------------------- # +# This program is free software; you can redistribute it and/or modify it # +# under the terms of the GNU General Public License as published by the Free # +# Software Foundation; version 2 of the License. # +# # +# This program is distributed in the hope that it will be useful, but WITHOUT # +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for # +# more details. # +# # +# You should have received a copy of the GNU General Public License along # +# with this program; if not, write to the Free Software Foundation, Inc., 59 # +# Temple Place, Suite 330, Boston, MA 02111-1307 USA # +############################################################################### +""" +The :mod:`ewimport` module provides the functionality for importing +EasyWorship song databases into the current installation database. +""" + +import os +import struct +import re + +from openlp.core.lib import translate +from openlp.core.ui.wizard import WizardStrings +from openlp.plugins.songs.lib import VerseType +from openlp.plugins.songs.lib import retrieve_windows_encoding +from songimport import SongImport + +def strip_rtf(blob, encoding): + depth = 0 + control = False + clear_text = [] + control_word = [] + for c in blob: + if control: + # for delimiters, set control to False + if c == '{': + if len(control_word) > 0: + depth += 1 + control = False + elif c == '}': + if len(control_word) > 0: + depth -= 1 + control = False + elif c == '\\': + new_control = (len(control_word) > 0) + control = False + elif c.isspace(): + control = False + else: + control_word.append(c) + if len(control_word) == 3 and control_word[0] == '\'': + control = False + if not control: + if len(control_word) == 0: + if c == '{' or c == '}' or c == '\\': + clear_text.append(c) + else: + control_str = ''.join(control_word) + if control_str == 'par' or control_str == 'line': + clear_text.append(u'\n') + elif control_str == 'tab': + clear_text.append(u'\t') + # Prefer the encoding specified by the RTF data to that + # specified by the Paradox table header + # West European encoding + elif control_str == 'fcharset0': + encoding = u'cp1252' + # Greek encoding + elif control_str == 'fcharset161': + encoding = u'cp1253' + # Turkish encoding + elif control_str == 'fcharset162': + encoding = u'cp1254' + # Vietnamese encoding + elif control_str == 'fcharset163': + encoding = u'cp1258' + # Hebrew encoding + elif control_str == 'fcharset177': + encoding = u'cp1255' + # Arabic encoding + elif control_str == 'fcharset178': + encoding = u'cp1256' + # Baltic encoding + elif control_str == 'fcharset186': + encoding = u'cp1257' + # Cyrillic encoding + elif control_str == 'fcharset204': + encoding = u'cp1251' + # Thai encoding + elif control_str == 'fcharset222': + encoding = u'cp874' + # Central+East European encoding + elif control_str == 'fcharset238': + encoding = u'cp1250' + elif control_str[0] == '\'': + s = chr(int(control_str[1:3], 16)) + clear_text.append(s.decode(encoding)) + del control_word[:] + if c == '\\' and new_control: + control = True + elif c == '{': + depth += 1 + elif c == '}': + depth -= 1 + elif depth > 2: + continue + elif c == '\n' or c == '\r': + continue + elif c == '\\': + control = True + else: + clear_text.append(c) + return u''.join(clear_text) + +class FieldDescEntry: + def __init__(self, name, type, size): + self.name = name + self.type = type + self.size = size + + +class EasyWorshipSongImport(SongImport): + """ + The :class:`EasyWorshipSongImport` class provides OpenLP with the + ability to import EasyWorship song files. + """ + def __init__(self, manager, **kwargs): + SongImport.__init__(self, manager, **kwargs) + + def do_import(self): + # Open the DB and MB files if they exist + import_source_mb = self.import_source.replace('.DB', '.MB') + if not os.path.isfile(self.import_source): + return + if not os.path.isfile(import_source_mb): + return + db_size = os.path.getsize(self.import_source) + if db_size < 0x800: + return + db_file = open(self.import_source, 'rb') + self.memo_file = open(import_source_mb, 'rb') + # Don't accept files that are clearly not paradox files + record_size, header_size, block_size, first_block, num_fields \ + = struct.unpack(' 4: + db_file.close() + self.memo_file.close() + return + # Take a stab at how text is encoded + self.encoding = u'cp1252' + db_file.seek(106) + code_page, = struct.unpack(' len(type): # tag is followed by number and/or note + p = re.compile(r'[0-9]+') + m = re.search(p, ew_tag) + if m: + number = m.group() + verse_type +=number + + p = re.compile(r'\(.*\)') + m = re.search(p, ew_tag) + if m: + self.comments += ew_tag+'\n' + break + self.add_verse( + verse_split[-1].strip() if first_line_is_tag else verse.strip(), # TODO: hacky: -1 + verse_type) + if len(self.comments) > 5: + self.comments += unicode(translate('SongsPlugin.EasyWorshipSongImport', + '\n[above are Song Tags with notes imported from EasyWorship]')) + if self.stop_import_flag: + break + if not self.finish(): + self.log_error(self.import_source) + db_file.close() + self.memo_file.close() + + def find_field(self, field_name): + return [i for i, x in enumerate(self.field_descs) + if x.name == field_name][0] + + def set_record_struct(self, field_descs): + # Begin with empty field struct list + fsl = ['>'] + for field_desc in field_descs: + if field_desc.type == 1: + # string + fsl.append('%ds' % field_desc.size) + elif field_desc.type == 3: + # 16-bit int + fsl.append('H') + elif field_desc.type == 4: + # 32-bit int + fsl.append('I') + elif field_desc.type == 9: + # Logical + fsl.append('B') + elif field_desc.type == 0x0c: + # Memo + fsl.append('%ds' % field_desc.size) + elif field_desc.type == 0x0d: + # Blob + fsl.append('%ds' % field_desc.size) + elif field_desc.type == 0x15: + # Timestamp + fsl.append('Q') + else: + fsl.append('%ds' % field_desc.size) + self.record_struct = struct.Struct(''.join(fsl)) + self.field_descs = field_descs + + def get_field(self, field_desc_index): + field = self.fields[field_desc_index] + field_desc = self.field_descs[field_desc_index] + # Return None in case of 'blank' entries + if isinstance(field, str): + if len(field.rstrip('\0')) == 0: + return None + elif field == 0: + return None + # Format the field depending on the field type + if field_desc.type == 1: + # string + return field.rstrip('\0').decode(self.encoding) + elif field_desc.type == 3: + # 16-bit int + return field ^ 0x8000 + elif field_desc.type == 4: + # 32-bit int + return field ^ 0x80000000 + elif field_desc.type == 9: + # Logical + return (field ^ 0x80 == 1) + elif field_desc.type == 0x0c or field_desc.type == 0x0d: + # Memo or Blob + block_start, blob_size = \ + struct.unpack_from(' 63: + return u'' + self.memo_file.seek(11 + (5 * sub_block), os.SEEK_CUR) + sub_block_start, = struct.unpack('B', self.memo_file.read(1)) + self.memo_file.seek(block_start + (sub_block_start * 16)) + else: + return u'' + return self.memo_file.read(blob_size) + else: + return 0 From 4d20334cce1d24d65732c5fb4178c12962badbed Mon Sep 17 00:00:00 2001 From: Andreas Preikschat Date: Thu, 23 Jun 2011 15:32:32 +0200 Subject: [PATCH 017/184] changed instance variable to camelCase as the class is Qt based --- openlp/core/lib/renderer.py | 14 +++++++------- openlp/core/lib/serviceitem.py | 2 +- openlp/core/ui/maindisplay.py | 14 +++++++------- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/openlp/core/lib/renderer.py b/openlp/core/lib/renderer.py index a8f4e842f..7c3189789 100644 --- a/openlp/core/lib/renderer.py +++ b/openlp/core/lib/renderer.py @@ -56,11 +56,11 @@ class Renderer(object): """ log.info(u'Renderer Loaded') - def __init__(self, image_manager, theme_manager): + def __init__(self, imageManager, theme_manager): """ Initialise the render manager. - ``image_manager`` + ``imageManager`` A ImageManager instance which takes care of e. g. caching and resizing images. @@ -69,7 +69,7 @@ class Renderer(object): """ log.debug(u'Initialisation started') self.theme_manager = theme_manager - self.image_manager = image_manager + self.imageManager = imageManager self.screens = ScreenList.get_instance() self.service_theme = u'' self.theme_level = u'' @@ -77,7 +77,7 @@ class Renderer(object): self.theme_data = None self.bg_frame = None self.force_page = False - self.display = MainDisplay(None, self.image_manager, False) + self.display = MainDisplay(None, self.imageManager, False) self.display.setup() def update_display(self): @@ -88,7 +88,7 @@ class Renderer(object): self._calculate_default(self.screens.current[u'size']) if self.display: self.display.close() - self.display = MainDisplay(None, self.image_manager, False) + self.display = MainDisplay(None, self.imageManager, False) self.display.setup() self.bg_frame = None self.theme_data = None @@ -167,7 +167,7 @@ class Renderer(object): self._build_text_rectangle(self.theme_data) # if No file do not update cache if self.theme_data.background_filename: - self.image_manager.add_image(self.theme_data.theme_name, + self.imageManager.add_image(self.theme_data.theme_name, self.theme_data.background_filename) return self._rect, self._rect_footer @@ -193,7 +193,7 @@ class Renderer(object): # make big page for theme edit dialog to get line count serviceItem.add_from_text(u'', VERSE + VERSE + VERSE) else: - self.image_manager.del_image(theme_data.theme_name) + self.imageManager.del_image(theme_data.theme_name) serviceItem.add_from_text(u'', VERSE) serviceItem.renderer = self serviceItem.raw_footer = FOOTER diff --git a/openlp/core/lib/serviceitem.py b/openlp/core/lib/serviceitem.py index ced78ad68..2ab09dbeb 100644 --- a/openlp/core/lib/serviceitem.py +++ b/openlp/core/lib/serviceitem.py @@ -208,7 +208,7 @@ class ServiceItem(object): """ self.service_item_type = ServiceItemType.Image self._raw_frames.append({u'title': title, u'path': path}) - self.renderer.image_manager.add_image(title, path) + self.renderer.imageManager.add_image(title, path) self._new_item() def add_from_text(self, title, raw_slide, verse_tag=None): diff --git a/openlp/core/ui/maindisplay.py b/openlp/core/ui/maindisplay.py index b661b1e49..1b9098816 100644 --- a/openlp/core/ui/maindisplay.py +++ b/openlp/core/ui/maindisplay.py @@ -48,13 +48,13 @@ class MainDisplay(QtGui.QGraphicsView): """ This is the display screen. """ - def __init__(self, parent, image_manager, live): + def __init__(self, parent, imageManager, live): if live: QtGui.QGraphicsView.__init__(self) else: QtGui.QGraphicsView.__init__(self, parent) self.isLive = live - self.image_manager = image_manager + self.imageManager = imageManager self.screens = ScreenList.get_instance() self.alertTab = None self.hideMode = None @@ -232,7 +232,7 @@ class MainDisplay(QtGui.QGraphicsView): """ API for replacement backgrounds so Images are added directly to cache """ - self.image_manager.add_image(name, path) + self.imageManager.add_image(name, path) self.image(name) if hasattr(self, u'serviceItem'): self.override[u'image'] = name @@ -247,7 +247,7 @@ class MainDisplay(QtGui.QGraphicsView): The name of the image to be displayed """ log.debug(u'image to display') - image = self.image_manager.get_image_bytes(name) + image = self.imageManager.get_image_bytes(name) self.resetVideo() self.displayImage(image) return self.preview() @@ -477,13 +477,13 @@ class MainDisplay(QtGui.QGraphicsView): self.override = {} else: # replace the background - background = self.image_manager. \ + background = self.imageManager. \ get_image_bytes(self.override[u'image']) if self.serviceItem.themedata.background_filename: - self.serviceItem.bg_image_bytes = self.image_manager. \ + self.serviceItem.bg_image_bytes = self.imageManager. \ get_image_bytes(self.serviceItem.themedata.theme_name) if image: - image_bytes = self.image_manager.get_image_bytes(image) + image_bytes = self.imageManager.get_image_bytes(image) else: image_bytes = None html = build_html(self.serviceItem, self.screen, self.alertTab, From 39caaca8d95e10feb86a69ac37171e41664583f8 Mon Sep 17 00:00:00 2001 From: Andreas Preikschat Date: Thu, 23 Jun 2011 16:34:43 +0200 Subject: [PATCH 018/184] comment fixes --- openlp/core/lib/renderer.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/openlp/core/lib/renderer.py b/openlp/core/lib/renderer.py index 7c3189789..11653533c 100644 --- a/openlp/core/lib/renderer.py +++ b/openlp/core/lib/renderer.py @@ -412,7 +412,7 @@ class Renderer(object): This implements the binary chop algorithm for faster rendering. This algorithm works line based (line by line) and word based (word by word). It is assumed that this method is **only** called, when the lines/words - to be rendered do not fit as a whole. + to be rendered do **not** fit as a whole. ``formatted`` The list to append any slides. @@ -434,8 +434,8 @@ class Renderer(object): using the binary chop. The elements can contain display tags. ``separator`` - The separator for the elements. For lines this is `u'
'`` and for - words this is u' '. + The separator for the elements. For lines this is ``u'
'`` and + for words this is ``u' '``. ``line_end`` The text added after each "element line". Either ``u' '`` or From 356ea8fff80cb2f9836a717b1c6712575b413cd9 Mon Sep 17 00:00:00 2001 From: Andreas Preikschat Date: Sat, 25 Jun 2011 06:42:49 +0200 Subject: [PATCH 019/184] - added an 'intelligent' image queue with priorities - resize image in the thread - change instances variables (based on qt) --- openlp/core/lib/imagemanager.py | 170 +++++++++++++++++++++----------- 1 file changed, 114 insertions(+), 56 deletions(-) diff --git a/openlp/core/lib/imagemanager.py b/openlp/core/lib/imagemanager.py index d89cefccc..bab9748d0 100644 --- a/openlp/core/lib/imagemanager.py +++ b/openlp/core/lib/imagemanager.py @@ -32,6 +32,7 @@ to wait for the conversion to happen. """ import logging import time +import Queue from PyQt4 import QtCore @@ -53,15 +54,59 @@ class ImageThread(QtCore.QThread): """ Run the thread. """ - self.imageManager.process() + self.imageManager._process() + + +class Priority(object): + """ + Enumeration class for different priorities. + + ``Low`` + Only the image's byte stream has to be generated. Neither the QImage nor + the byte stream has been requested yet. + + ``Normal`` + The image's byte stream as well as the image has to be generated. + Neither the QImage nor the byte stream has been requested yet. + + ``High`` + The image's byte stream as well as the image has to be generated. The + QImage for this image has been requested. + + ``Urgent`` + The image's byte stream as well as the image has to be generated. The + byte stream for this image has been requested. + """ + Low = 3 + Normal = 2 + High = 1 + Urgent = 0 class Image(object): - name = '' - path = '' - dirty = True - image = None - image_bytes = None + def __init__(self, name='', path=''): + self.name = name + self.path = path + self.image = None + self.image_bytes = None + self.priority = Priority.Normal + + +class PriorityQueue(Queue.PriorityQueue): + """ + Customised ``Queue.PriorityQueue``. + """ + def remove(self, item): + """ + Removes the given ``item`` from the queue. + + ``item`` + The item to remove. This should be a tuple:: + + ``(Priority, Image)`` + """ + if item in self.queue: + self.queue.remove(item) class ImageManager(QtCore.QObject): @@ -76,50 +121,64 @@ class ImageManager(QtCore.QObject): self.width = current_screen[u'size'].width() self.height = current_screen[u'size'].height() self._cache = {} - self._thread_running = False - self._cache_dirty = False - self.image_thread = ImageThread(self) + self._imageThread = ImageThread(self) + self._clean_queue = PriorityQueue() def update_display(self): """ - Screen has changed size so rebuild the cache to new size + Screen has changed size so rebuild the cache to new size. """ log.debug(u'update_display') current_screen = ScreenList.get_instance().current self.width = current_screen[u'size'].width() self.height = current_screen[u'size'].height() - # mark the images as dirty for a rebuild - for key in self._cache.keys(): - image = self._cache[key] - image.dirty = True - image.image = resize_image(image.path, self.width, self.height) - self._cache_dirty = True - # only one thread please - if not self._thread_running: - self.image_thread.start() + # Mark the images as dirty for a rebuild by setting the image and byte + # stream to None. + self._clean_queue = PriorityQueue() + for key, image in self._cache.iteritems(): + image.priority = Priority.Normal + image.image = None + image.image_bytes = None + self._clean_queue.put((image.priority, image)) + # We want only one thread. + if not self._imageThread.isRunning(): + self._imageThread.start() def get_image(self, name): """ - Return the Qimage from the cache + Return the ``QImage`` from the cache. If not present wait for the + background thread to process it. """ log.debug(u'get_image %s' % name) - return self._cache[name].image + image = self._cache[name] + if image.image is None: + self._clean_queue.remove((image.priority, image)) + image.priority = Priority.High + self._clean_queue.put((image.priority, image)) + while image.image is None: + log.debug(u'get_image - waiting') + time.sleep(0.1) + return image.image def get_image_bytes(self, name): """ - Returns the byte string for an image - If not present wait for the background thread to process it. + Returns the byte string for an image. If not present wait for the + background thread to process it. """ log.debug(u'get_image_bytes %s' % name) - if not self._cache[name].image_bytes: - while self._cache[name].dirty: + image = self._cache[name] + if image.image_bytes is None: + self._clean_queue.remove((image.priority, image)) + image.priority = Priority.Urgent + self._clean_queue.put((image.priority, image)) + while image.image_bytes is None: log.debug(u'get_image_bytes - waiting') time.sleep(0.1) - return self._cache[name].image_bytes + return image.image_bytes def del_image(self, name): """ - Delete the Image from the Cache + Delete the Image from the cache. """ log.debug(u'del_image %s' % name) if name in self._cache: @@ -127,45 +186,44 @@ class ImageManager(QtCore.QObject): def add_image(self, name, path): """ - Add image to cache if it is not already there + Add image to cache if it is not already there. """ log.debug(u'add_image %s:%s' % (name, path)) if not name in self._cache: - image = Image() - image.name = name - image.path = path - image.image = resize_image(path, self.width, self.height) + image = Image(name, path) self._cache[name] = image + self._clean_queue.put((image.priority, image)) else: log.debug(u'Image in cache %s:%s' % (name, path)) - self._cache_dirty = True - # only one thread please - if not self._thread_running: - self.image_thread.start() + # We want only one thread. + if not self._imageThread.isRunning(): + self._imageThread.start() - def process(self): + def _process(self): """ - Controls the processing called from a QThread + Controls the processing called from a ``QtCore.QThread``. """ - log.debug(u'process - started') - self._thread_running = True - self.clean_cache() - # data loaded since we started ? - while self._cache_dirty: - log.debug(u'process - recycle') - self.clean_cache() - self._thread_running = False - log.debug(u'process - ended') + log.debug(u'_process - started') + while not self._clean_queue.empty(): + self._clean_cache() + log.debug(u'_process - ended') - def clean_cache(self): + def _clean_cache(self): """ Actually does the work. """ - log.debug(u'clean_cache') - # we will clean the cache now - self._cache_dirty = False - for key in self._cache.keys(): - image = self._cache[key] - if image.dirty: - image.image_bytes = image_to_byte(image.image) - image.dirty = False + log.debug(u'_clean_cache') + image = self._clean_queue.get()[1] + # Generate the QImage for the image. + if image.image is None: + image.image = resize_image(image.path, self.width, self.height) + # If the priority is not urgent, then set the priority to low and + # do not start to generate the byte stream. + if image.priority != Priority.Urgent: + self._clean_queue.remove((image.priority, image)) + image.priority = Priority.Low + self._clean_queue.put((image.priority, image)) + return + # Generate the byte stream for the image. + if image.image_bytes is None: + image.image_bytes = image_to_byte(image.image) From 1730f5a99f8c84b8aca73ca05ab4cdcff72f622d Mon Sep 17 00:00:00 2001 From: Andreas Preikschat Date: Sat, 25 Jun 2011 07:34:07 +0200 Subject: [PATCH 020/184] added new priority and fixed comments --- openlp/core/lib/imagemanager.py | 43 ++++++++++++++++++++++++++------- 1 file changed, 34 insertions(+), 9 deletions(-) diff --git a/openlp/core/lib/imagemanager.py b/openlp/core/lib/imagemanager.py index bab9748d0..d445545a7 100644 --- a/openlp/core/lib/imagemanager.py +++ b/openlp/core/lib/imagemanager.py @@ -43,8 +43,8 @@ log = logging.getLogger(__name__) class ImageThread(QtCore.QThread): """ - A special Qt thread class to speed up the display of text based frames. - This is threaded so it loads the frames in background + A special Qt thread class to speed up the display of images. This is + threaded so it loads the frames and generates byte stream in background. """ def __init__(self, manager): QtCore.QThread.__init__(self, None) @@ -61,22 +61,33 @@ class Priority(object): """ Enumeration class for different priorities. + ``Lowest`` + Only the image's byte stream has to be generated. But neither the + ``QImage`` nor the byte stream has been requested yet. + ``Low`` - Only the image's byte stream has to be generated. Neither the QImage nor - the byte stream has been requested yet. + Only the image's byte stream has to be generated. Because the image's + ``QImage`` has been requested previously it is reasonable to assume that + the byte stream will be needed before the byte stream of other images + which ``QImage`` were not generated due to a request. ``Normal`` The image's byte stream as well as the image has to be generated. - Neither the QImage nor the byte stream has been requested yet. + Neither the ``QImage`` nor the byte stream has been requested yet. ``High`` The image's byte stream as well as the image has to be generated. The - QImage for this image has been requested. + ``QImage`` for this image has been requested. + **Note**, this priority is only set when the ``QImage`` has not been + generated yet. ``Urgent`` The image's byte stream as well as the image has to be generated. The byte stream for this image has been requested. + **Note**, this priority is only set when the byte stream has not been + generated yet. """ + Lowest = 4 Low = 3 Normal = 2 High = 1 @@ -84,6 +95,11 @@ class Priority(object): class Image(object): + """ + This class represents an image. To mark an image as *dirty* set the instance + variables ``image`` and ``image_bytes`` to ``None`` and add the image object + to the queue of images to process. + """ def __init__(self, name='', path=''): self.name = name self.path = path @@ -217,9 +233,18 @@ class ImageManager(QtCore.QObject): # Generate the QImage for the image. if image.image is None: image.image = resize_image(image.path, self.width, self.height) - # If the priority is not urgent, then set the priority to low and - # do not start to generate the byte stream. - if image.priority != Priority.Urgent: + # Set the priority to Lowest and stop here as we need to process + # more important images first. + if image.priority == Priority.Normal: + self._clean_queue.remove((image.priority, image)) + image.priority = Priority.Lowest + self._clean_queue.put((image.priority, image)) + return + # For image with high priority we set the priority to Low, as the + # byte stream might be needed earlier the byte stream of image with + # Normal priority. We stop here as we need to process more important + # images first. + elif image.priority == Priority.High: self._clean_queue.remove((image.priority, image)) image.priority = Priority.Low self._clean_queue.put((image.priority, image)) From b1b29e9abfa8148c2eb5861a119fdd5b8a7fd5d9 Mon Sep 17 00:00:00 2001 From: Andreas Preikschat Date: Sat, 25 Jun 2011 08:20:02 +0200 Subject: [PATCH 021/184] comment fix --- openlp/core/lib/imagemanager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openlp/core/lib/imagemanager.py b/openlp/core/lib/imagemanager.py index d445545a7..3eace2a6a 100644 --- a/openlp/core/lib/imagemanager.py +++ b/openlp/core/lib/imagemanager.py @@ -69,7 +69,7 @@ class Priority(object): Only the image's byte stream has to be generated. Because the image's ``QImage`` has been requested previously it is reasonable to assume that the byte stream will be needed before the byte stream of other images - which ``QImage`` were not generated due to a request. + whose ``QImage`` were not generated due to a request. ``Normal`` The image's byte stream as well as the image has to be generated. From f9792337877274f48a838978a5985e7478f32620 Mon Sep 17 00:00:00 2001 From: Andreas Preikschat Date: Sat, 25 Jun 2011 21:37:23 +0200 Subject: [PATCH 022/184] renamed method --- openlp/core/lib/imagemanager.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/openlp/core/lib/imagemanager.py b/openlp/core/lib/imagemanager.py index 3eace2a6a..ea8295f23 100644 --- a/openlp/core/lib/imagemanager.py +++ b/openlp/core/lib/imagemanager.py @@ -221,14 +221,14 @@ class ImageManager(QtCore.QObject): """ log.debug(u'_process - started') while not self._clean_queue.empty(): - self._clean_cache() + self._process_cache() log.debug(u'_process - ended') - def _clean_cache(self): + def _process_cache(self): """ Actually does the work. """ - log.debug(u'_clean_cache') + log.debug(u'_process_cache') image = self._clean_queue.get()[1] # Generate the QImage for the image. if image.image is None: From 217510281c902c26cfa68829dd63d55e80215fcc Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Sun, 26 Jun 2011 07:49:10 +0100 Subject: [PATCH 023/184] Fix comments --- openlp/core/ui/mainwindow.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/openlp/core/ui/mainwindow.py b/openlp/core/ui/mainwindow.py index 11467cded..12b59763d 100644 --- a/openlp/core/ui/mainwindow.py +++ b/openlp/core/ui/mainwindow.py @@ -424,8 +424,8 @@ class Ui_MainWindow(object): translate('OpenLP.MainWindow', 'Toggle Live Panel')) self.lockPanel.setText( translate('OpenLP.MainWindow', 'L&ock Panels')) - self.lockPanel.setToolTip( - translate('OpenLP.MainWindow', 'Prevent Panels changing')) + self.lockPanel.setStatusTip( + translate('OpenLP.MainWindow', 'Prevent the Panels being moved.')) self.viewLivePanel.setStatusTip(translate('OpenLP.MainWindow', 'Toggle the visibility of the live panel.')) self.settingsPluginListItem.setText(translate('OpenLP.MainWindow', @@ -971,7 +971,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): def setLockPanel(self, lock): """ - Sets the ability to stiop the toolbars being changed. + Sets the ability to stop the toolbars being changed. """ if lock: self.themeManagerDock.setFeatures( From f7f20f9722cab57ed9fedef58bbcfa3294613989 Mon Sep 17 00:00:00 2001 From: Stevan Pettit Date: Mon, 27 Jun 2011 00:05:25 -0400 Subject: [PATCH 024/184] Add link to Windows help file from main window --- openlp/core/ui/mainwindow.py | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/openlp/core/ui/mainwindow.py b/openlp/core/ui/mainwindow.py index 0210da52d..4148b40eb 100644 --- a/openlp/core/ui/mainwindow.py +++ b/openlp/core/ui/mainwindow.py @@ -269,7 +269,20 @@ class Ui_MainWindow(object): self.helpAboutItem = shortcut_action(mainWindow, u'helpAboutItem', [QtGui.QKeySequence(u'Ctrl+F1')], self.onHelpAboutItemClicked, u':/system/system_about.png', category=UiStrings().Help) - self.helpOnlineHelpItem = shortcut_action( + self.localHelpFile = os.path.join( + AppLocation.get_directory(AppLocation.AppDir), 'Openlp.chm') + self.haveHelpFile = os.path.isfile(self.localHelpFile) + if self.haveHelpFile: + self.helpLocalHelpItem = shortcut_action( + mainWindow, u'helpLocalHelpItem', [QtGui.QKeySequence(u'F1')], + self.onHelpLocalHelpClicked, u':/system/system_about.png', + category=UiStrings().Help) + self.helpOnlineHelpItem = shortcut_action( + mainWindow, u'helpOnlineHelpItem', [QtGui.QKeySequence(u'Alt+F1')], + self.onHelpOnlineHelpClicked, u':/system/system_online_help.png', + category=UiStrings().Help) + else: + self.helpOnlineHelpItem = shortcut_action( mainWindow, u'helpOnlineHelpItem', [QtGui.QKeySequence(u'F1')], self.onHelpOnlineHelpClicked, u':/system/system_online_help.png', category=UiStrings().Help) @@ -307,9 +320,14 @@ class Ui_MainWindow(object): add_actions(self.toolsMenu, (self.toolsAddToolItem, None)) add_actions(self.toolsMenu, (self.toolsOpenDataFolder, None)) add_actions(self.toolsMenu, [self.updateThemeImages]) - add_actions(self.helpMenu, (self.helpDocumentationItem, + add_actions(self.helpMenu, (self.helpDocumentationItem, None)) + if self.haveHelpFile: + add_actions(self.helpMenu, (self.helpLocalHelpItem, self.helpOnlineHelpItem, None, self.helpWebSiteItem, self.helpAboutItem)) + else: + add_actions(self.helpMenu, (self.helpOnlineHelpItem, None, + self.helpWebSiteItem, self.helpAboutItem)) add_actions(self.menuBar, (self.fileMenu.menuAction(), self.viewMenu.menuAction(), self.toolsMenu.menuAction(), self.settingsMenu.menuAction(), self.helpMenu.menuAction())) @@ -425,6 +443,9 @@ class Ui_MainWindow(object): self.helpAboutItem.setText(translate('OpenLP.MainWindow', '&About')) self.helpAboutItem.setStatusTip( translate('OpenLP.MainWindow', 'More information about OpenLP')) + if self.haveHelpFile: + self.helpLocalHelpItem.setText( + translate('OpenLP.MainWindow', '&Help')) self.helpOnlineHelpItem.setText( translate('OpenLP.MainWindow', '&Online Help')) self.helpWebSiteItem.setText( @@ -723,6 +744,12 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): import webbrowser webbrowser.open_new(u'http://openlp.org/') + def onHelpLocalHelpClicked(self): + """ + Load the local OpenLP help file + """ + os.startfile(self.localHelpFile) + def onHelpOnlineHelpClicked(self): """ Load the online OpenLP manual From e50ca971d657988005a3b973fe62495b79eb0faf Mon Sep 17 00:00:00 2001 From: Andreas Preikschat Date: Mon, 27 Jun 2011 13:28:58 +0200 Subject: [PATCH 025/184] change queue name; remove image from queue when deleted from cache --- openlp/core/lib/imagemanager.py | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/openlp/core/lib/imagemanager.py b/openlp/core/lib/imagemanager.py index ea8295f23..5970efd4f 100644 --- a/openlp/core/lib/imagemanager.py +++ b/openlp/core/lib/imagemanager.py @@ -138,7 +138,7 @@ class ImageManager(QtCore.QObject): self.height = current_screen[u'size'].height() self._cache = {} self._imageThread = ImageThread(self) - self._clean_queue = PriorityQueue() + self._conversion_queue = PriorityQueue() def update_display(self): """ @@ -150,12 +150,12 @@ class ImageManager(QtCore.QObject): self.height = current_screen[u'size'].height() # Mark the images as dirty for a rebuild by setting the image and byte # stream to None. - self._clean_queue = PriorityQueue() + self._conversion_queue = PriorityQueue() for key, image in self._cache.iteritems(): image.priority = Priority.Normal image.image = None image.image_bytes = None - self._clean_queue.put((image.priority, image)) + self._conversion_queue.put((image.priority, image)) # We want only one thread. if not self._imageThread.isRunning(): self._imageThread.start() @@ -168,9 +168,9 @@ class ImageManager(QtCore.QObject): log.debug(u'get_image %s' % name) image = self._cache[name] if image.image is None: - self._clean_queue.remove((image.priority, image)) + self._conversion_queue.remove((image.priority, image)) image.priority = Priority.High - self._clean_queue.put((image.priority, image)) + self._conversion_queue.put((image.priority, image)) while image.image is None: log.debug(u'get_image - waiting') time.sleep(0.1) @@ -184,9 +184,9 @@ class ImageManager(QtCore.QObject): log.debug(u'get_image_bytes %s' % name) image = self._cache[name] if image.image_bytes is None: - self._clean_queue.remove((image.priority, image)) + self._conversion_queue.remove((image.priority, image)) image.priority = Priority.Urgent - self._clean_queue.put((image.priority, image)) + self._conversion_queue.put((image.priority, image)) while image.image_bytes is None: log.debug(u'get_image_bytes - waiting') time.sleep(0.1) @@ -198,6 +198,8 @@ class ImageManager(QtCore.QObject): """ log.debug(u'del_image %s' % name) if name in self._cache: + self._conversion_queue.remove( + (self._cache[name].priority, self._cache[name])) del self._cache[name] def add_image(self, name, path): @@ -208,7 +210,7 @@ class ImageManager(QtCore.QObject): if not name in self._cache: image = Image(name, path) self._cache[name] = image - self._clean_queue.put((image.priority, image)) + self._conversion_queue.put((image.priority, image)) else: log.debug(u'Image in cache %s:%s' % (name, path)) # We want only one thread. @@ -220,7 +222,7 @@ class ImageManager(QtCore.QObject): Controls the processing called from a ``QtCore.QThread``. """ log.debug(u'_process - started') - while not self._clean_queue.empty(): + while not self._conversion_queue.empty(): self._process_cache() log.debug(u'_process - ended') @@ -229,25 +231,25 @@ class ImageManager(QtCore.QObject): Actually does the work. """ log.debug(u'_process_cache') - image = self._clean_queue.get()[1] + image = self._conversion_queue.get()[1] # Generate the QImage for the image. if image.image is None: image.image = resize_image(image.path, self.width, self.height) # Set the priority to Lowest and stop here as we need to process # more important images first. if image.priority == Priority.Normal: - self._clean_queue.remove((image.priority, image)) + self._conversion_queue.remove((image.priority, image)) image.priority = Priority.Lowest - self._clean_queue.put((image.priority, image)) + self._conversion_queue.put((image.priority, image)) return # For image with high priority we set the priority to Low, as the # byte stream might be needed earlier the byte stream of image with # Normal priority. We stop here as we need to process more important # images first. elif image.priority == Priority.High: - self._clean_queue.remove((image.priority, image)) + self._conversion_queue.remove((image.priority, image)) image.priority = Priority.Low - self._clean_queue.put((image.priority, image)) + self._conversion_queue.put((image.priority, image)) return # Generate the byte stream for the image. if image.image_bytes is None: From 74d2b2d25c7d43dd84dc16383b114bef0726855f Mon Sep 17 00:00:00 2001 From: Andreas Preikschat Date: Mon, 27 Jun 2011 13:44:57 +0200 Subject: [PATCH 026/184] replaced
by
--- openlp/core/lib/__init__.py | 2 +- openlp/core/lib/renderer.py | 16 ++++++++-------- openlp/core/lib/serviceitem.py | 4 ++-- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/openlp/core/lib/__init__.py b/openlp/core/lib/__init__.py index 7fbd5243c..187226272 100644 --- a/openlp/core/lib/__init__.py +++ b/openlp/core/lib/__init__.py @@ -202,7 +202,7 @@ def clean_tags(text): """ Remove Tags from text for display """ - text = text.replace(u'
', u'\n') + text = text.replace(u'
', u'\n') text = text.replace(u'{br}', u'\n') text = text.replace(u' ', u' ') for tag in DisplayTags.get_html_tags(): diff --git a/openlp/core/lib/renderer.py b/openlp/core/lib/renderer.py index 11653533c..3832cb75c 100644 --- a/openlp/core/lib/renderer.py +++ b/openlp/core/lib/renderer.py @@ -219,7 +219,7 @@ class Renderer(object): """ log.debug(u'format slide') # Add line endings after each line of text used for bibles. - line_end = u'
' + line_end = u'
' if item.is_capable(ItemCapabilities.NoLineBreaks): line_end = u' ' # Bibles @@ -240,7 +240,7 @@ class Renderer(object): pages.extend(self._paginate_slide(lines, line_end)) new_pages = [] for page in pages: - while page.endswith(u'
'): + while page.endswith(u'
'): page = page[:-4] new_pages.append(page) return new_pages @@ -326,13 +326,13 @@ class Renderer(object): The text to be fitted on the slide split into lines. ``line_end`` - The text added after each line. Either ``u' '`` or ``u'
``. + The text added after each line. Either ``u' '`` or ``u'
``. """ log.debug(u'_paginate_slide - Start') formatted = [] previous_html = u'' previous_raw = u'' - separator = u'
' + separator = u'
' html_lines = map(expand_tags, lines) html = self.page_shell + separator.join(html_lines) + HTML_END self.web.setHtml(html) @@ -357,7 +357,7 @@ class Renderer(object): The words to be fitted on the slide split into lines. ``line_end`` - The text added after each line. Either ``u' '`` or ``u'
``. This + The text added after each line. Either ``u' '`` or ``u'
``. This is needed for bibles. """ log.debug(u'_paginate_slide_words - Start') @@ -434,12 +434,12 @@ class Renderer(object): using the binary chop. The elements can contain display tags. ``separator`` - The separator for the elements. For lines this is ``u'
'`` and + The separator for the elements. For lines this is ``u'
'`` and for words this is ``u' '``. ``line_end`` The text added after each "element line". Either ``u' '`` or - ``u'
``. This is needed for bibles. + ``u'
``. This is needed for bibles. """ smallest_index = 0 highest_index = len(html_list) - 1 @@ -459,7 +459,7 @@ class Renderer(object): # We found the number of words which will fit. if smallest_index == index or highest_index == index: index = smallest_index - formatted.append(previous_raw.rstrip(u'
') + + formatted.append(previous_raw.rstrip(u'
') + separator.join(raw_list[:index + 1])) previous_html = u'' previous_raw = u'' diff --git a/openlp/core/lib/serviceitem.py b/openlp/core/lib/serviceitem.py index 2ab09dbeb..e5a6c4033 100644 --- a/openlp/core/lib/serviceitem.py +++ b/openlp/core/lib/serviceitem.py @@ -174,7 +174,7 @@ class ServiceItem(object): for slide in self._raw_frames: pages = self.renderer.format_slide(slide[u'raw_slide'], self) for page in pages: - page = page.replace(u'
', u'{br}') + page = page.replace(u'
', u'{br}') html = expand_tags(cgi.escape(page.rstrip())) self._display_frames.append({ u'title': clean_tags(page), @@ -194,7 +194,7 @@ class ServiceItem(object): if self.raw_footer is None: self.raw_footer = [] self.foot_text = \ - u'
'.join([footer for footer in self.raw_footer if footer]) + u'
'.join([footer for footer in self.raw_footer if footer]) def add_from_image(self, path, title): """ From 86c0eea4733fdd2d79f92fa38c1cd93e58d0f263 Mon Sep 17 00:00:00 2001 From: Andreas Preikschat Date: Mon, 27 Jun 2011 13:51:25 +0200 Subject: [PATCH 027/184] changed theme_manager to themeManager as it is Qt based --- openlp/core/lib/renderer.py | 10 +++++----- openlp/plugins/songs/forms/editsongform.py | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/openlp/core/lib/renderer.py b/openlp/core/lib/renderer.py index 3832cb75c..2b20900a9 100644 --- a/openlp/core/lib/renderer.py +++ b/openlp/core/lib/renderer.py @@ -56,7 +56,7 @@ class Renderer(object): """ log.info(u'Renderer Loaded') - def __init__(self, imageManager, theme_manager): + def __init__(self, imageManager, themeManager): """ Initialise the render manager. @@ -64,11 +64,11 @@ class Renderer(object): A ImageManager instance which takes care of e. g. caching and resizing images. - ``theme_manager`` + ``themeManager`` The ThemeManager instance, used to get the current theme details. """ log.debug(u'Initialisation started') - self.theme_manager = theme_manager + self.themeManager = themeManager self.imageManager = imageManager self.screens = ScreenList.get_instance() self.service_theme = u'' @@ -108,7 +108,7 @@ class Renderer(object): self.global_theme = global_theme self.theme_level = theme_level self.global_theme_data = \ - self.theme_manager.getThemeData(self.global_theme) + self.themeManager.getThemeData(self.global_theme) self.theme_data = None def set_service_theme(self, service_theme): @@ -162,7 +162,7 @@ class Renderer(object): if override_levels: self.theme_data = override_theme else: - self.theme_data = self.theme_manager.getThemeData(theme) + self.theme_data = self.themeManager.getThemeData(theme) self._calculate_default(self.screens.current[u'size']) self._build_text_rectangle(self.theme_data) # if No file do not update cache diff --git a/openlp/plugins/songs/forms/editsongform.py b/openlp/plugins/songs/forms/editsongform.py index 05c891a55..171564b24 100644 --- a/openlp/plugins/songs/forms/editsongform.py +++ b/openlp/plugins/songs/forms/editsongform.py @@ -90,7 +90,7 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog): self.onVerseListViewPressed) QtCore.QObject.connect(self.themeAddButton, QtCore.SIGNAL(u'clicked()'), - self.mediaitem.plugin.renderer.theme_manager.onAddTheme) + self.mediaitem.plugin.renderer.themeManager.onAddTheme) QtCore.QObject.connect(self.maintenanceButton, QtCore.SIGNAL(u'clicked()'), self.onMaintenanceButtonClicked) QtCore.QObject.connect(Receiver.get_receiver(), From 2d60f3842ac7107521afe4543a4c6853e65d4406 Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Mon, 27 Jun 2011 16:56:48 +0100 Subject: [PATCH 028/184] review comment --- openlp/core/ui/mainwindow.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openlp/core/ui/mainwindow.py b/openlp/core/ui/mainwindow.py index 191b26998..e73ea5b80 100644 --- a/openlp/core/ui/mainwindow.py +++ b/openlp/core/ui/mainwindow.py @@ -425,7 +425,7 @@ class Ui_MainWindow(object): self.lockPanel.setText( translate('OpenLP.MainWindow', 'L&ock Panels')) self.lockPanel.setStatusTip( - translate('OpenLP.MainWindow', 'Prevent the Panels being moved.')) + translate('OpenLP.MainWindow', 'Prevent the panels being moved.')) self.viewLivePanel.setStatusTip(translate('OpenLP.MainWindow', 'Toggle the visibility of the live panel.')) self.settingsPluginListItem.setText(translate('OpenLP.MainWindow', From 231c47db531ac054d8320a3035e0108225f1cfb0 Mon Sep 17 00:00:00 2001 From: Stevan Pettit Date: Tue, 28 Jun 2011 00:52:46 -0400 Subject: [PATCH 029/184] Remove settings for confirm delete --- openlp/plugins/custom/lib/customtab.py | 29 +------------------------- openlp/plugins/custom/lib/mediaitem.py | 22 ++++++++----------- 2 files changed, 10 insertions(+), 41 deletions(-) diff --git a/openlp/plugins/custom/lib/customtab.py b/openlp/plugins/custom/lib/customtab.py index 12acabd0b..b16746f8b 100644 --- a/openlp/plugins/custom/lib/customtab.py +++ b/openlp/plugins/custom/lib/customtab.py @@ -47,57 +47,30 @@ class CustomTab(SettingsTab): self.displayFooterCheckBox.setObjectName(u'displayFooterCheckBox') self.customModeLayout.addRow(self.displayFooterCheckBox) self.leftLayout.addWidget(self.customModeGroupBox) - self.customUIGroupBox = QtGui.QGroupBox(self.leftColumn) - self.customUIGroupBox.setObjectName(u'customUIGroupBox') - self.customUILayout = QtGui.QFormLayout(self.customUIGroupBox) - self.customUILayout.setObjectName(u'customUILayout') - self.confirmDeleteCheckBox = QtGui.QCheckBox(self.customUIGroupBox) - self.confirmDeleteCheckBox.setObjectName(u'confirmDeleteCheckBox') - self.customUILayout.addRow(self.confirmDeleteCheckBox) - self.leftLayout.addWidget(self.customUIGroupBox) self.leftLayout.addStretch() self.rightLayout.addStretch() QtCore.QObject.connect(self.displayFooterCheckBox, QtCore.SIGNAL(u'stateChanged(int)'), self.onDisplayFooterCheckBoxChanged) - QtCore.QObject.connect(self.confirmDeleteCheckBox, - QtCore.SIGNAL(u'stateChanged(int)'), - self.onConfirmDeleteCheckBoxChanged) def retranslateUi(self): self.customModeGroupBox.setTitle(translate('CustomPlugin.CustomTab', 'Custom Display')) self.displayFooterCheckBox.setText( translate('CustomPlugin.CustomTab', 'Display footer')) - self.customUIGroupBox.setTitle(translate('CustomPlugin.CustomTab', - 'UI Settings')) - self.confirmDeleteCheckBox.setText( - translate('CustomPlugin.CustomTab', 'Confirm delete')) def onDisplayFooterCheckBoxChanged(self, check_state): self.displayFooter = False # we have a set value convert to True/False if check_state == QtCore.Qt.Checked: - self.displayFooter = True - - def onConfirmDeleteCheckBoxChanged(self, check_state): - self.confirmDelete = False - # we have a set value convert to True/False - if check_state == QtCore.Qt.Checked: - self.confirmDelete = True + self.displayFooter = True def load(self): self.displayFooter = QtCore.QSettings().value( self.settingsSection + u'/display footer', QtCore.QVariant(True)).toBool() self.displayFooterCheckBox.setChecked(self.displayFooter) - self.confirmDelete = QtCore.QSettings().value( - self.settingsSection + u'/confirm delete', - QtCore.QVariant(True)).toBool() - self.confirmDeleteCheckBox.setChecked(self.confirmDelete) def save(self): QtCore.QSettings().setValue(self.settingsSection + u'/display footer', QtCore.QVariant(self.displayFooter)) - QtCore.QSettings().setValue(self.settingsSection + u'/confirm delete', - QtCore.QVariant(self.confirmDelete)) diff --git a/openlp/plugins/custom/lib/mediaitem.py b/openlp/plugins/custom/lib/mediaitem.py index fec660360..41accef27 100644 --- a/openlp/plugins/custom/lib/mediaitem.py +++ b/openlp/plugins/custom/lib/mediaitem.py @@ -200,20 +200,16 @@ class CustomMediaItem(MediaManagerItem): Remove a custom item from the list and database """ if check_item_selected(self.listView, UiStrings().SelectDelete): - self.confirmDelete = QtCore.QSettings().value( - self.settingsSection + u'/confirm delete', - QtCore.QVariant(u'False')).toBool() items = self.listView.selectedIndexes() - if self.confirmDelete: - if QtGui.QMessageBox.question(self, - translate('CustomPlugin.MediaItem', 'Delete Custom(s)?'), - translate('CustomPlugin.MediaItem', - 'Are you sure you want to delete the %n selected custom(s)?', '', - QtCore.QCoreApplication.CodecForTr, len(items)), - QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Ok | - QtGui.QMessageBox.Cancel), - QtGui.QMessageBox.Ok) == QtGui.QMessageBox.Cancel: - return + if QtGui.QMessageBox.question(self, + translate('CustomPlugin.MediaItem', 'Delete Custom(s)?'), + translate('CustomPlugin.MediaItem', + 'Are you sure you want to delete the %n selected custom(s)?', '', + QtCore.QCoreApplication.CodecForTr, len(items)), + QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Ok | + QtGui.QMessageBox.Cancel), + QtGui.QMessageBox.Ok) == QtGui.QMessageBox.Cancel: + return row_list = [item.row() for item in self.listView.selectedIndexes()] row_list.sort(reverse=True) id_list = [(item.data(QtCore.Qt.UserRole)).toInt()[0] From c3631659251d8b76febed523f7fd553cf375e5fc Mon Sep 17 00:00:00 2001 From: Stevan Pettit Date: Tue, 28 Jun 2011 00:59:26 -0400 Subject: [PATCH 030/184] Removed some whitespace --- openlp/plugins/custom/lib/customtab.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openlp/plugins/custom/lib/customtab.py b/openlp/plugins/custom/lib/customtab.py index b16746f8b..fb83fab81 100644 --- a/openlp/plugins/custom/lib/customtab.py +++ b/openlp/plugins/custom/lib/customtab.py @@ -63,7 +63,7 @@ class CustomTab(SettingsTab): self.displayFooter = False # we have a set value convert to True/False if check_state == QtCore.Qt.Checked: - self.displayFooter = True + self.displayFooter = True def load(self): self.displayFooter = QtCore.QSettings().value( From f14fa780812839e53e531643e854f58bee97e443 Mon Sep 17 00:00:00 2001 From: Stevan Pettit Date: Tue, 28 Jun 2011 09:29:36 -0400 Subject: [PATCH 031/184] Modified delete message and dialog buttons --- openlp/plugins/custom/lib/mediaitem.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/openlp/plugins/custom/lib/mediaitem.py b/openlp/plugins/custom/lib/mediaitem.py index 41accef27..8babfc245 100644 --- a/openlp/plugins/custom/lib/mediaitem.py +++ b/openlp/plugins/custom/lib/mediaitem.py @@ -204,11 +204,12 @@ class CustomMediaItem(MediaManagerItem): if QtGui.QMessageBox.question(self, translate('CustomPlugin.MediaItem', 'Delete Custom(s)?'), translate('CustomPlugin.MediaItem', - 'Are you sure you want to delete the %n selected custom(s)?', '', + 'Are you sure you want to delete the %n selected custom' \ + ' slides(s)?', '', QtCore.QCoreApplication.CodecForTr, len(items)), - QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Ok | - QtGui.QMessageBox.Cancel), - QtGui.QMessageBox.Ok) == QtGui.QMessageBox.Cancel: + QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Yes | + QtGui.QMessageBox.No), + QtGui.QMessageBox.Yes) == QtGui.QMessageBox.No: return row_list = [item.row() for item in self.listView.selectedIndexes()] row_list.sort(reverse=True) From 75550b505bdb2bc88b4b3e8d12e129c0e6a46ba6 Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Tue, 28 Jun 2011 17:35:50 +0100 Subject: [PATCH 032/184] Save Controller Toolbars Fixes: https://launchpad.net/bugs/765239 --- openlp/core/ui/mainwindow.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/openlp/core/ui/mainwindow.py b/openlp/core/ui/mainwindow.py index e73ea5b80..ca84de411 100644 --- a/openlp/core/ui/mainwindow.py +++ b/openlp/core/ui/mainwindow.py @@ -1030,6 +1030,10 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): self.restoreGeometry( settings.value(u'main window geometry').toByteArray()) self.restoreState(settings.value(u'main window state').toByteArray()) + self.liveController.splitter.restoreState( + settings.value(u'live splitter geometry').toByteArray()) + self.previewController.splitter.restoreState( + settings.value(u'preview splitter geometry').toByteArray()) settings.endGroup() def saveSettings(self): @@ -1050,6 +1054,10 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): QtCore.QVariant(self.saveState())) settings.setValue(u'main window geometry', QtCore.QVariant(self.saveGeometry())) + settings.setValue(u'live splitter geometry', + QtCore.QVariant(self.liveController.splitter.saveState())) + settings.setValue(u'preview splitter geometry', + QtCore.QVariant(self.liveController.splitter.saveState())) settings.endGroup() def updateFileMenu(self): From a167f6ef86f4d21799d7dcd7b5a8abb04101e1bd Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Tue, 28 Jun 2011 17:40:17 +0100 Subject: [PATCH 033/184] Make progressbar smaller --- openlp/core/ui/mainwindow.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/openlp/core/ui/mainwindow.py b/openlp/core/ui/mainwindow.py index ca84de411..53cd5a792 100644 --- a/openlp/core/ui/mainwindow.py +++ b/openlp/core/ui/mainwindow.py @@ -65,6 +65,12 @@ MEDIA_MANAGER_STYLE = """ } """ +PROGRESSBAR = """ + QProgressBar{ + height: 10px; + } +""" + class Ui_MainWindow(object): def setupUi(self, mainWindow): """ @@ -130,6 +136,7 @@ class Ui_MainWindow(object): self.statusBar.addPermanentWidget(self.loadProgressBar) self.loadProgressBar.hide() self.loadProgressBar.setValue(0) + self.loadProgressBar.setStyleSheet(PROGRESSBAR) self.defaultThemeLabel = QtGui.QLabel(self.statusBar) self.defaultThemeLabel.setObjectName(u'defaultThemeLabel') self.statusBar.addPermanentWidget(self.defaultThemeLabel) From 334bf4ab444559b5063a4baf54f2dd56bb4047fb Mon Sep 17 00:00:00 2001 From: Stevan Pettit Date: Tue, 28 Jun 2011 15:05:05 -0400 Subject: [PATCH 034/184] Changed dialog heading. Changed Songs delete confirm to match Custom Slides --- openlp/plugins/custom/lib/mediaitem.py | 6 +++--- openlp/plugins/songs/lib/mediaitem.py | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/openlp/plugins/custom/lib/mediaitem.py b/openlp/plugins/custom/lib/mediaitem.py index 8babfc245..23094a98e 100644 --- a/openlp/plugins/custom/lib/mediaitem.py +++ b/openlp/plugins/custom/lib/mediaitem.py @@ -202,10 +202,10 @@ class CustomMediaItem(MediaManagerItem): if check_item_selected(self.listView, UiStrings().SelectDelete): items = self.listView.selectedIndexes() if QtGui.QMessageBox.question(self, - translate('CustomPlugin.MediaItem', 'Delete Custom(s)?'), + translate('CustomPlugin.MediaItem', 'Confirm Delete'), translate('CustomPlugin.MediaItem', - 'Are you sure you want to delete the %n selected custom' \ - ' slides(s)?', '', + 'Are you sure you want to delete the %n selected custom' + ' slides(s)?', '', QtCore.QCoreApplication.CodecForTr, len(items)), QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Yes | QtGui.QMessageBox.No), diff --git a/openlp/plugins/songs/lib/mediaitem.py b/openlp/plugins/songs/lib/mediaitem.py index 61bdc32c0..badb5cde9 100644 --- a/openlp/plugins/songs/lib/mediaitem.py +++ b/openlp/plugins/songs/lib/mediaitem.py @@ -353,13 +353,13 @@ class SongMediaItem(MediaManagerItem): if check_item_selected(self.listView, UiStrings().SelectDelete): items = self.listView.selectedIndexes() if QtGui.QMessageBox.question(self, - translate('SongsPlugin.MediaItem', 'Delete Song(s)?'), + translate('SongsPlugin.MediaItem', 'Confirm Delete'), translate('SongsPlugin.MediaItem', 'Are you sure you want to delete the %n selected song(s)?', '', QtCore.QCoreApplication.CodecForTr, len(items)), - QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Ok | - QtGui.QMessageBox.Cancel), - QtGui.QMessageBox.Ok) == QtGui.QMessageBox.Cancel: + QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Yes | + QtGui.QMessageBox.No), + QtGui.QMessageBox.Yes) == QtGui.QMessageBox.No: return for item in items: item_id = (item.data(QtCore.Qt.UserRole)).toInt()[0] From 486a427794fa9e3c6a8f56dbc04d244190dac284 Mon Sep 17 00:00:00 2001 From: Raoul Snyman Date: Tue, 28 Jun 2011 21:24:29 +0200 Subject: [PATCH 035/184] Minor UI tweaks. --- openlp/core/ui/serviceitemeditdialog.py | 2 ++ openlp/core/ui/servicenoteform.py | 2 ++ 2 files changed, 4 insertions(+) diff --git a/openlp/core/ui/serviceitemeditdialog.py b/openlp/core/ui/serviceitemeditdialog.py index a00feafc7..d821430b2 100644 --- a/openlp/core/ui/serviceitemeditdialog.py +++ b/openlp/core/ui/serviceitemeditdialog.py @@ -35,6 +35,8 @@ class Ui_ServiceItemEditDialog(object): def setupUi(self, serviceItemEditDialog): serviceItemEditDialog.setObjectName(u'serviceItemEditDialog') self.dialogLayout = QtGui.QGridLayout(serviceItemEditDialog) + self.dialogLayout.setContentsMargins(8, 8, 8, 8) + self.dialogLayout.setSpacing(8) self.dialogLayout.setObjectName(u'dialogLayout') self.listWidget = QtGui.QListWidget(serviceItemEditDialog) self.listWidget.setAlternatingRowColors(True) diff --git a/openlp/core/ui/servicenoteform.py b/openlp/core/ui/servicenoteform.py index d361c567e..3bc55e242 100644 --- a/openlp/core/ui/servicenoteform.py +++ b/openlp/core/ui/servicenoteform.py @@ -49,6 +49,8 @@ class ServiceNoteForm(QtGui.QDialog): def setupUi(self): self.setObjectName(u'serviceNoteEdit') self.dialogLayout = QtGui.QVBoxLayout(self) + self.dialogLayout.setContentsMargins(8, 8, 8, 8) + self.dialogLayout.setSpacing(8) self.dialogLayout.setObjectName(u'verticalLayout') self.textEdit = QtGui.QTextEdit(self) self.textEdit.setObjectName(u'textEdit') From da45d09e48df447d40c8e89a6fb3a2f587e44ca1 Mon Sep 17 00:00:00 2001 From: Stevan Pettit Date: Tue, 28 Jun 2011 16:35:28 -0400 Subject: [PATCH 036/184] Moved delete dialog heading translate to ui.py --- openlp/core/lib/ui.py | 1 + openlp/plugins/custom/lib/mediaitem.py | 2 +- openlp/plugins/songs/lib/mediaitem.py | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/openlp/core/lib/ui.py b/openlp/core/lib/ui.py index 5055bb619..558c8ba52 100644 --- a/openlp/core/lib/ui.py +++ b/openlp/core/lib/ui.py @@ -64,6 +64,7 @@ class UiStrings(object): self.Cancel = translate('OpenLP.Ui', 'Cancel') self.CCLINumberLabel = translate('OpenLP.Ui', 'CCLI number:') self.CreateService = translate('OpenLP.Ui', 'Create a new service.') + self.ConfirmDelete = translate('OpenLP.Ui', 'Confirm Delete') self.Continuous = translate('OpenLP.Ui', 'Continuous') self.Default = unicode(translate('OpenLP.Ui', 'Default')) self.Delete = translate('OpenLP.Ui', '&Delete') diff --git a/openlp/plugins/custom/lib/mediaitem.py b/openlp/plugins/custom/lib/mediaitem.py index 23094a98e..60f25ee0c 100644 --- a/openlp/plugins/custom/lib/mediaitem.py +++ b/openlp/plugins/custom/lib/mediaitem.py @@ -202,7 +202,7 @@ class CustomMediaItem(MediaManagerItem): if check_item_selected(self.listView, UiStrings().SelectDelete): items = self.listView.selectedIndexes() if QtGui.QMessageBox.question(self, - translate('CustomPlugin.MediaItem', 'Confirm Delete'), + UiStrings().ConfirmDelete, translate('CustomPlugin.MediaItem', 'Are you sure you want to delete the %n selected custom' ' slides(s)?', '', diff --git a/openlp/plugins/songs/lib/mediaitem.py b/openlp/plugins/songs/lib/mediaitem.py index badb5cde9..e0634d5cc 100644 --- a/openlp/plugins/songs/lib/mediaitem.py +++ b/openlp/plugins/songs/lib/mediaitem.py @@ -353,7 +353,7 @@ class SongMediaItem(MediaManagerItem): if check_item_selected(self.listView, UiStrings().SelectDelete): items = self.listView.selectedIndexes() if QtGui.QMessageBox.question(self, - translate('SongsPlugin.MediaItem', 'Confirm Delete'), + UiStrings().ConfirmDelete, translate('SongsPlugin.MediaItem', 'Are you sure you want to delete the %n selected song(s)?', '', QtCore.QCoreApplication.CodecForTr, len(items)), From 30df723358536ab462a050fbe51f3871039e88ca Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Wed, 29 Jun 2011 07:12:32 +0100 Subject: [PATCH 037/184] Fixes --- openlp/core/ui/mainwindow.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/openlp/core/ui/mainwindow.py b/openlp/core/ui/mainwindow.py index 53cd5a792..67839b52f 100644 --- a/openlp/core/ui/mainwindow.py +++ b/openlp/core/ui/mainwindow.py @@ -65,7 +65,7 @@ MEDIA_MANAGER_STYLE = """ } """ -PROGRESSBAR = """ +PROGRESSBAR_STYLE = """ QProgressBar{ height: 10px; } @@ -136,7 +136,7 @@ class Ui_MainWindow(object): self.statusBar.addPermanentWidget(self.loadProgressBar) self.loadProgressBar.hide() self.loadProgressBar.setValue(0) - self.loadProgressBar.setStyleSheet(PROGRESSBAR) + self.loadProgressBar.setStyleSheet(PROGRESSBAR_STYLE) self.defaultThemeLabel = QtGui.QLabel(self.statusBar) self.defaultThemeLabel.setObjectName(u'defaultThemeLabel') self.statusBar.addPermanentWidget(self.defaultThemeLabel) @@ -1064,7 +1064,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): settings.setValue(u'live splitter geometry', QtCore.QVariant(self.liveController.splitter.saveState())) settings.setValue(u'preview splitter geometry', - QtCore.QVariant(self.liveController.splitter.saveState())) + QtCore.QVariant(self.previewController.splitter.saveState())) settings.endGroup() def updateFileMenu(self): From 95743de19f5a76196ae36b396dc1b53a69b26e0f Mon Sep 17 00:00:00 2001 From: Andreas Preikschat Date: Wed, 29 Jun 2011 09:38:04 +0200 Subject: [PATCH 038/184] more html fixes --- openlp/core/lib/displaytags.py | 2 +- openlp/core/lib/renderer.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/openlp/core/lib/displaytags.py b/openlp/core/lib/displaytags.py index 95ce13bda..addab4d75 100644 --- a/openlp/core/lib/displaytags.py +++ b/openlp/core/lib/displaytags.py @@ -111,7 +111,7 @@ class DisplayTags(object): u'start html': u'', u'end tag': u'{/u}', u'end html': u'', u'protected': True}) base_tags.append({u'desc': translate('OpenLP.DisplayTags', 'Break'), - u'start tag': u'{br}', u'start html': u'
', u'end tag': u'', + u'start tag': u'{br}', u'start html': u'
', u'end tag': u'', u'end html': u'', u'protected': True}) DisplayTags.add_html_tags(base_tags) diff --git a/openlp/core/lib/renderer.py b/openlp/core/lib/renderer.py index 2b20900a9..4f4a3e4c9 100644 --- a/openlp/core/lib/renderer.py +++ b/openlp/core/lib/renderer.py @@ -241,7 +241,7 @@ class Renderer(object): new_pages = [] for page in pages: while page.endswith(u'
'): - page = page[:-4] + page = page[:-6] new_pages.append(page) return new_pages @@ -357,8 +357,8 @@ class Renderer(object): The words to be fitted on the slide split into lines. ``line_end`` - The text added after each line. Either ``u' '`` or ``u'
``. This - is needed for bibles. + The text added after each line. Either ``u' '`` or ``u'
``. + This is needed for bibles. """ log.debug(u'_paginate_slide_words - Start') formatted = [] From 8bb96b97bfad8ac49e61ed961aedf95510b60c78 Mon Sep 17 00:00:00 2001 From: Andreas Preikschat Date: Wed, 29 Jun 2011 10:04:14 +0200 Subject: [PATCH 039/184] - When creating/editing a custom slide give the title edit the focus (and not only when creating a new) - fixed long lines - simplification --- openlp/plugins/custom/forms/editcustomform.py | 6 ++---- openlp/plugins/songs/forms/editsongform.py | 6 ++++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/openlp/plugins/custom/forms/editcustomform.py b/openlp/plugins/custom/forms/editcustomform.py index 32a2a3146..f4ac97fab 100644 --- a/openlp/plugins/custom/forms/editcustomform.py +++ b/openlp/plugins/custom/forms/editcustomform.py @@ -93,7 +93,6 @@ class EditCustomForm(QtGui.QDialog, Ui_CustomEditDialog): self.titleEdit.setText(u'') self.creditEdit.setText(u'') self.themeComboBox.setCurrentIndex(0) - self.titleEdit.setFocus(QtCore.Qt.OtherFocusReason) else: self.customSlide = self.manager.get_object(CustomSlide, id) self.titleEdit.setText(self.customSlide.title) @@ -104,10 +103,9 @@ class EditCustomForm(QtGui.QDialog, Ui_CustomEditDialog): self.slideListView.addItem(slide[1]) theme = self.customSlide.theme_name find_and_set_in_combo_box(self.themeComboBox, theme) + self.titleEdit.setFocus(QtCore.Qt.OtherFocusReason) # If not preview hide the preview button. - self.previewButton.setVisible(False) - if preview: - self.previewButton.setVisible(True) + self.previewButton.setVisible(preview) def reject(self): Receiver.send_message(u'custom_edit_clear') diff --git a/openlp/plugins/songs/forms/editsongform.py b/openlp/plugins/songs/forms/editsongform.py index a07ceb6c9..4eab75703 100644 --- a/openlp/plugins/songs/forms/editsongform.py +++ b/openlp/plugins/songs/forms/editsongform.py @@ -209,9 +209,11 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog): self.alternativeEdit.setText(u'') if self.song.song_book_id != 0: book_name = self.manager.get_object(Book, self.song.song_book_id) - find_and_set_in_combo_box(self.songBookComboBox, unicode(book_name.name)) + find_and_set_in_combo_box( + self.songBookComboBox, unicode(book_name.name)) if self.song.theme_name: - find_and_set_in_combo_box(self.themeComboBox, unicode(self.song.theme_name)) + find_and_set_in_combo_box( + self.themeComboBox, unicode(self.song.theme_name)) if self.song.copyright: self.copyrightEdit.setText(self.song.copyright) else: From 6e3343c6060606acef6f0dac92fd72199f1c2342 Mon Sep 17 00:00:00 2001 From: Andreas Preikschat Date: Wed, 29 Jun 2011 11:08:53 +0200 Subject: [PATCH 040/184] fixed theme copy --- openlp/core/ui/thememanager.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/openlp/core/ui/thememanager.py b/openlp/core/ui/thememanager.py index d84fe7e1f..ff852c591 100644 --- a/openlp/core/ui/thememanager.py +++ b/openlp/core/ui/thememanager.py @@ -298,11 +298,10 @@ class ThemeManager(QtGui.QWidget): Copies an existing theme to a new name """ item = self.themeListWidget.currentItem() - oldThemeName = unicode( - translate('OpenLP.ThemeManager', 'Copy of %s', - 'Copy of ')) % unicode( - item.data(QtCore.Qt.UserRole).toString()) - self.fileRenameForm.fileNameEdit.setText(oldThemeName) + oldThemeName = unicode(item.data(QtCore.Qt.UserRole).toString()) + self.fileRenameForm.fileNameEdit.setText( + unicode(translate('OpenLP.ThemeManager', + 'Copy of %s','Copy of ')) % oldThemeName) if self.fileRenameForm.exec_(True): newThemeName = unicode(self.fileRenameForm.fileNameEdit.text()) if self.checkIfThemeExists(newThemeName): From 6980299697f56531ac18b26c7cb75877f2f9c218 Mon Sep 17 00:00:00 2001 From: Andreas Preikschat Date: Wed, 29 Jun 2011 11:23:42 +0200 Subject: [PATCH 041/184] use help function --- openlp/core/ui/servicemanager.py | 2 +- openlp/core/ui/thememanager.py | 59 ++++++++++++++------------------ 2 files changed, 27 insertions(+), 34 deletions(-) diff --git a/openlp/core/ui/servicemanager.py b/openlp/core/ui/servicemanager.py index 8fc796ea4..d35b0cb33 100644 --- a/openlp/core/ui/servicemanager.py +++ b/openlp/core/ui/servicemanager.py @@ -688,7 +688,7 @@ class ServiceManager(QtGui.QWidget): QtGui.QAction, serviceItem[u'service_item'].theme) if themeAction is not None: themeAction.setChecked(True) - action = self.menu.exec_(self.serviceManagerList.mapToGlobal(point)) + self.menu.exec_(self.serviceManagerList.mapToGlobal(point)) def onServiceItemNoteForm(self): item = self.findServiceItem()[0] diff --git a/openlp/core/ui/thememanager.py b/openlp/core/ui/thememanager.py index d84fe7e1f..4582e55c0 100644 --- a/openlp/core/ui/thememanager.py +++ b/openlp/core/ui/thememanager.py @@ -39,7 +39,8 @@ from openlp.core.lib import OpenLPToolbar, get_text_file_string, build_icon, \ check_directory_exists from openlp.core.lib.theme import ThemeXML, BackgroundType, VerticalType, \ BackgroundGradientType -from openlp.core.lib.ui import UiStrings, critical_error_message_box +from openlp.core.lib.ui import UiStrings, critical_error_message_box, \ + context_menu_action, context_menu_separator from openlp.core.theme import Theme from openlp.core.ui import FileRenameForm, ThemeForm from openlp.core.utils import AppLocation, delete_file, file_is_unicode, \ @@ -104,25 +105,29 @@ class ThemeManager(QtGui.QWidget): self.contextMenu) # build the context menu self.menu = QtGui.QMenu() - self.editAction = self.menu.addAction( - translate('OpenLP.ThemeManager', '&Edit Theme')) - self.editAction.setIcon(build_icon(u':/themes/theme_edit.png')) - self.copyAction = self.menu.addAction( - translate('OpenLP.ThemeManager', '&Copy Theme')) - self.copyAction.setIcon(build_icon(u':/themes/theme_edit.png')) - self.renameAction = self.menu.addAction( - translate('OpenLP.ThemeManager', '&Rename Theme')) - self.renameAction.setIcon(build_icon(u':/themes/theme_edit.png')) - self.deleteAction = self.menu.addAction( - translate('OpenLP.ThemeManager', '&Delete Theme')) - self.deleteAction.setIcon(build_icon(u':/general/general_delete.png')) - self.separator = self.menu.addSeparator() - self.globalAction = self.menu.addAction( - translate('OpenLP.ThemeManager', 'Set As &Global Default')) - self.globalAction.setIcon(build_icon(u':/general/general_export.png')) - self.exportAction = self.menu.addAction( - translate('OpenLP.ThemeManager', '&Export Theme')) - self.exportAction.setIcon(build_icon(u':/general/general_export.png')) + self.editAction = context_menu_action( + self.menu, u':/themes/theme_edit.png', + translate('OpenLP.ThemeManager', '&Edit Theme'), self.onEditTheme) + self.copyAction = context_menu_action( + self.menu, u':/themes/theme_edit.png', + translate('OpenLP.ThemeManager', '&Copy Theme'), self.onCopyTheme) + self.renameAction = context_menu_action( + self.menu, u':/themes/theme_edit.png', + translate('OpenLP.ThemeManager', '&Rename Theme'), + self.onRenameTheme) + self.deleteAction = context_menu_action( + self.menu, u':/general/general_delete.png', + translate('OpenLP.ThemeManager', '&Delete Theme'), + self.onDeleteTheme) + context_menu_separator(self.menu) + self.globalAction = context_menu_action( + self.menu, u':/general/general_export.png', + translate('OpenLP.ThemeManager', 'Set As &Global Default'), + self.changeGlobalFromScreen) + self.exportAction = context_menu_action( + self.menu, u':/general/general_export.png', + translate('OpenLP.ThemeManager', '&Export Theme'), + self.onExportTheme) # Signals QtCore.QObject.connect(self.themeListWidget, QtCore.SIGNAL(u'doubleClicked(QModelIndex)'), @@ -198,19 +203,7 @@ class ThemeManager(QtGui.QWidget): self.deleteAction.setVisible(True) self.renameAction.setVisible(True) self.globalAction.setVisible(True) - action = self.menu.exec_(self.themeListWidget.mapToGlobal(point)) - if action == self.editAction: - self.onEditTheme() - if action == self.copyAction: - self.onCopyTheme() - if action == self.renameAction: - self.onRenameTheme() - if action == self.deleteAction: - self.onDeleteTheme() - if action == self.globalAction: - self.changeGlobalFromScreen() - if action == self.exportAction: - self.onExportTheme() + self.menu.exec_(self.themeListWidget.mapToGlobal(point)) def changeGlobalFromTab(self, themeName): """ From c2fb73dde6feec58a8c00ce1ad87702425686162 Mon Sep 17 00:00:00 2001 From: Andreas Preikschat Date: Wed, 29 Jun 2011 16:28:10 +0200 Subject: [PATCH 042/184] do not regenerate all service items when collapsing/expanding all items --- openlp/core/ui/servicemanager.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/openlp/core/ui/servicemanager.py b/openlp/core/ui/servicemanager.py index 8fc796ea4..6424dfb2c 100644 --- a/openlp/core/ui/servicemanager.py +++ b/openlp/core/ui/servicemanager.py @@ -832,7 +832,7 @@ class ServiceManager(QtGui.QWidget): """ for item in self.serviceItems: item[u'expanded'] = False - self.regenerateServiceItems() + self.serviceManagerList.collapseAll() def collapsed(self, item): """ @@ -848,7 +848,7 @@ class ServiceManager(QtGui.QWidget): """ for item in self.serviceItems: item[u'expanded'] = True - self.regenerateServiceItems() + self.serviceManagerList.expandAll() def expanded(self, item): """ @@ -856,7 +856,7 @@ class ServiceManager(QtGui.QWidget): correct state. """ pos = item.data(0, QtCore.Qt.UserRole).toInt()[0] - self.serviceItems[pos -1 ][u'expanded'] = True + self.serviceItems[pos - 1][u'expanded'] = True def onServiceTop(self): """ From 0612a939641b9dfec3067dccbb72bc021db8a773 Mon Sep 17 00:00:00 2001 From: Stevan Pettit Date: Wed, 29 Jun 2011 10:42:14 -0400 Subject: [PATCH 043/184] Changed helpfile check to Windows condition check. Modified build script to create OpenLP.chm --- openlp/core/ui/mainwindow.py | 11 +++++------ scripts/windows-builder.py | 6 +++--- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/openlp/core/ui/mainwindow.py b/openlp/core/ui/mainwindow.py index 4148b40eb..2114e17a9 100644 --- a/openlp/core/ui/mainwindow.py +++ b/openlp/core/ui/mainwindow.py @@ -269,10 +269,9 @@ class Ui_MainWindow(object): self.helpAboutItem = shortcut_action(mainWindow, u'helpAboutItem', [QtGui.QKeySequence(u'Ctrl+F1')], self.onHelpAboutItemClicked, u':/system/system_about.png', category=UiStrings().Help) - self.localHelpFile = os.path.join( - AppLocation.get_directory(AppLocation.AppDir), 'Openlp.chm') - self.haveHelpFile = os.path.isfile(self.localHelpFile) - if self.haveHelpFile: + if sys.platform[:3] == u'win': + self.localHelpFile = os.path.join( + AppLocation.get_directory(AppLocation.AppDir), 'OpenLP.chm') self.helpLocalHelpItem = shortcut_action( mainWindow, u'helpLocalHelpItem', [QtGui.QKeySequence(u'F1')], self.onHelpLocalHelpClicked, u':/system/system_about.png', @@ -321,7 +320,7 @@ class Ui_MainWindow(object): add_actions(self.toolsMenu, (self.toolsOpenDataFolder, None)) add_actions(self.toolsMenu, [self.updateThemeImages]) add_actions(self.helpMenu, (self.helpDocumentationItem, None)) - if self.haveHelpFile: + if sys.platform[:3] == u'win': add_actions(self.helpMenu, (self.helpLocalHelpItem, self.helpOnlineHelpItem, None, self.helpWebSiteItem, self.helpAboutItem)) @@ -443,7 +442,7 @@ class Ui_MainWindow(object): self.helpAboutItem.setText(translate('OpenLP.MainWindow', '&About')) self.helpAboutItem.setStatusTip( translate('OpenLP.MainWindow', 'More information about OpenLP')) - if self.haveHelpFile: + if sys.platform[:3] == u'win': self.helpLocalHelpItem.setText( translate('OpenLP.MainWindow', '&Help')) self.helpOnlineHelpItem.setText( diff --git a/scripts/windows-builder.py b/scripts/windows-builder.py index 854c927c9..4ab31f893 100644 --- a/scripts/windows-builder.py +++ b/scripts/windows-builder.py @@ -242,10 +242,10 @@ def copy_windows_files(): os.path.join(dist_path, u'LICENSE.txt')) copy(os.path.join(winres_path, u'psvince.dll'), os.path.join(dist_path, u'psvince.dll')) - if os.path.isfile(os.path.join(helpfile_path, u'Openlp.chm')): + if os.path.isfile(os.path.join(helpfile_path, u'OpenLP.chm')): print u' Windows help file found' - copy(os.path.join(helpfile_path, u'Openlp.chm'), - os.path.join(dist_path, u'Openlp.chm')) + copy(os.path.join(helpfile_path, u'OpenLP.chm'), + os.path.join(dist_path, u'OpenLP.chm')) else: print u' WARNING ---- Windows help file not found ---- WARNING' From 143e69728173e6596e06b3ea1c75030f98a85863 Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Wed, 29 Jun 2011 17:11:19 +0100 Subject: [PATCH 044/184] Add middle splitter --- openlp/core/ui/mainwindow.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/openlp/core/ui/mainwindow.py b/openlp/core/ui/mainwindow.py index 67839b52f..a34cb7b96 100644 --- a/openlp/core/ui/mainwindow.py +++ b/openlp/core/ui/mainwindow.py @@ -1041,6 +1041,9 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): settings.value(u'live splitter geometry').toByteArray()) self.previewController.splitter.restoreState( settings.value(u'preview splitter geometry').toByteArray()) + self.controlSplitter.restoreState( + settings.value(u'mainwindow splitter geometry').toByteArray()) + settings.endGroup() def saveSettings(self): @@ -1065,6 +1068,8 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): QtCore.QVariant(self.liveController.splitter.saveState())) settings.setValue(u'preview splitter geometry', QtCore.QVariant(self.previewController.splitter.saveState())) + settings.setValue(u'mainwindow splitter geometry', + QtCore.QVariant(self.controlSplitter.saveState())) settings.endGroup() def updateFileMenu(self): From 97a76369bf3b31d50ea87a5890df706985089813 Mon Sep 17 00:00:00 2001 From: Stevan Pettit Date: Wed, 29 Jun 2011 13:30:53 -0400 Subject: [PATCH 045/184] Changed Windows test to os.name --- openlp/core/ui/mainwindow.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/openlp/core/ui/mainwindow.py b/openlp/core/ui/mainwindow.py index 2114e17a9..cde13f18a 100644 --- a/openlp/core/ui/mainwindow.py +++ b/openlp/core/ui/mainwindow.py @@ -269,7 +269,7 @@ class Ui_MainWindow(object): self.helpAboutItem = shortcut_action(mainWindow, u'helpAboutItem', [QtGui.QKeySequence(u'Ctrl+F1')], self.onHelpAboutItemClicked, u':/system/system_about.png', category=UiStrings().Help) - if sys.platform[:3] == u'win': + if os.name == u'nt': self.localHelpFile = os.path.join( AppLocation.get_directory(AppLocation.AppDir), 'OpenLP.chm') self.helpLocalHelpItem = shortcut_action( @@ -320,7 +320,7 @@ class Ui_MainWindow(object): add_actions(self.toolsMenu, (self.toolsOpenDataFolder, None)) add_actions(self.toolsMenu, [self.updateThemeImages]) add_actions(self.helpMenu, (self.helpDocumentationItem, None)) - if sys.platform[:3] == u'win': + if os.name == u'nt': add_actions(self.helpMenu, (self.helpLocalHelpItem, self.helpOnlineHelpItem, None, self.helpWebSiteItem, self.helpAboutItem)) @@ -442,7 +442,7 @@ class Ui_MainWindow(object): self.helpAboutItem.setText(translate('OpenLP.MainWindow', '&About')) self.helpAboutItem.setStatusTip( translate('OpenLP.MainWindow', 'More information about OpenLP')) - if sys.platform[:3] == u'win': + if os.name == u'nt': self.helpLocalHelpItem.setText( translate('OpenLP.MainWindow', '&Help')) self.helpOnlineHelpItem.setText( From 870d0b51e98066e507d346447f7109145313baf9 Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Wed, 29 Jun 2011 22:04:08 +0100 Subject: [PATCH 046/184] Move SongUsage active to toolbar --- openlp/plugins/songusage/songusageplugin.py | 43 ++++++++++++-------- resources/images/openlp-2.qrc | 4 ++ resources/images/song_usage_active.png | Bin 0 -> 757 bytes resources/images/song_usage_inactive.png | Bin 0 -> 716 bytes 4 files changed, 31 insertions(+), 16 deletions(-) create mode 100644 resources/images/song_usage_active.png create mode 100644 resources/images/song_usage_inactive.png diff --git a/openlp/plugins/songusage/songusageplugin.py b/openlp/plugins/songusage/songusageplugin.py index 7304b5196..c600aece3 100644 --- a/openlp/plugins/songusage/songusageplugin.py +++ b/openlp/plugins/songusage/songusageplugin.py @@ -48,6 +48,8 @@ class SongUsagePlugin(Plugin): Plugin.__init__(self, u'SongUsage', plugin_helpers) self.weight = -4 self.icon = build_icon(u':/plugins/plugin_songusage.png') + self.activeIcon = QtGui.QIcon(u':/songusage/song_usage_active.png') + self.inactiveIcon = QtGui.QIcon(u':/songusage/song_usage_inactive.png') self.manager = None self.songusageActive = False @@ -79,22 +81,21 @@ class SongUsagePlugin(Plugin): self.songUsageReport.setStatusTip( translate('SongUsagePlugin', 'Generate a report on song usage.')) # SongUsage activation - self.songUsageStatus = shortcut_action(tools_menu, u'songUsageStatus', - [QtCore.Qt.Key_F4], self.toggleSongUsageState, checked=False) - self.songUsageStatus.setText(translate( - 'SongUsagePlugin', 'Toggle Tracking')) - self.songUsageStatus.setStatusTip(translate('SongUsagePlugin', - 'Toggle the tracking of song usage.')) - #Add Menus together + # Add Menus together self.toolsMenu.addAction(self.songUsageMenu.menuAction()) - self.songUsageMenu.addAction(self.songUsageStatus) - self.songUsageMenu.addSeparator() self.songUsageMenu.addAction(self.songUsageDelete) self.songUsageMenu.addAction(self.songUsageReport) + self.songUsageStatus = QtGui.QToolButton(self.formparent.statusBar) + self.songUsageStatus.setCheckable(True) + self.songUsageStatus.setStatusTip(translate('SongUsagePlugin', + 'Toggle the tracking of song usage.')) + self.songUsageStatus.setObjectName(u'songUsageStatus') + self.formparent.statusBar.insertPermanentWidget(1, self.songUsageStatus) + self.songUsageStatus.hide() # Signals and slots QtCore.QObject.connect(self.songUsageStatus, - QtCore.SIGNAL(u'visibilityChanged(bool)'), - self.songUsageStatus.setChecked) + QtCore.SIGNAL(u'toggled(bool)'), + self.toggleSongUsageState) QtCore.QObject.connect(self.songUsageDelete, QtCore.SIGNAL(u'triggered()'), self.onSongUsageDelete) QtCore.QObject.connect(self.songUsageReport, @@ -116,14 +117,14 @@ class SongUsagePlugin(Plugin): translate('SongUsagePlugin', 'Song Usage')) action_list.add_action(self.songUsageReport, translate('SongUsagePlugin', 'Song Usage')) - action_list.add_action(self.songUsageStatus, - translate('SongUsagePlugin', 'Song Usage')) if self.manager is None: self.manager = Manager(u'songusage', init_schema) self.songUsageDeleteForm = SongUsageDeleteForm(self.manager, self.formparent) self.songUsageDetailForm = SongUsageDetailForm(self, self.formparent) self.songUsageMenu.menuAction().setVisible(True) + self.songUsageStatus.show() + self.songUsageStatus.setIcon(self.activeIcon) def finalise(self): """ @@ -138,22 +139,32 @@ class SongUsagePlugin(Plugin): translate('SongUsagePlugin', 'Song Usage')) action_list.remove_action(self.songUsageReport, translate('SongUsagePlugin', 'Song Usage')) - action_list.remove_action(self.songUsageStatus, - translate('SongUsagePlugin', 'Song Usage')) - #stop any events being processed + self.songUsageStatus.hide() + # stop any events being processed self.SongUsageActive = False def toggleSongUsageState(self): + """ + Manage the state of the audit collection and amend + the UI when necessary, + """ + print "toggle state" self.SongUsageActive = not self.SongUsageActive QtCore.QSettings().setValue(self.settingsSection + u'/active', QtCore.QVariant(self.SongUsageActive)) + if self.SongUsageActive: + self.songUsageStatus.setIcon(self.activeIcon) + else: + self.songUsageStatus.setIcon(self.inactiveIcon) def onReceiveSongUsage(self, item): """ Song Usage for live song from SlideController """ audit = item[0].audit + print audit if self.SongUsageActive and audit: + print "here" song_usage_item = SongUsageItem() song_usage_item.usagedate = datetime.today() song_usage_item.usagetime = datetime.now().time() diff --git a/resources/images/openlp-2.qrc b/resources/images/openlp-2.qrc index fc76ad434..89be90056 100644 --- a/resources/images/openlp-2.qrc +++ b/resources/images/openlp-2.qrc @@ -137,6 +137,10 @@ messagebox_info.png messagebox_warning.png + + song_usage_active.png + song_usage_inactive.png + tools_add.png tools_alert.png diff --git a/resources/images/song_usage_active.png b/resources/images/song_usage_active.png new file mode 100644 index 0000000000000000000000000000000000000000..1221e13103a3066b11a821e82e26f441fac9dc5d GIT binary patch literal 757 zcmV( zu7%a2Roh&aSgW9Is}@mYfvfg@U<>=ej6$bT8Fkc|dGF18_vGV=jf8)=+{HQP z$GzvAzo;tpvhG-?8{w8(j0g+^C@hF!&WD%gh516A4gqpTti(CFe=^6#=*=W z>Goa#^4lvc<`;SO>9zko|KmYzMxW|uHHUzx*dCFO_paQ{T_3%MZ3|)nLM#PU2x`jP znRh(<@O(O$)5{UW25892_>Bu!a~FrsvsKH3p$(u z2Cyq7Qe8MffiYWzY*VZ9wKPkA@)QV^i?I1qz#>)wx(1Y%ju^1K_l;yqk#))1z_8=M zYGsLFr%HGG309W{Zx66Q00p*|Ad^)#%j*=}Rh$+;7`6eB_-yP4w##c2Hk%2`32eIo z1VR&H2Q}Pkg}@IG`PX0@SnynOEd~I>Fd)&p!^XTEc|m4K2}3~RMtW61S+G=@b@znO z2R&#~TMwkOO0pf29grDS+R~tY91mTnmIO7-irkiHjPscRby7WGwSY8%I3NkY0t{#k z)B{t7ojh3Ynh6)-MnB~CVb2X_U+ay;JRFTwYih-#0la%(5K zuC&tJ2@OqP*?`1colW>@>#!uLAC_P%7dDJ`d~7 nbgZ4lVnnUj&SF^5W92nAaxE{#x9n?dXzXmN3N z(4{(baH^BELc6q3a2Dy%#nnkDbna+11at}oF(G2BVxpJ(``*6ar5p;S&3N7^7N z=77Ct%ggT2=qN15ffAC4C?SXdX6Psa3*#U_yVb(?^>zP>dD3=)`8?pN)6?Epvsuu< z0F)~$nM^7`VF>N};BFW8#Rc+~GP#ORb zA044kD4-v-8x3U5>4KnSr*D<&Tc9I*Av7@8st-VGjecSFcB2TU);1aH5LHIxMO}j9 zj|o0eyXq@bVI&{J_9CA+~~f*Lp$Jl-rks%(iO+WLdocnG+e?d_O6U zuC5XWoes|1Z8Sa4_n2SVOOox+O0Bix_=DqlAf3qx7Il;Va6cC}tJ zwYQ>tSEd2a{yWY@RDyubI5Yoqoc{m~r92WwE;k{~O literal 0 HcmV?d00001 From 0b41274f8e7e37e078d19b81aaeb731e6ab58360 Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Thu, 30 Jun 2011 19:59:51 +0100 Subject: [PATCH 047/184] Fix up button --- openlp/plugins/songusage/songusageplugin.py | 54 ++++++++++++--------- 1 file changed, 30 insertions(+), 24 deletions(-) diff --git a/openlp/plugins/songusage/songusageplugin.py b/openlp/plugins/songusage/songusageplugin.py index c600aece3..ff7a691f7 100644 --- a/openlp/plugins/songusage/songusageplugin.py +++ b/openlp/plugins/songusage/songusageplugin.py @@ -51,7 +51,7 @@ class SongUsagePlugin(Plugin): self.activeIcon = QtGui.QIcon(u':/songusage/song_usage_active.png') self.inactiveIcon = QtGui.QIcon(u':/songusage/song_usage_inactive.png') self.manager = None - self.songusageActive = False + self.songUsageActive = False def addToolsMenuItem(self, tools_menu): """ @@ -85,15 +85,17 @@ class SongUsagePlugin(Plugin): self.toolsMenu.addAction(self.songUsageMenu.menuAction()) self.songUsageMenu.addAction(self.songUsageDelete) self.songUsageMenu.addAction(self.songUsageReport) - self.songUsageStatus = QtGui.QToolButton(self.formparent.statusBar) - self.songUsageStatus.setCheckable(True) - self.songUsageStatus.setStatusTip(translate('SongUsagePlugin', - 'Toggle the tracking of song usage.')) - self.songUsageStatus.setObjectName(u'songUsageStatus') - self.formparent.statusBar.insertPermanentWidget(1, self.songUsageStatus) - self.songUsageStatus.hide() + self.songUsageActiveButton = QtGui.QToolButton( + self.formparent.statusBar) + self.songUsageActiveButton.setCheckable(True) + self.songUsageActiveButton.setStatusTip(translate('SongUsagePlugin', + 'Toggle the tracking of song usage.')) + self.songUsageActiveButton.setObjectName(u'songUsageActiveButton') + self.formparent.statusBar.insertPermanentWidget(1, + self.songUsageActiveButton) + self.songUsageActiveButton.hide() # Signals and slots - QtCore.QObject.connect(self.songUsageStatus, + QtCore.QObject.connect(self.songUsageActiveButton, QtCore.SIGNAL(u'toggled(bool)'), self.toggleSongUsageState) QtCore.QObject.connect(self.songUsageDelete, @@ -108,10 +110,15 @@ class SongUsagePlugin(Plugin): QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'slidecontroller_live_started'), self.onReceiveSongUsage) - self.SongUsageActive = QtCore.QSettings().value( + self.songUsageActive = QtCore.QSettings().value( self.settingsSection + u'/active', QtCore.QVariant(False)).toBool() - self.songUsageStatus.setChecked(self.SongUsageActive) + # Set the correct state and icon turn of signals as the state + # will get messed up + self.songUsageActiveButton.blockSignals(True) + self.songUsageActiveButton.setChecked(self.songUsageActive) + self.setButtonState() + self.songUsageActiveButton.blockSignals(False) action_list = ActionList.get_instance() action_list.add_action(self.songUsageDelete, translate('SongUsagePlugin', 'Song Usage')) @@ -123,8 +130,7 @@ class SongUsagePlugin(Plugin): self.formparent) self.songUsageDetailForm = SongUsageDetailForm(self, self.formparent) self.songUsageMenu.menuAction().setVisible(True) - self.songUsageStatus.show() - self.songUsageStatus.setIcon(self.activeIcon) + self.songUsageActiveButton.show() def finalise(self): """ @@ -139,32 +145,32 @@ class SongUsagePlugin(Plugin): translate('SongUsagePlugin', 'Song Usage')) action_list.remove_action(self.songUsageReport, translate('SongUsagePlugin', 'Song Usage')) - self.songUsageStatus.hide() + self.songUsageActiveButton.hide() # stop any events being processed - self.SongUsageActive = False + self.songUsageActive = False def toggleSongUsageState(self): """ Manage the state of the audit collection and amend the UI when necessary, """ - print "toggle state" - self.SongUsageActive = not self.SongUsageActive + self.songUsageActive = not self.songUsageActive QtCore.QSettings().setValue(self.settingsSection + u'/active', - QtCore.QVariant(self.SongUsageActive)) - if self.SongUsageActive: - self.songUsageStatus.setIcon(self.activeIcon) + QtCore.QVariant(self.songUsageActive)) + self.setButtonState() + + def setButtonState(self): + if self.songUsageActive: + self.songUsageActiveButton.setIcon(self.activeIcon) else: - self.songUsageStatus.setIcon(self.inactiveIcon) + self.songUsageActiveButton.setIcon(self.inactiveIcon) def onReceiveSongUsage(self, item): """ Song Usage for live song from SlideController """ audit = item[0].audit - print audit - if self.SongUsageActive and audit: - print "here" + if self.songUsageActive and audit: song_usage_item = SongUsageItem() song_usage_item.usagedate = datetime.today() song_usage_item.usagetime = datetime.now().time() From bddf91ddcb748d6c6929e95cbad80d414cab9da0 Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Fri, 1 Jul 2011 17:55:07 +0100 Subject: [PATCH 048/184] Add ability to clone songs Amend framework for plugins to add non toolbar context items Fixes: https://launchpad.net/bugs/763583 --- openlp/core/lib/mediamanageritem.py | 8 ++++++++ openlp/plugins/songs/lib/mediaitem.py | 27 ++++++++++++++++++++++++++- 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/openlp/core/lib/mediamanageritem.py b/openlp/core/lib/mediamanageritem.py index a79355c88..17862326e 100644 --- a/openlp/core/lib/mediamanageritem.py +++ b/openlp/core/lib/mediamanageritem.py @@ -288,6 +288,7 @@ class MediaManagerItem(QtGui.QWidget): self.listView, u':/general/general_add.png', translate('OpenLP.MediaManagerItem', '&Add to selected Service Item'), self.onAddEditClick) + self.addCutomContextActions() # Create the context menu and add all actions from the listView. self.menu = QtGui.QMenu() self.menu.addActions(self.listView.actions()) @@ -301,6 +302,13 @@ class MediaManagerItem(QtGui.QWidget): QtCore.SIGNAL('customContextMenuRequested(QPoint)'), self.contextMenu) + def addCutomContextActions(self): + """ + Implement this method in your descendent media manager item to + add any context menu items. This method is called automatically. + """ + pass + def initialise(self): """ Implement this method in your descendent media manager item to diff --git a/openlp/plugins/songs/lib/mediaitem.py b/openlp/plugins/songs/lib/mediaitem.py index e2efbe3df..9082d8a1f 100644 --- a/openlp/plugins/songs/lib/mediaitem.py +++ b/openlp/plugins/songs/lib/mediaitem.py @@ -35,7 +35,8 @@ from sqlalchemy.sql import or_ from openlp.core.lib import MediaManagerItem, Receiver, ItemCapabilities, \ translate, check_item_selected, PluginStatus from openlp.core.lib.searchedit import SearchEdit -from openlp.core.lib.ui import UiStrings +from openlp.core.lib.ui import UiStrings, context_menu_action, \ + context_menu_separator from openlp.plugins.songs.forms import EditSongForm, SongMaintenanceForm, \ SongImportForm, SongExportForm from openlp.plugins.songs.lib import OpenLyrics, SongXML, VerseType, \ @@ -128,6 +129,13 @@ class SongMediaItem(MediaManagerItem): QtCore.SIGNAL(u'searchTypeChanged(int)'), self.onSearchTextButtonClick) + def addCutomContextActions(self): + context_menu_separator(self.listView) + context_menu_action( + self.listView, u':/general/general_add.png', + translate('OpenLP.MediaManagerItem', + '&Clone.'), self.onCloneClick) + def onFocus(self): self.searchTextEdit.setFocus() @@ -366,6 +374,23 @@ class SongMediaItem(MediaManagerItem): self.plugin.manager.delete_object(Song, item_id) self.onSearchTextButtonClick() + def onCloneClick(self): + """ + Clone a Song + """ + log.debug(u'onCloneClick') + if check_item_selected(self.listView, UiStrings().SelectEdit): + self.editItem = self.listView.currentItem() + item_id = (self.editItem.data(QtCore.Qt.UserRole)).toInt()[0] + old_song = self.plugin.manager.get_object(Song, item_id) + song_xml = self.openLyrics.song_to_xml(old_song) + new_song_id = self.openLyrics.xml_to_song(song_xml) + new_song = self.plugin.manager.get_object(Song, new_song_id) + new_song.title = u'%s <%s>' % (new_song.title, + translate('SongsPlugin.MediaItem', 'copy')) + self.plugin.manager.save_object(new_song) + self.onSongListLoad() + def generateSlideData(self, service_item, item=None, xmlVersion=False): log.debug(u'generateSlideData (%s:%s)' % (service_item, item)) item_id = self._getIdOfItemToGenerate(item, self.remoteSong) From 219218161b11f86ec6fbe709fd77b27d5bff8608 Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Fri, 1 Jul 2011 17:59:56 +0100 Subject: [PATCH 049/184] 6am spelling fix --- openlp/core/lib/mediamanageritem.py | 4 ++-- openlp/plugins/songs/lib/mediaitem.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/openlp/core/lib/mediamanageritem.py b/openlp/core/lib/mediamanageritem.py index 17862326e..0cc25717c 100644 --- a/openlp/core/lib/mediamanageritem.py +++ b/openlp/core/lib/mediamanageritem.py @@ -288,7 +288,7 @@ class MediaManagerItem(QtGui.QWidget): self.listView, u':/general/general_add.png', translate('OpenLP.MediaManagerItem', '&Add to selected Service Item'), self.onAddEditClick) - self.addCutomContextActions() + self.addCustomContextActions() # Create the context menu and add all actions from the listView. self.menu = QtGui.QMenu() self.menu.addActions(self.listView.actions()) @@ -302,7 +302,7 @@ class MediaManagerItem(QtGui.QWidget): QtCore.SIGNAL('customContextMenuRequested(QPoint)'), self.contextMenu) - def addCutomContextActions(self): + def addCustomContextActions(self): """ Implement this method in your descendent media manager item to add any context menu items. This method is called automatically. diff --git a/openlp/plugins/songs/lib/mediaitem.py b/openlp/plugins/songs/lib/mediaitem.py index 9082d8a1f..743013934 100644 --- a/openlp/plugins/songs/lib/mediaitem.py +++ b/openlp/plugins/songs/lib/mediaitem.py @@ -129,7 +129,7 @@ class SongMediaItem(MediaManagerItem): QtCore.SIGNAL(u'searchTypeChanged(int)'), self.onSearchTextButtonClick) - def addCutomContextActions(self): + def addCustomContextActions(self): context_menu_separator(self.listView) context_menu_action( self.listView, u':/general/general_add.png', From bc808ade93762cf5d3a1a4501e0f3378a1cee4c3 Mon Sep 17 00:00:00 2001 From: Benny Date: Sat, 2 Jul 2011 00:45:27 +0200 Subject: [PATCH 050/184] EasyWorshipSongImport: use tag from previous slide for slides without tag, fix regex for notes --- openlp/plugins/songs/lib/ewimport.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/openlp/plugins/songs/lib/ewimport.py b/openlp/plugins/songs/lib/ewimport.py index c207a07d2..95533ba94 100644 --- a/openlp/plugins/songs/lib/ewimport.py +++ b/openlp/plugins/songs/lib/ewimport.py @@ -261,6 +261,7 @@ class EasyWorshipSongImport(SongImport): # Format the lyrics words = strip_rtf(words, self.encoding) # TODO: convert rtf instead of stripping? p = re.compile(r'\n *?\n[\n ]*') # at least two newlines, with zero or more space characters between them + verse_type = VerseType.Tags[VerseType.Verse] # TODO!!!: use previous verse type.... for verse in p.split(words): #for verse in words.split(u'\n\n'): # ew tags: verse, chorus, pre-chorus, bridge, tag, intro, ending, slide @@ -268,13 +269,11 @@ class EasyWorshipSongImport(SongImport): if len(verse) == 0: continue verse_split = verse.split(u'\n', 1) - verse_type = VerseType.Tags[VerseType.Verse] first_line_is_tag = False for type in VerseType.Names+['tag', 'slide']: # doesnt cover tag, slide type = type.lower() ew_tag = verse_split[0].strip().lower() if ew_tag.startswith(type): - #print ew_tag verse_type = type[0] if type == 'tag' or type == 'slide': verse_type = VerseType.Tags[VerseType.Other] @@ -286,7 +285,7 @@ class EasyWorshipSongImport(SongImport): number = m.group() verse_type +=number - p = re.compile(r'\(.*\)') + p = re.compile(r'\(.*?\)') m = re.search(p, ew_tag) if m: self.comments += ew_tag+'\n' From 6a259e0489470ebfa1f9e4c46a8ea2e80238e266 Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Sat, 2 Jul 2011 06:51:03 +0100 Subject: [PATCH 051/184] Correct build icon --- openlp/plugins/bibles/lib/mediaitem.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/openlp/plugins/bibles/lib/mediaitem.py b/openlp/plugins/bibles/lib/mediaitem.py index cb8273327..5ad8af73d 100644 --- a/openlp/plugins/bibles/lib/mediaitem.py +++ b/openlp/plugins/bibles/lib/mediaitem.py @@ -34,7 +34,8 @@ from openlp.core.lib import MediaManagerItem, Receiver, ItemCapabilities, \ translate from openlp.core.lib.searchedit import SearchEdit from openlp.core.lib.ui import UiStrings, add_widget_completer, \ - media_item_combo_box, critical_error_message_box, find_and_set_in_combo_box + media_item_combo_box, critical_error_message_box, \ + find_and_set_in_combo_box, build_icon from openlp.plugins.bibles.forms import BibleImportForm from openlp.plugins.bibles.lib import LayoutStyle, DisplayStyle, \ VerseReferenceList, get_reference_match @@ -57,8 +58,8 @@ class BibleMediaItem(MediaManagerItem): def __init__(self, parent, plugin, icon): self.IconPath = u'songs/song' - self.lockIcon = QtGui.QIcon(u':/bibles/bibles_search_lock.png') - self.unlockIcon = QtGui.QIcon(u':/bibles/bibles_search_unlock.png') + self.lockIcon = build_icon(u':/bibles/bibles_search_lock.png') + self.unlockIcon = build_icon(u':/bibles/bibles_search_unlock.png') MediaManagerItem.__init__(self, parent, plugin, icon) # Place to store the search results for both bibles. self.settings = self.plugin.settings_tab From 091cdbbc24ee25684116b1b0ec7002edbf2ef8f6 Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Sat, 2 Jul 2011 07:48:17 +0100 Subject: [PATCH 052/184] Slow down slidecontroller events to allow buffers to clear. Line wrap incorrect and fix object name Fixes: https://launchpad.net/bugs/752374 --- openlp/core/ui/servicemanager.py | 8 ++++---- openlp/core/ui/slidecontroller.py | 3 +++ openlp/plugins/bibles/lib/mediaitem.py | 3 ++- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/openlp/core/ui/servicemanager.py b/openlp/core/ui/servicemanager.py index 6424dfb2c..cccbed399 100644 --- a/openlp/core/ui/servicemanager.py +++ b/openlp/core/ui/servicemanager.py @@ -48,18 +48,18 @@ class ServiceManagerList(QtGui.QTreeWidget): """ Set up key bindings and mouse behaviour for the service list """ - def __init__(self, mainwindow, parent=None, name=None): + def __init__(self, serviceManager, parent=None, name=None): QtGui.QTreeWidget.__init__(self, parent) - self.mainwindow = mainwindow + self.serviceManager = serviceManager def keyPressEvent(self, event): if isinstance(event, QtGui.QKeyEvent): # here accept the event and do something if event.key() == QtCore.Qt.Key_Up: - self.mainwindow.onMoveSelectionUp() + self.serviceManager.onMoveSelectionUp() event.accept() elif event.key() == QtCore.Qt.Key_Down: - self.mainwindow.onMoveSelectionDown() + self.serviceManager.onMoveSelectionDown() event.accept() event.ignore() else: diff --git a/openlp/core/ui/slidecontroller.py b/openlp/core/ui/slidecontroller.py index 8e2c199a1..e86e2e760 100644 --- a/openlp/core/ui/slidecontroller.py +++ b/openlp/core/ui/slidecontroller.py @@ -27,6 +27,7 @@ import logging import os +import time from PyQt4 import QtCore, QtGui from PyQt4.phonon import Phonon @@ -412,9 +413,11 @@ class SlideController(QtGui.QWidget): self.display.videoStop() def servicePrevious(self): + time.sleep(0.1) Receiver.send_message('servicemanager_previous_item') def serviceNext(self): + time.sleep(0.1) Receiver.send_message('servicemanager_next_item') def screenSizeChanged(self): diff --git a/openlp/plugins/bibles/lib/mediaitem.py b/openlp/plugins/bibles/lib/mediaitem.py index 5ad8af73d..0734df818 100644 --- a/openlp/plugins/bibles/lib/mediaitem.py +++ b/openlp/plugins/bibles/lib/mediaitem.py @@ -984,7 +984,8 @@ class BibleMediaItem(MediaManagerItem): Search for some Bible verses (by reference). """ bible = unicode(self.quickVersionComboBox.currentText()) - search_results = self.plugin.manager.get_verses(bible, string, False, False) + search_results = self.plugin.manager.get_verses(bible, string, False, + False) if search_results: versetext = u' '.join([verse.text for verse in search_results]) return [[string, versetext]] From dfa1bad08c1355dc2c97ee90906e61f9d70e96f3 Mon Sep 17 00:00:00 2001 From: Martin Zibricky Date: Sun, 3 Jul 2011 00:01:58 +0200 Subject: [PATCH 053/184] Add testing directory From 222d4c228cbe9ef97776f4a82eefd391d3f994c0 Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Sun, 3 Jul 2011 06:43:32 +0100 Subject: [PATCH 054/184] Method fix --- openlp/plugins/songusage/songusageplugin.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openlp/plugins/songusage/songusageplugin.py b/openlp/plugins/songusage/songusageplugin.py index ff7a691f7..c40935430 100644 --- a/openlp/plugins/songusage/songusageplugin.py +++ b/openlp/plugins/songusage/songusageplugin.py @@ -48,8 +48,8 @@ class SongUsagePlugin(Plugin): Plugin.__init__(self, u'SongUsage', plugin_helpers) self.weight = -4 self.icon = build_icon(u':/plugins/plugin_songusage.png') - self.activeIcon = QtGui.QIcon(u':/songusage/song_usage_active.png') - self.inactiveIcon = QtGui.QIcon(u':/songusage/song_usage_inactive.png') + self.activeIcon = build_icon(u':/songusage/song_usage_active.png') + self.inactiveIcon = build_icon(u':/songusage/song_usage_inactive.png') self.manager = None self.songUsageActive = False From 2a73f1b1889d0a7c24a17f607f7945d69a1516a6 Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Sun, 3 Jul 2011 09:13:48 +0100 Subject: [PATCH 055/184] Prevent Images and Media backgrounds being added when No service Item is present in the live controller. Fixes: https://launchpad.net/bugs/795980 --- openlp/core/ui/maindisplay.py | 7 ++++++- openlp/plugins/images/lib/mediaitem.py | 9 +++++++-- openlp/plugins/media/lib/mediaitem.py | 8 ++++++-- 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/openlp/core/ui/maindisplay.py b/openlp/core/ui/maindisplay.py index b661b1e49..72a998efe 100644 --- a/openlp/core/ui/maindisplay.py +++ b/openlp/core/ui/maindisplay.py @@ -233,10 +233,12 @@ class MainDisplay(QtGui.QGraphicsView): API for replacement backgrounds so Images are added directly to cache """ self.image_manager.add_image(name, path) - self.image(name) if hasattr(self, u'serviceItem'): self.override[u'image'] = name self.override[u'theme'] = self.serviceItem.themedata.theme_name + self.image(name) + return True + return False def image(self, name): """ @@ -349,6 +351,9 @@ class MainDisplay(QtGui.QGraphicsView): """ Loads and starts a video to run with the option of sound """ + # We request a background video but have no service Item + if isBackground and not hasattr(self, u'serviceItem'): + return None if not self.mediaObject: self.createMediaObject() log.debug(u'video') diff --git a/openlp/plugins/images/lib/mediaitem.py b/openlp/plugins/images/lib/mediaitem.py index 481b55c09..3c4489bbc 100644 --- a/openlp/plugins/images/lib/mediaitem.py +++ b/openlp/plugins/images/lib/mediaitem.py @@ -208,8 +208,13 @@ class ImageMediaItem(MediaManagerItem): filename = unicode(bitem.data(QtCore.Qt.UserRole).toString()) if os.path.exists(filename): (path, name) = os.path.split(filename) - self.plugin.liveController.display.directImage(name, filename) - self.resetAction.setVisible(True) + if self.plugin.liveController.display.directImage(name, + filename): + self.resetAction.setVisible(True) + else: + critical_error_message_box(UiStrings().LiveBGError, + translate('ImagePlugin.MediaItem', + 'There was no display item to amend.')) else: critical_error_message_box(UiStrings().LiveBGError, unicode(translate('ImagePlugin.MediaItem', diff --git a/openlp/plugins/media/lib/mediaitem.py b/openlp/plugins/media/lib/mediaitem.py index 1e39a0426..77f91a529 100644 --- a/openlp/plugins/media/lib/mediaitem.py +++ b/openlp/plugins/media/lib/mediaitem.py @@ -114,8 +114,12 @@ class MediaMediaItem(MediaManagerItem): filename = unicode(item.data(QtCore.Qt.UserRole).toString()) if os.path.exists(filename): (path, name) = os.path.split(filename) - self.plugin.liveController.display.video(filename, 0, True) - self.resetAction.setVisible(True) + if self.plugin.liveController.display.video(filename, 0, True): + self.resetAction.setVisible(True) + else: + critical_error_message_box(UiStrings().LiveBGError, + translate('MediaPlugin.MediaItem', + 'There was no display item to amend.')) else: critical_error_message_box(UiStrings().LiveBGError, unicode(translate('MediaPlugin.MediaItem', From 1c454b606fc76f598d6ea9371b17a613322032aa Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Sun, 3 Jul 2011 13:43:31 +0100 Subject: [PATCH 056/184] Fix fullstop and add icon --- openlp/plugins/songs/lib/mediaitem.py | 4 ++-- resources/images/general_clone.png | Bin 0 -> 527 bytes resources/images/openlp-2.qrc | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) create mode 100644 resources/images/general_clone.png diff --git a/openlp/plugins/songs/lib/mediaitem.py b/openlp/plugins/songs/lib/mediaitem.py index 743013934..e9335a684 100644 --- a/openlp/plugins/songs/lib/mediaitem.py +++ b/openlp/plugins/songs/lib/mediaitem.py @@ -132,9 +132,9 @@ class SongMediaItem(MediaManagerItem): def addCustomContextActions(self): context_menu_separator(self.listView) context_menu_action( - self.listView, u':/general/general_add.png', + self.listView, u':/general/general_clone.png', translate('OpenLP.MediaManagerItem', - '&Clone.'), self.onCloneClick) + '&Clone'), self.onCloneClick) def onFocus(self): self.searchTextEdit.setFocus() diff --git a/resources/images/general_clone.png b/resources/images/general_clone.png new file mode 100644 index 0000000000000000000000000000000000000000..db1d9fbafc2f08e1beef834d7128ada961f53ea5 GIT binary patch literal 527 zcmV+q0`UEbP)pya@#$h3+(` zJq0}ybtIrch?)+XKnZ~=3M-;iiImO76nn{Jmx7V3(Rjz7|M|TF`~mj(-RipgYnX_D zz0V}+xPzIZB8Vy?k_CVWs>;^pW(%kR$nOAYGv0@d1FGY_B~9f0PSEdWW-J={wZHRw>t ztrk}SD+S@(0tJ-`)b6eQNZ~4H{{zI`Nz;^Rn)>t0b3Xzc5m!|SC5D~C;(otRqp`vN z^Yi=btLsaE9pC^s1P=G(_+m1d_;fn;G);XzpZj95@a1ypgeneral_save.png general_email.png general_revert.png + general_clone.png slide_close.png From 4d82e55ca0c34ba3f0c1c9ed2ac9d7f4824dfe4a Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Sun, 3 Jul 2011 18:45:48 +0100 Subject: [PATCH 057/184] Correct code --- openlp/plugins/songusage/songusageplugin.py | 30 +++++++++++++++++---- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/openlp/plugins/songusage/songusageplugin.py b/openlp/plugins/songusage/songusageplugin.py index c40935430..3b5d11b63 100644 --- a/openlp/plugins/songusage/songusageplugin.py +++ b/openlp/plugins/songusage/songusageplugin.py @@ -81,8 +81,16 @@ class SongUsagePlugin(Plugin): self.songUsageReport.setStatusTip( translate('SongUsagePlugin', 'Generate a report on song usage.')) # SongUsage activation + self.songUsageStatus = shortcut_action(tools_menu, u'songUsageStatus', + [QtCore.Qt.Key_F4], self.toggleSongUsageState, checked=False) + self.songUsageStatus.setText(translate( + 'SongUsagePlugin', 'Toggle Tracking')) + self.songUsageStatus.setStatusTip(translate('SongUsagePlugin', + 'Toggle the tracking of song usage.')) # Add Menus together self.toolsMenu.addAction(self.songUsageMenu.menuAction()) + self.songUsageMenu.addAction(self.songUsageStatus) + self.songUsageMenu.addSeparator() self.songUsageMenu.addAction(self.songUsageDelete) self.songUsageMenu.addAction(self.songUsageReport) self.songUsageActiveButton = QtGui.QToolButton( @@ -95,6 +103,9 @@ class SongUsagePlugin(Plugin): self.songUsageActiveButton) self.songUsageActiveButton.hide() # Signals and slots + QtCore.QObject.connect(self.songUsageStatus, + QtCore.SIGNAL(u'visibilityChanged(bool)'), + self.songUsageStatus.setChecked) QtCore.QObject.connect(self.songUsageActiveButton, QtCore.SIGNAL(u'toggled(bool)'), self.toggleSongUsageState) @@ -113,12 +124,8 @@ class SongUsagePlugin(Plugin): self.songUsageActive = QtCore.QSettings().value( self.settingsSection + u'/active', QtCore.QVariant(False)).toBool() - # Set the correct state and icon turn of signals as the state - # will get messed up - self.songUsageActiveButton.blockSignals(True) - self.songUsageActiveButton.setChecked(self.songUsageActive) + # Set the button and checkbox state self.setButtonState() - self.songUsageActiveButton.blockSignals(False) action_list = ActionList.get_instance() action_list.add_action(self.songUsageDelete, translate('SongUsagePlugin', 'Song Usage')) @@ -160,10 +167,23 @@ class SongUsagePlugin(Plugin): self.setButtonState() def setButtonState(self): + """ + Keep buttons inline. Turn of signals to stop dead loop but we need the + button and check box set correctly. + """ + self.songUsageActiveButton.blockSignals(True) + self.songUsageStatus.blockSignals(True) if self.songUsageActive: self.songUsageActiveButton.setIcon(self.activeIcon) + self.songUsageStatus.setChecked(True) + self.songUsageActiveButton.setChecked(True) else: self.songUsageActiveButton.setIcon(self.inactiveIcon) + self.songUsageStatus.setChecked(False) + self.songUsageActiveButton.setChecked(False) + self.songUsageActiveButton.blockSignals(False) + self.songUsageStatus.blockSignals(False) + def onReceiveSongUsage(self, item): """ From b2b8dd1d4d48e5e8dd3ee7464132f5912034adfe Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Sun, 3 Jul 2011 19:33:04 +0100 Subject: [PATCH 058/184] Extra fix --- openlp/plugins/songusage/songusageplugin.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/openlp/plugins/songusage/songusageplugin.py b/openlp/plugins/songusage/songusageplugin.py index 3b5d11b63..ad79870b8 100644 --- a/openlp/plugins/songusage/songusageplugin.py +++ b/openlp/plugins/songusage/songusageplugin.py @@ -127,6 +127,8 @@ class SongUsagePlugin(Plugin): # Set the button and checkbox state self.setButtonState() action_list = ActionList.get_instance() + action_list.add_action(self.songUsageStatus, + translate('SongUsagePlugin', 'Song Usage')) action_list.add_action(self.songUsageDelete, translate('SongUsagePlugin', 'Song Usage')) action_list.add_action(self.songUsageReport, @@ -148,6 +150,8 @@ class SongUsagePlugin(Plugin): Plugin.finalise(self) self.songUsageMenu.menuAction().setVisible(False) action_list = ActionList.get_instance() + action_list.remove_action(self.songUsageStatus, + translate('SongUsagePlugin', 'Song Usage')) action_list.remove_action(self.songUsageDelete, translate('SongUsagePlugin', 'Song Usage')) action_list.remove_action(self.songUsageReport, From ffab60d29e9cf2c8ec969a599cfaf3d5d7a5425f Mon Sep 17 00:00:00 2001 From: Martin Zibricky Date: Mon, 4 Jul 2011 11:32:13 +0200 Subject: [PATCH 059/184] Updat windows icon to contain higher resolution images (64x64, 128x128) --- resources/images/OpenLP.ico | Bin 15086 -> 99678 bytes resources/images/README.txt | 6 ++++++ 2 files changed, 6 insertions(+) create mode 100644 resources/images/README.txt diff --git a/resources/images/OpenLP.ico b/resources/images/OpenLP.ico index b275542c3809b3c3fb91facd13bc8ce75df076e0..c4aa7c41e76f50f6000a58b400c427e72cb8343e 100644 GIT binary patch literal 99678 zcmeEv1$b4*_Wh-_r7qMcP~0s-fVdJv;|hc%kOYVjLPF34cZcBa(BkeCr?|V7mKKT@ z3Z-z?f9*NX4h?L_wf3;|>mD2W;ctDuZ$k5$ z2d53aGcD3q8_~E1`uJ8sN4IiFv@3}ytD;(%W$_1X>N$nJ=sUJepWN#4g-gH>w|L#a z)m@vhbzFb29f-I32vHUvBdE%UXi)J(gxggal=nM2MFv&c(>WO1G6S`JBQkMz$qd{) zychS*oP_rMceru%5T)IOaD0p-0mp?o?b`+0}9l?X+hwq zs@>bO6}Q>$YdbdJo2_ebVdHX~TC*5uH?G2^9b53-!F{;0Z#S+U+z-7?Ltdm z=W&OoO&IoM|5w0?6TpRwz&BTcTX*s3@GjxU+dV&P*GKtv%zhu6sPb{&F>N{{j2&Al8o`jEj_E zcHb^=E>aNopT33$HA<~pnidv)VR$QC7}E|{7mddw_TQ6B)Z=&G;m6Y_u(E$Tt{>Wm zC*NJg=+x%O45^D`KNmzeSs==z_R!_o$<-fhS@lFadQ`)iv%r;aafAK0V^}7RESRJ| z_x=9e7?}`&E`d&H*U%2}UbWEF)k;ff;Nm6Y;L3`n7jWbV9)7hIM~1e=?g5E-eCYzm z(GNJkVL1i`+o7kwEjrY%i8k&v5M^Hp&E2f-WW|KODW8w=b}M{hQ0vDhdPQjWc5Q-o zfuH^Edu$!v89AYK(BH2ny82W{s#`_0v@4@U*_KCwuX9cLtnr%NCcyXZp52de?mQly zII3;!m4GRs))*CNg}(KwqLX`hEzzz7;_b^K(YsD7<8yiM&0OmgzPw@eg)M3IpDb?a zj2TVpU`&uT1~jOKt{xShbZKDoLrX6^ncBbkniAi*dQPNE^n_TSK_jC)hxPEcZ__iZ zu8pNzK*9VUeC%Q}-G0|(y2!t5=9OK*eC2s#Hh(sLFYmcnNdJtMrQ4ZO{JSeJv0v&X zhUcGqz0x%%tWx(T4Sg~iIkZXjw&|YYY27Qyt5*B80FS^PEyAtKyr#_CKlha9KV2|0 z#COn)l(75M`!7QpTWI|nR7Ve=D(K=-5$P`FknB(zt?WuZ?iud=s9TdpYuOd0p8uLZ z{hQZv+C+?)+|2pmtmY1w5MqtdftK13+R%RWtD=W@C3N*q>=bN&~lmdxsA_0_}x% z`Lc#@z5%}f9>08j33q8nwvOqI0epV8M_F{`^E+@YY3o=Tt!+yn)}|PmS$>Mpsvp6h zHoacicTvCMM@Vk$KJJgSAHC7oV?Py~;J?duU>FZ*ncVa~Bsj zug21T85kJuip1JQ(W+K4w6rO%o*!22WB6D40QJkghq|TS)*4nThNMPrzuAUp7n>4a zb&L3Edy2cZExjR*jOv7MR?WxHXHVhr*O&3+>bI&5hTYG-b6vcB;wWZxX@f+^vWTV* z!mEFbz{($>LHYOLRr(#ceD(+`{h8B4+F);&U~Fpbgq1P1vA9`H z%!{;+UOm2i_9i#B&$Sj;*^*QddU9t{HU#LF0c@vMWT*0NCTd`P5-|1BP$K8ZVAJHJ``1y0P( z!Ol@#u`0VI7Nmw?Qmhw-1lrIB+h9^s2$m1-io?qmsP*(F`$B9y9`mbqZo}ZDXf$=G z2D?uSq1xLft%aBUn*3wo_<}j-aO{}AUY?>{XSwE_KM!2w+W9rxBV&+bK>A$9fvj7P zsgGay`$t#4#$B#yr`9jWrpY5Qvs+vAiE4!2&HXTMKsL_r_)_^BKb}8_G2PNNznT@m z1*VkI2CKpaT^@e52fz9JZ@*P*kIYB$gK$Hxo92G!c)WcFxceh;?W0FNH4 z_uM>rT=@oaeR#kGrYiayBU`IE3``bcaU+aGI&W?|WYPWYmCI_6}z#njGiFfKg~<2oc@ zKILCGbu137T#8G3_}%O)T)(dUc;@sYK3`UZHxBnpcyKz)AE$U7>(U7OGwWk#nin=D zx?xqE0~R;0jkz3y(?V)sX0#I)whzbJ0qwDC>M)#Iy%5(Ae1%)|V?+n{&!5H5oGYRu z)gK&_yB5ynH3xUkoW|X=r`6cVY!>`DHPF{O!MARivwfQVa=u>_E)8pg%Q+diG%*{O zXAQ=;izegR`o(Gt{><-IeSe32EaUywZN2|RAJ?zv+Ju{I$5&s>#F}wKurg;5HqDrz z#>rLscxShNiErssB{XnDwf733sfS(Qu(&2QpX}fNSo{h7Yg}@?-Q%ym(w~3$FzD|o`EmA~>VpRd_uvNo&Er!CVr7~?Ciz$57;wR|&M`Q( za=xwy(FJ9dIsYAf;hEi%F`{)CH2RwI`q`$Yv? z@cEB*`KA9);_muII6FE6yE7VKOR5hxq}Io(w)L@VXgY2k*!7GZR^yD%`02tqEa=%5 zIfiecT+C$cVjgt?vn8@)L+|s^ugLTHDt2qrCg9K^XdHuv9oE!3z<$4c1-Ex^ z#=)`KSdvm7YqDc;Y2z|A=MDWo;J#u}?==hiO4 z*eG`l4RyePAUpK(uZ?aEY>??|g?646NOZ4;IOob}ZeIZrwaaP#7A26?JZQM;^?d(~ zNs68J6W5rpbJ}aiy7}Wk7e5^88;ctomZ<%oCSyR>VzGmifA6%RY9BQ!)DA;}YNH?b zV?7#Jp|ej7q}Q#A6t~J~)U!He0!$5 zKTdS>!}Z0JbUS>Gwn*%-%mF_C3D>Y?8DW?lX@{|4wJ{>d1_S-9(7S#OWO-LbM~}*A z=UPGeVl8b;AiI(JPjkW<^ z0na??*Z=d$u?4fg)g*Rs>XfFPIRjaTe%P`KOIkQ#L5u@tHnqj%aO3%w7|^g9dh_|+ z`20*hKb8J?8`~0^_`_+wwSG$W_iXU%k9+(V+y`r0yJ1OOi<3eg;WPl|GHLR}UN?D$j7+WgO=a)j7TSfGYtbZoP+p)y+PxxcM z39ePiZR61F&Fg6YHzavrd7KlU@1V_TW{0T}wK1O09~EGQ!F+yipGwH8TONJ<>!4eJ z)48l>eyM-#DSzl)#rnqtP5UA({O+3efsf`kw|_jXiS3gKp|zfj4zzxp6Y2EJl;p4n zLs~~}bFEO6yZ68B^-_R+&Eox9HMbZL7iQN#F2ufHLerWZqa(`jiEsSbr$WmDHWvg; zCTJ#8)?<^YB#qO%w|QOUJmpnzvwjuGW+)-wW#a$kdgk|=`F~yoFX~qz`7VBENq)DB zJOkMU=u;Jfyd-F1$*Vc9+&D!!{^u`v)%ftW0#Tk01-)ukeZB0bAAMw1xwV^1x@)=Um4NRm#%fOR4E&VXDbpR%}3BqLVzs9!;!WhQlhQ&0(fM)g3vuXVs-69*ViFUC{ z_o`gnGNG~8yA=z+{>+;5ryB7Oyt%%0rT5!4avb@M2Pj;>{p?ob88!HsG#21A?6SbBG_ zN-7Q|cDKEA85N6ZV^;!kwTh#;RS_+++J|ZlYTv+KVnRn^+-t=p_&R;|XBzZJ-&?D2 z!O~N*I%MydIqBBnN!%ND2*uo3S8ZajCB_9>AScigBm6BPF)WE+s`h(VR&kt6#&Oy^ zmsM+58@rN-ul<=G&$0Sc;u%^%#rL(~YM&t4#}=)_59^CavLmp+PYdn%*si$v`FLFaaupt)Vl0At ze%z4U8}AZ#l2`}#97>k&x!*JI`6M@1dNMZ3*r4WE>rerUyPxi)|WFM?d_Qk5S0Bjr37Dr|b$7SZ-?w>uW_HE!eQhVh*GAUU^ z9$u1PdvNgrE^gm~F9vi)s+To_E4>feAjWkIqhSSe`?;rQ|7#A#UWa|rHxT7&b*)`U zeX&cw`5Kd&5OZjJKU|sI1E+?y)eiJ%hVAX^VIyN+Yg@TsMZ6PzZAbAnF|WBjX3^iA z-ozG@!s}pKj60Teiov$AeQ-`=yAe4g=4r&E%yNjHp2*nab?(cJnBKiTVjU`? zep#8n?0?PyH;x~tVsB`5K6w>hm5MS4R%=!3dM>}ZKD4fDTY3G+!3R}dj{5`1{($is zoWFoy82h-#9O?B=>^6njQ?!G@mkSk%@Z)1#a)f%}%6pqkvb=zhDb!~Ggr zVIqBrWdk~5@BFE_x|i`t?z1GuDltouLFq?iWL)LMhSkW)XpJzNvW)9UeETit9$$x5 z;g>j$ESX2Nj-vuzv`)X0liDifhbL!?mgGxmL)H9cyah7OrC)C{ z&csX2S;iqQZC-^V3#Vb*gn?MrHyzX4MPg{A2fF!MAj6&eAnzI&65AMadZgjY>Em#I z+a|^!PpO#P!^_;uQb*dg?{R>++y05sj7OD)bIJF#Iz``-JoJ&)4LwTbA4KW?-lf(I z>3dxITswA5Q~6!S3stN{^uWDpZroaIs1duS4U!y&?3;0ob6E8w=d|Q9Bz`6_O~&o; z<9!uNmUz~;j0GQEwFq0L=HQF|U6Io+76V&`U}W1^%<0z^TV_vDvF)EYPvkp)qV4{2 z{w#Ei3f3|s{SfJD)4cqf&%_yC>Jb$h^zE7zjPY=9X~Y`ywm)y&-DtnqQHehqV?b=s zbC-GSi(E1nL@tSmi(EfaF3D3!T>Rl9{m#C>e)KSoZ&-spOBUeR`Zc(`cQ@`yobBE{ z?J=J(ud+8cuSpJ#8NQ=hz2=Q@F%&^EKPce6?Z! zk6Ru~EIi_X&{LFaK1NQMx=NN0@n7B*3DLI^*Tt_4?{vBhw-!LA3dFPinzjY(d zY+j2K>sR8)>Lob3b~#ROS&vJ*wi7e34>wL6!;k!)hy32$d2;I(PHkL^n0juqy-}~W z{ys%F^y_&0!TK+7chy|nSv3c@SI)wXGZ7O zI6i#{4o?|~{S*6Q_n4m8Mqg+XV{dEww!`usiCEaBCFW){$F#QLn3NcTDQ%lzdU_0I zc4~z=St*#`I|E+~?20ABdSL});_D`l#@0Dgv2W?;IKehvq#Rf1b6sJKT5=>Rw!|EP z*ym1>e(6CLC769SnZhkgx*zNlk8{1kaHeM{PWNCuEGqzqJ2k@IjC$DF&J$lIx?)|t z19Mlku%sFDRuLAM9a0U`0xDsmUjrz6Lk~H(PJg+9*G9(mi7R2-?{hAwxy>BQ zx|vhZwR!NGVCUMe1Y1{lsl8Xt&KLSc;Y3Ft?L;SEx#MUDFC0koz@8Kr>`e8*u8fA* z-8CG0dbh;B!KpZy(+x)%`#v?F_G85yTxKlno2_f{-R>{(17qWNm=C>w?zFO%YECdF ztj4{}X=7gBaeE!d6yx+i5~Cq_ zm;3aaAJDJ)ndABw=42#prtGN9P4P!1f0estiBF;X70ND2yTuOi{vC5WTc?k~xOUMP zmDCi=hWAn9{}S;kwWbq2PLhhxe2Q0XlbT6o%_&@Pl-1w8$>@^@_*0RP~8Voea>+z zv3MC9cTOI|frT?LKRX$HL!8kJ^x5J@jpW`aWx8$JII!2o$GEB)%$L>Y*)f#tk z_fDjTHBf$p^@p#Z>boW_+S3-+AHC+>w65!GEBbXmi6hKW9Hg%)acaqxhz&L8j6?<% ztIKOcjhLy~msU1Zt!1>2Y_Hg#(<>KX&EQTL8{?&7n7tcXGoR1`hZfU5P#zi2l50}B zVUF>;1N$%{xjAO`%ETSBJV(~8M6`>g%J0|~d5t-yS5f_46LVa)u>a(>z))Am*Vhc{ zrSLc^*TPtPZoWy{pJyF5a?a)8R`A;wGD67hw&9$Y_i5M#K8br1K(1(lQ4eWT5@r@*i3r_52m0Vn2% zBtN6t&m3J7_d0O=v`|Edi^J=y2lPCr`dxBm=Ju;teZKaK4#byu!ra?0%o~2cc?FJ4 z?uWIR;gGoDG{#LQGj=&Xv=$b2Xo^FhPgXJfy#BTF4b)oAb&B(7X15f^(`#Vkp2OvBN_8p_*x^_fpGf91 z+mqYZ{8@aq>qquuasN)};8_imGg>I$N6mfy{Wf#^L)tWf_h*F^MuB@7m7gO{0S?R& z)?tp&;{5_zbX`07xn7*F`zy0MwOgac%z=Y=vVSjr`D!N~?fMe;XcNDiHv(ryq+)N! zM%dQ2F1EDw#OC(Q-*pPb*6z{RH6#tExv%;0*a5beV_({xXD_4XB>(>l*XJ9|bL=3# zZ(MR1CZ$E``Bbr4v{xeIRoaa%!5(Ta8C?BSH0GYzSI2n>&O)`{mN`a?_g_N1j{~ZH z__|dS2g`zkng@@5!W`F+E9YuA*xql(5tG=j8BX>H!tve_IMzQJM+U~>DD!?Nn1en& za}d5=GY|LaYvQW-ZS-wqKhM6EcIf>rzT6GvQ(WhIuzS{6Oy^oWt4jj*a}5*!S*-(n z&oA6JA78%$1LA_wHPROynVW0N{A65RYeW+J=5O&Ce2A41oQQp~H(|l?pV-g^ML#V3 z5oIY5YgZxq!l?E*-7{D_JD?fP4^L1z!wX{w-58gSi&J{w^4y`gM!(`dF^Xz0FMg2N zeu+s)JVN&Kh9Al~DZbG6%xUbMor76ii)XfPimg+IDL+W9W1=IzPv-R2S>w@*vBj(i zZ*=7x?iA*Q4vfvU5B5ZA5b=Zl?ucW4F_QVcM%MJD%Y1;eV4suD7L{KY|A82gs@sUa zyF4ZZ7e*zjwtq7<8`l<$z^yfN@zbtNTnFe&pQrzSp07fN`Ffp{OZn4 z*f(P&KJU;B(-Zx%DW?}MZCkJJ6=b|{oP&Ot%->=%+m=@%%;-;BFzJ=$eMIHTqYByY;KZ5?- zT;@#It2GR#I2Y9=>zMeY^ikP<$=j&>z371X<0rHkSDD-0H+3+Ub!miN}J&)URq z+91r?QtQ+#5RI(L2ikmGNcnGdK7H%e0a1b3_tr1Nlf8R1wU!;_`X!gxAz1^Ay#U*< z$y&_zi!Uv?zwc;A4@~HdwOKKk*T$C^fG8YaJRP@>b1jknW}DTV;2uEkhnLO6xTG-j z33ElSFgIi~C*74XiH`nG$Y|_K^a*uAk6>qH1v;X$pFKJd>)O749klhW zMa*bTBrvzv!rcnZT`kbmsX9XKs%WhnxgnvR)7U6C8#VT2{L9Oy{3nHHc1)e4)~`c{ zG_@WG_C)&M@FUb-{vvL&-A6`cVte-}tnUzr70iKc>z{=0wynh@?q8HYXS7?j{RjMX z{tTA(O~de}9vB$v#P&O(SC9j;1MJb&&lZ^t^}KYdPfa9wS)o;3OT@WZAclGIW{y=6 zVP6^k+y`fb)q4`_>uj&L`q_Vnw~p~WHhY?;bRd`!wqMpTHFnONCq|@UPxmI+ zPW<<#^v2lSISl8C=lPj?E!m3+jv_ZEC+jSIq93^Lnw1)k;gQZ5%yth5aX=sDw0jUE z+^ta^bYfn+Lp^Jxd0QccxoyD=$GcWT3#TdyI~-|O5y3WPCBII;*=c&DqviY0wp{-o ze_425R_4Tq^!K=)Q4acXCr;wt=4CiX+kdEgIQDi6#;(qR*xoS!M@DzT{X<{rb~KL- zm6(n(-Y*c(JTay&Mn^beSeOF_h1jEipe^(9wa~qh4Z7C1W=`G`>E0Gdty@Fojvy9E(L7=#18qwxc=G%A+D`OBEJl0o&qIVLJ&e*cUS7#CrWF%b@sT>jADIv5yO z8-0oG>q%cUtG*?3`i!Y~5z}hU>$i5Uh&adc%sG8Uv6HdJH~JF3Rd zRs78T`^Nt5Ffqaw;rh+WQ=Y_W+bLY*1;sUe;jcPql0ZQEWjFr8e5`Y zLksk*R~^~JGj#E+j1G)vrMZ+xic?v%wl9M?;u>OVl|WPL;##;xQKf^_MlL7QL+iWd zYvb?z_tRNz0_L3MlH>-M5m5`%n1i1b zYJ;)C%)=8?FMEN3%*FRr_+;V{hzIE8PK>l*5}eAI^BN_Y7x+x_0>nyx%G?;od;^C| z9U~eC|6XHX^!N8nrqU~h^qY5U$9BeqIA)B!jCmiR)?tqQN8Agao;?yvTGhqernNDP z7>a4q|BQ!@C5}UI1i9^JUPXb3bOZe+u`K6WIPSK~{Qhm3!gb+^QEb`m8a@ za4v;R>Y;b28#)KN9qbV76JuYlIAJz_%}ds}VaY9h$FvHavp6;A@wSe{>m|BlC3Ubk z)0>Kb5s!-W8dfEQkI9buhT87kY$yA5ZkPOGyi^ zSNX4L_4D6augYhI+c$Kq)78&0dqP6MkxfJJh@NU)OJHxqOu_iVOR?!1|@OeW%vOePnTi5Mhx=g0U# zlS$o~VYn^-H||6yUX=eEckcc+%m4G=xvNsY=RI5g{!iSE?|J5)=Xn?T_40gmXS-B; zjXT?I$fM+=T!x%VZpsh&JpYk?DIj-#k?JRY(Yx}0e!xZUx!3J?^`E8V^?EW_eg!}N z6sIM>`1|#r=mE*AzQ?O#@mEd37Vnt4)PCPI+U^6>WVz&L`Q2yyo4m*T-WTO!`KSMx zSCLAun&NuLH<>%BL#yMHQlsvTjcbJQye7mq#>51Fj8E{xn7GCm)v^(WM)_i3GavLN z27YMk@Oz`$wLIRxRkOL(UpGl!y2$^C)bDs&RPb)@P<7F?jF$M4cz?k^4XIyQ8z}fE zV(65gXU3pOEnX*Lpu|@a9GZ@UVr^^9PZ4AJk(Nj-_Ovd^7@5=z5w?{V`C3=M(T-TP1~|5?@iru~B}7 zLn^825(UeqW2rtxGvdLTbMG`DF67CiPD$4oU~0`ic=f-bA8Nd7ikQ%@#o5(eWAQoT z{nNs26wY}f{j+i0qvV)D0gAu%s?D(YA!b!g0^S z`cTTx`b@#Y1y?SNaPGf)G-d5VQuJA;67NR*r~2T7mrbRj9jk5lX6puQ>egIa#66ni zYGx2;FF5Z>VK(|6!R({zIVZFHvR5Mp@EQ4KzsCKJlAl;ism*OkJeSnRivC4@!J`Ee zk0y1Zo}U%cMz?E8TwuBNpT6;OiGOE5(76j;J8IB9*;_MKuj*|dG2Skbm5%uB&>V&BQ!RZ{bP&XGPBcYTT#j`z(>a7v=BnCGzY0^$x^QD*0K5kYuOZ042Y| zQ;PgW5J5bj$S-xeB7Z|-`iRNW1QR!)RTDIGw(Q3a_^Z~OZ;o>r`6d;gW-jIy^LopOnUJ~{!I1W?SH&zpZJ^rk%NjsDrm+S%7&frDZUfDD zOu+*RCRXGZOrwDbRQ1Zm3TgdXH)GA3)kOBezuGpw+M%)Qnx76cZ@~C~s;yy+PxS#~ zd@5gMjmlz9y(&l;Gr3Ja`b zQA2q_L`Bu_7WpizDmV>I+n`E&DqdF3~c12q>6`OWv-u|a!rkG1g& zSPR`wY#`%y!gXWVK#^Z!cVYt!`2)lTDESqxS8%a#moXrCgd&Bs?s1Va7sMX?!>_k# z=ePH3i#=&xnqZ~2Cc9yCvOBhQ@W<|+G1xye4QGk@`eEBT#_DMUB~LC`5$2p#E$wf} zp0_`8`+?&^^3NByZ^DWZz0twP5>eIPN3{4qY7G!f^T)J-ALiP?2F#=DxKv$!$)`IK z4`B0QL5=mI_(#`;4+|A2wJbaJ-jPlXw7u!R*xlX-JKA|+t6+wc>SBExcdU{48Zozv zSZ_Wr!V*gpeX*Ujrl%K9!8OLz?;blu{v6r|$u$b*LHdTe&y_ddc*xr)>ixttT_Wye zLV8QqX4c~T{}`cFJ}|EVf=e%~aNQ!mflXKP6I(2pl$syEs*UZCc<<9UU-{GiK~(K> z8;)g%V1I_UCV1&xlzn?D@p37i#7t9u#^%du-2+#@cobv9P%<=5P$m3b(?HaBEBrtH~OinwZE-{9uXm4Q)^b z1AHoALT96?_=w&pS?Xe0UpD^{{I&z%>4qkbot1Fj?A6O%Wz zEq&qI<=F@Ca{j-j^e=V$Hsmd+@VZGG*e3cc$H4EdiQH(nzDcaNl3jAddF40i%O%Hg z{=9yP4`k#j^ZEd?{we!Mi~)as%pCpCv;~6U6&{pZ#CV*h-nUO4hJ`&+kkg_ex_VVX za;+ldhAD#9HoVghPI0M#c6F;`P>TSp9y?fJ0&(v?@q_-hpYSK|k+<%)Vg*t7eI-~*n+ zN*Xv5qYq>b$QYm>pfHDqA7G3D!w2{+KPaD#`&E0W>IrmwjgC{7{-T|rE%=Tca63Pr zjahxWp+|HudbJEE4!t{0aSZ>=wmg=0@O^jBp25aB)1P=&FC#IO7rqkQZ5BN-cs=rA zRB~}P23F|zTiK_p zj*}%uMCo7pz`$x6`u{cgWgnDZ_kvNDHDA_#Ji|;F!jCr|k-_bA8r(80A<&wYg zvw}+%jwGoq`jI-kO-`O4h`$z0;pN>saCYk^)+DUP!Iev}XYqU-WNpZ4{_Y#%9mN(r zlDU|t|5lD3$msa<@x+p(gA|;tCKq#|8uvOHYw0zve;P5;Pl$O|*U1xjLLBuI;xV6` zCeIY_KhsX%Bi`iBSKIId*U78G$*^`I&MlvflMAQd(3~9Xoje%Z$MnL+p`Ed+PbwC7 zi^rVyO))hw2xD8+!_Wv9^zo~uY@qA|QtUoMqSUpqt~So5DEEOy5yO2@lzyre?LrhH2w)hB7}QUQzY6*cBNQ?0?a@S}Tk`;O|A&{9_<1wBfufL*pR4KIi&2 z!`VJfaE2JmlRb!0A;#lS7k})_Y=qtE^{~C2H?|~uU_)zHtYLm~WlIMvjkU+3Xj^<9 zRR{B$)xoUDTA0pQ*px79OboVSEv_X-GY&Yyk2O9Gt73p}MfCP8hitdf=;HhtI@mF; zMf}9@=DwKGp(R!j|F?7YL~=xtLuvbF+WkGa#k!3L;y;NjGCpJ+$=EXF6`7U)a0^G) zty26!55)g8WS2YFj?56BdHLioI6ouq_^B@SwNu?1L#~tN`|&Ofakyhc93aQi-V9&t zO7o^4=#}dSuA?8U^2~A0SQ5+nGv@l|305JpCgrb*nT&)a~%}UBB=`z&L-icTr*`1 zYcJ@V@NdE&b&F$EK68zjW%o+O87GK3PWhRg%6+}JzH{uolU*7p*^NGs`w8+(aSwol zlz$)P-%a_S?gQMp4{%fafX$g9*fW?oT-LsPz2$N``55C>aeL=T7&RuxGriQ$XF2{a3?;|axX$>N*y3x8C*$T?%0{l2d%L&b;o<$9 z|J0qTTje@q)UitK745&m?aKPYzBl3_`E~hg|5vh#Jr}<~{9SScE$G)7J;S}o(NYmZ zT7_fRf|(AA^H8F z7wG&My~;f1b)PjBQqQ%6_~qf`O^B&c7)j*m>qRW^j=58wt`Eld@iPy({_OaiwRB?q~9T zo?~O>*r8}bOrOr1_jLS6*jH8i09$i?iTJ@aD1W%K6)c%=H1u!to@q4p@7Luw`apaD z=>x+D{xv^X{Geaczgd3emx}D-18_V)x^h`@`hLk;^ttVuV30p~VO>fh)1er$h`*Uj z{Pe-av(?^5AKPY}vLUz33;rzgKi;JZW|Ob%7w(VMn#aC8Mt`7wrH|pnJ)p!w4Eebi zgazdfb+SgC!lu!N{B_VTTIBS#Dd>6Ye{gwZsO_Q3sUGrzC`uwh} zNBBkhIL|tvse*X0330BmKCat5*R_x+UPdJ=>sg^pq{P zrY*nR;z!=Rg(ZWt(Z;bH;_XT+&P-!I7`8I2X=BB+pkg7c?a3DlLCud|fu+dL`JY$* z-0^SB0Ym;5`N7-=Dx9luEKA)3xy~MPFZ(@lyQiiN!nPiM(*&n%qLX&zO`?@?Us1$E!}>72Mpzo9{H6WR5pO?3}XQr>mDD| zkNAmtyD+Ukgm-maD`({ctV(cId{crKlsbIDJkE=8#`27CT%k{_{57TL7mV$EI+uE= z?W|)IKUi{NgQFYhF;(;Xj6VDR&;dje$1EHPk`ogCSRcwS@nEUbmw2$$N7<@a$SaHm zyn;v<>u2m=F|L2tSFh0JmoXsna}7{+7E-f(jJ3wB9l1Cr6UTZ-VPD6_*wNM7M`bRrZ@yxuLdYvR|B_D04Pr7p7H^SG<1xmdDZJ%B{K$~FrLHYEoWZ}9Xajrv)XJIlq z0mcePQv2rkYQa?9&(HT6kON@(m_g`5U#MG?dPw(oMH_MkMhjnG%~GsQEJE(g_u$6* zMCODb^4l3};0FcC?dbH3|3mrT+cBcgy>G{Lf^f*6?AnNTf1K?fg^Qz-aA|xxE{tWY zKPL^RMy2A!$hJ5-JOzh`CFAszUbsuXS7QxSm~kT~DE^OJB70u>&Ax!4^SyJ%V`_2; zCZ~jALQ)Wx59&huK)Y_%ciy|ixJD#5Mfaxlkxki!ud;K5H!?%Lk=0P1JX{$QRPkVPc-DB&1md>y`@aR}r^g;Y+b3KT4*H9uQ*ep$UK+L*rB@AXlsL0TIApVn7RempLca)2V9`+Pp@QL z7@362TXPYJ}F4A!)MF-`gTO4b+1evGyCy&~$OR}*h^Cq^oZa(4->i%yigLy#NVa}Kog zb3qE@f=TAuxOmp~wPbBvw3jWSD1Q_B{Vf~0V^Hg+`S-u3GB26pZhk(R@+O+EHu#P* zKit7sFxSDnb-P+#KUn;rJbpm_SYU2Wkn-;#ztzI@Ff3q9d@g05nH+%a6Z)%tTV7je z{A}ob897S(5zpM4^?*GiJSn>ex`w!;6Xos@=*s!;jCPHkSexmDB-R89cWVOc>sol* zB1YBM@tgy98-$ZbbYjmgsPWqK@ekU7B8xjF;QGAbxX=37$K!!Hxd7G8euK#V178rXVBMsq0Tu59`fvonVnmq z5A(x)$)!zK!}N`CNAEB< z^ayc5R;AKlxSp#SaqM4f&-H%=-X^3!v;zI2R6#?t+b-Bgo|zjFlO* z=j{WrFr_gL%^acoeR=GEGNW1B80Aufd);c}kgrDW>Wb*qD(Xo+>x#b` z|K_-OXJ%T$H8t)<_xbhzYx1*hM0n3nPaA;E^no^J1}g5|)fs_Un#6eF;Pwz~lo6ZG zEAuly(+}8`(}%T$4m_{M6$8RuR6S?!U?=nlbU+qsBD*xUMaM?A$Y@XpY0L>rU1YMC zHQIPuA;H}eE!|ifDcrrzRne6GK)79HgxXeC=cG*Rl>D3d56UkSqxH=VYoW$4dT9>!Wqi3JY|cSipZN7hr?qi28}vi(_8*_btztOxB--v;Tv)|A~EDPERHtZRu@ ztgVdW85XfF)ez14%4YVI*{%|K&MG2^K0vRya1{Uj{FijWt8+S~o+W37Cb4jXx8a#s z!09vig*-Z^$oajmdnEZ+La>u{quV+KVsnQ8tZnOqGsH#w!Wf;w<&*0N$vT+V|KVJa zI((`B7#ZP&;k<@~IbtB|G5b;W-T}7g;a3M)jccPzLmPBrU1o-_6>Fg^(Uvu($*j$6 z?N*I-rB%_Aaz{HavzWz z3p#NM4;bISLLQfcUCFnc6|Cw`cXtWIj!psCLjHt9!_#qJd>H11Rqf-i#KQEo?FMb( z=NQ+-897ayFfv@PMI9V$Pi|;i^bM$up3DhIJ!&^{)px3ArPri-u_l$=7Rls_ZbP|M zT`FUOG2|(WvMZ0KbyRICLTZ*qpjAn2QnxfX6npEB=D(#2Owpt)d$NC@>I02^@R;%U zE974|!F<3mUWZw?dVqO>uPFO2%D%H>Aa0NcL+ZCR!w<^u2XhXnSdiHl+C6C?#z#6} zY@{PbhuLF9*wb3pegU=6r!nhU8`ne@W$#kY5*>YNm}^?Ap{++%Bne+N>ssT9lWt*O zUY(yIwXKoliVU+Ui6E;IS}Zxl!)ujar-b?w{}A6=V(q{l_a5)uqt+z1z2kH57np|LnYXzQopN{ve*ZHs%H2k_l3u^gK(dG zkIE00c#!x2h96|eFMg27&rA8h+y|atIak$BPH$?jxX>qr*TGoIp2Irg5v(H~>TlE% z*C4MD&r9;Hs`$}6vz|Cp&P{TwfK)j$19IzCuxX$|=WAFktrpW>tA6+WE& zlf(upzSgQAYFXS9_lyqySK?odsqku3+o}`QUdZ54%rC!@50W{+J@CU5N3c4@7mJt| zmHJy98%HiVv-}f6Sp!P>rA9>X@q&vQ$e6f}kJfpb1s|=~$msG5HZ;lpDLy)u*wE(8 ziHBGHKpUTtKt55W_us`i8AAQZ`^$kArTU#>UQuCzPn=-=dLAxG%CGi7SH8u!nBU*)6V^Y3tQpe#p5P%k|MfE$%sDZQKHupn{jjoy z9abjr+!^M@^?0zO;$@X{2;@AzDH0Qx8X0pP`BV8>Bho;x5qc`WUL&OBH`fU1eAmUb zH2Q!uxW@gncK-Kd&i{Au52Ed>uD?c{5qa=bA4ojttM1LnN$ZYv%!{w0{8E1|XFz2&fXwS_fXGf*vy#tMxOg1xQJEcLR0c{4hSFG{AkLrY#@0Y zDF0-0jgV0zW5_Rca=A4!$_BDdjx|#4$v5B8vkJzv3B$g$oB_7^XjME zTTM%kzjk0?@{=v8zQhN6C|t;jTpOTsC>Sy2StA2+uo^Lt*m#9edR@SGGcLTY!=q1_+W92ohCW4 z&#C`;)W5QUTmuXnsILLSbFa(a-?tKad6v_Lkk@9#fJ{tCizU}lwM9Nw|F!jxFY1gU z6<#*Q^=KY4cY0>R@%b6e?=4`=cX7L5EbkD3m6_y3;I))LFH9rnKmRtpO#mh__c5tm z)V+zBZI1V4{cDv%|5Np^FX{*RovcYu>z|o#e6IePzY`n^-zT^fdGBAoj`11)-@owm z_1H!KSx5!=dT270l>0>?YTzqdhzKBu&XAx1!ara#xe&V|_jlFX)EhU;{|l7@rflNFSA}@=vn=;62C2*mvCX^p64U~`TO;E5B%K&G7(;M{oOPFH+n!g zkHpV-jTgh6%J2Au_u{zBepAW5A^yKF8Bdo<=gZ=X+W8H}EnAfp|+K1(k zPk0D(@cno`rJPYYFw7OhdEV3*p4~SowJDYi?1Ei$CaLpA?y?Tx@XEzcrtmxEyX6`3 zEP19p+uR0eOWwK*{`c?Kzp@9|-(r8IpNq24(Z6B=)2RAo-`mkUCg_Ho$+KZ}KkS)0 z99u?aX$vx%k^k2TJ?oZ551#ARo%imn$IbREPi~qDikm|CS%jlUV$i}s^ zA(DwrZBzSGb@o`C)ki8fIXsRSpMIURb>oL9ys|vAFP|-KkhVyhq;1khb6ff2->-kN z2Sn$x{(kaS0h3edw+eI#to+f%e#A(gT)Pb4Zd<1<@7e;xh`Arqpo-$68meOL#Gwl( z6XT7-%Oz(M_9icl#9bx!oJ}rVIpi-#lW>^DSd%lE+$}Abr{=kM z+RW@UT-df5L*v8mOPi(bB7<2L-u{05Ru8a)q>sesu3XY&>KW%;xrJ3JjGzkdU~sDlZPT=|SUR)^5?n1ViYy|N z$Yz$2KmPs7(*t57-+rZl$)eml1+&5`z5i(UoGCcJbfzYJBU8yMEZokLTc2poEsbN% zk>r<@{>@y3l4lue&b0~mwwnJ+|5X$>p>VSq`WKEm$-zqw_Nfmb`WHWdoPC`8l9SeX z>tqb*yhW|3dl>`5;U{B2^e=gO83Rpe3xvx`_{>7d zmDk_vg5C**cq>`)b<^NPH;e0s7R|wqA?a9{;HAxoup#fDnRAC@K=d!U)d?Xw2jN)i zU%1L;42-1iO17$v{>RR8*U+Ry4=&$%o8o4NVK2FN+#GXEw2s`Rh8 zI(4qTT>UE_P@n&TOHukK=Y0aPNlO3Zuv9*P(!ah22v#Ro|J6nRRzxE z!iO(-g6H(Fuoc3QpI86-8X$c6&(43r9OcnJF?VYIKcjzr4=7x<9Ti_M&)XpuL(X0o zJcjVrs`;<OTb^EV#8IsSE^FN$?e!^*K@LI|k5N=1|wyRh6ZR}Yz zPa7H+g4!Rvw1kSc;wApB^v(a-SHS{m&HJQmAye06cZ-{6*Ak0OJhfmc?~!xiGV4dS z^o+-hPz&;G*gVz0I$NN&!WOCdZ`S`fVho@9fV%z#Z>D@e@=)q~0PX<|ACS72G0=na zU+@>o2cYg%9Dq1P;pr0n>wCb`Y7FRmz>*4^CVK#54G<1f;cyfl*J$noWDJP@n^5;+ z1BA~nRO$aibymFSU$`wr|5DE>XBBn~^~JtLbCKp-`)27vrp{FS$L2ozzc>a2*HX=< z@Jlmu+C)mNfF?DSs;*Kv5Cl&zcD>-^ZDlLU-%XM{U$pn)PpBs#To@vDJ^si*SYK)h}gz-Q-Yf zg)Mtt|2o!I>EFBu9Mbq{44^;9z*GI}9Nn@9)b{|K|K=Ew!~mYvzi^gH49J-O`X1mJ z{WBh<_5j=msQE8@0AAs;2gsxU05$&$t6KI(6@=eX=Xe#4OX0bVW-Z%s+C%Rm1ujZo znfvU2eLax&e^C4-Q-@BCoPN5sZ;#k|O}lX6DYu*%OP|XxBQ`)T>R#2E8?_azA-m6- z%d;!yVr{QPj19Cvj(;_^2h8CW%4+FTUedS!&99dk)2iY5=_`l# zOdqe#URL#k=g;TzN#)M{y!tnMK(PVF`u|({H^u;Kj13#`++BEeZr{b3)eA8tp&^Dy z?WODi%zHq|1wG>faQ=64e;Nmrb6Zp#m@$C14(2$3oxTTXZPvdY2ar7=bAskLpyUCJ zI8Zow&4t%q;()=7{pfqZ!e$?U`d2=n&hwsE|L!Hs97p80@vZa;woD%f=~L-jD*wNA z42XRyC+$49a*5Q;YPq$eM*XOag9~}=zp)17*S}!{3_n2D0kQwa{Qo2Rm$4x>LhJ&0 z<$mHhF5m3hLT>Wb$RanXoTr!@2QtyVr*U8v15j~5a~#Mfzy28qW*orS z1L|>L`hey*pg%dC{LC?c24){n?E#GWFXtVQ-$^*GT*z@HJYRt}<+Zb0)~PWdea!2> zYArDPCndz@@0mJQ>V`FS?z+?sith93Kkpb2y&IS4Jn#I^t9!!-G{%7F)wq7k2ITo$ zuFt?VLVi9>PO5pGTk=fJ+UV$95}mpC)Ag^P+x1lc`X11T1M2$M&oO#_{_A@{rGK>t z+N3@k`e9xRBQ;}U1i0~m2YInP9o1IoEZALoe!${s-1zlsCW50E{e z*Z_SG_>PJL82Wdo420Eq+T>Ysk#Q~kfLxDI*#4O%yJ({|38Z0rsH)A50~CAO0j7fKGj4%*HXS8Pvm zA&;~t4)u#CkK_PcU$X#r$u%aN%8Elm&el+RXY5yW|04a%ILJE&Ua$xJm(Bk?HblmP z;;|DB@;g7`$npimgEm8UquPqIUCz8#djLBf3u43pUxWpbbKN57|EW9xeL(U5j6I*{`T+C;gzr|)KB-x_05T#QYdJ|xVU7_=Z1q3!k{Gp1=SI#y z-B~>cU#0tKd)n(f>O0L`>Ra3LTpeDU)!90ps(yHPuNa)0J%ZedTXnmCiFQK91J{6D zUY%dlzu17hK42c*{loVE1>ceDEAVe>Oz@fC?cak591CqY28=v_!ULMIAh8CIzd08u z`qzCx0}Eiz1DNwbdK~b5b=I4l^(A{ii3563|7s7Y;s9nJz^s4aJGJ|?5Nh-Mqc27e zl{n#j>cE-TzZFMd&QVqK{`93wm*$Vh-ZW2g=-0!ZbRWf|uj}6%x%yA8i;cWCkW+OX z&sJKK;EWY5?NuH9hKvC0=oN?kqdMdK!pXQLoSS0fe_)JH&IjSoxm=@p_5UaRzkgY=?yEfpmzpRoXhhZufk}-y`PE$=3;@K$AW}blRcn*zSq+@u;^cp11ld; z^v^h;u7BAB>OO#Q-OBve_5T{`d{PJ&JojbggwaO6pz6OdZzya2Cz8iIy>Kp$W`}6| zJJeJ9rwvf&2<%GJ&lKCvxi4d23w6I)#sK*PS#VC2v{_ zb0e&_aETYhE*8ZI*c_W zmORg`h{A*Fd4N1v5as|R4y5k^=>wYMz-kX*jsrf`KVv{D4wz5>$_LcXKNJ1)3@~_B z`cym0e45P%1*cOdQVa3#@CV;2`=%QB)V=6`ALqZ)KhKjh^uNu}Kkfgs z`lk(`9mv%`xkN<&OIq^0H92eJ87zn$u^_~RL_1+FbHNMAvAJ_}7QWuJ0#B}TJ)qwv z`}@55`FH)Ccb$;4Y_5|taB7z%H08P5(n1L`qSe;5(CtI z0Eq)|{_}D!uAluT^I!OWZOM5oV?cPn8(5UVX!-)g4|Jmb1w-l8POoA=kw z(++p6ug(uq`tRUN{p;rm=IUS06>RH;EpoP?G5>`_rL}&>-YVJveg2F7dCp2+{R^*% zV1X33N?t4waUjHhOd#*N;DKkxx?^ca@{cu)P*_mG0tIpX&yNLBabU&(j5v_!zb^BEPvbzk{)O*a z*MA|Uf8qTW?)&AF$7*RlwQo}KR(~;;>?6T!om;X1XZpwDMDHdz+C5C?%jl)=Fn!1{$G3N0bXU5?fr<(ow;{(MrTGGE7Bp9 zkdQ!n2qmEt(i?L%*Ys{Ld3d@cF)-_+Sfr z*DWo>*~!CLLy|R9lYOx_$rmpr`C$)5e8Anw0csAg=f6eG0apHE`=z#wH6OHszmX4Y z&IM8Vpeh&0I1e&IdQwR)F!O+9FKBi&Yclo?#MUDAA=$hFU+LbIvfi`KA!eI?H|7!B z>v2Cqe8&&ZoWk0%xd?Ce2)fq0U-|z=49Keg^Z^b1H~6=cI56woOAJWyf7Gb?Z}9)E z(tqiHGO&w3W-y;na!Q5OT^<8`NvEg7n$$jTtCJ@+gQa(hh}25cHRGgiAnVAoj+znw zkvI^0X^8xA@jSj}AI(qq@51}+Npx-9Y@AUS_YU=Td^PxgUFt#j(#u zygSy@A6&=$Kk2=?mb$O_TYJ%~^8n^tFv$nD=7Rhr7mVXT<$^IEV4Up#cWi)yfTx%X z;EY8>dScs{OdMG?7gt`|srqv&zrxycOl*aX~8%$ zAo=;b%CalhOs|qZ>n2LwI1yb#(?Kk_Qv65O{E`bQeP%xR5dWlZO0Su>o?VI)^NO*z zus=2@by7ayxef`j>o%44yZnb-!m`q*5CR0?#37}&pjLupI^CzX=wux;`|7@ za9>!*0CXHk)_~IgSFZsTfA;(r~tKctVK=yykdq6r4Y>fe_y#QPMhq)g*?kn|mDYxinf5$lO z%_|r1#rf0tl=aEqr_XnRy%!G8AA{$LldvYa8)h>Pcye%kOzzx}Jqa6OQr9LFXCoJY z=K;;RAnHtz`AldBYc80a1!8TwOrNKa#k|l0)~FsA)eiGmr*6-JDXN#R>h<##eNE|K z{4?!@&9<;-fb=$dhyKEbsbdh<>M3~DuBCdN82pW%H`4dX#$Wk>27l>+wQ@|Pc3lQ!iItDEK?Z<#^98{4D z#JHU8+R1*utOdEh2l4%-=OS~7zhDi3cMtBtxvi`5+TzK0e*6e*${m1}!y~bve=w%8 zCU+Un21u{wTha=v<)TjQ=LNKZ=2^{({7oe^#~Ymt+mZ z%S&eB-0to88~bXDtIF(BNv=zRdO1Ll1Ia~xRWKsB(*GFB{=9>+C+tOF=Nu*d2L>_c<<*;Uv* zy%;Mp;xRtVi}_%BKUkj&ugC?_`Jl#`Fnu0C@_~64fb0HL_H$mAn}X9jH>-ZNx{sx8 z%vwK-{e6eug`ZJ+A&!`I?+A;ncd&35(euCA{#V6c#zIwlf%Y~)*qd_!WDMK|{tmCJc|6Ei5Idss zOKD5gx_~_>nP2$%#dG-Jh<1LTsB{z#5i`7|Z^Z>Ft^z-uaJ+ZSn`i zIzNcGW`9C#^FK@dVnj84i0l7{Fp%rN5$xwOCZU&F1Dx9Vtm@~CZ@;6>`cn0bsp>P@ z#)#Mje$K0hU&V$Q6A|8~DVqL|6I>purFx)AA3)!_e^zHs<=n9_{Fw$o{KxtO+BPaz zwSdpEHn`Y*5qthJ4)hohz1L#ae=~pW186_MtovdE%>3nd(R&dY1KJ;uJpye5YN-EJ zUE4ePyRsp=Z@G*UHQ#(?%r{@(RQ+qOaS!=0&-`wkR*LzV15g&<4Y{H1klxuHgZ-K! z&h1I`69Ww@xE=lw?)(jMTROcKpQ#X#Zc^ z|LXW_A5g}D=>6^Zo5z5#*J9S?U(xR}X2kaY$T2JZ-+o}PH;ETZuk)kNuET~&C76^H zi{wu3%n6sXVa7VJdy|Ke8`lFn7tF*b7pQll`@&r8l!Naly%nV|{Hlp%aIO72Jj>b% z)*2L2L*-6?9`X5u)46Yt9j(k?j{$85%(^c&Ky=^CU$|?L`CsROXd9sYK+${6U)ul~ z2afdLp1;@u2iN1*{5NIK)qKOf3*pMWMKuR}`IYiTJ|*w#wDBi*ZpBM07h(OBF<4fb zixp$@v1&pwHcX#@7gsFC#r-cEKCr|z^)-;!W9;Iqt5+a(NC;kP(bV{db4IQEYdQH% zis^C_m#@AhutN=>GqM z{B5i>vubW_bHBtWWt}N;DUK5vFJDuSF6`Tjzn^{Mr~UT6{K_&ZG4!U?BNC=H9ssOi zRhPZ9%eQYf`b5dxFH%$fdj6L&a6A5D2ekjE_1_VH83%d{X!gSW{{#M2jTPItFpVAi zzm*?4fV#g|J;9}RT1|f*3vKwP@^6nGf#nSQ<%;MrVDAGu(tpigZXJyQv;Ld;>-C@T z*JD8Izde7M1BAbf1w9T-*P*Iw_G|ikB~~&QsQG|)T=bl=AT=+D|0g;x^Mm-BqWfR) zR{kdbr}zW>-j!atI5y3tYsHEkv+(%@2XGQPxy-+5biP- z^cv7?|Lysk$AGZcaRBWDX#Lmx<<>j~%sznF0Aa5AYxZIXOy67oUh`Y=sjLh%3rDxs zYc2kq_*;fQ_rCJyWPj(M%u)H4>qWWl-`u#4o7b=5>uXolT>K?_27SRe@8_2<;veiQ z_8HfdpRnildps9=_0|1qKj1j`Ru8UUi5Hj7!?w9ouyNWrteePqL|HBt6=q>hb}AMX zjlzxvv+(+kXH~3Fe90=m=O>?9CMNWNFeUt&oE!L`#`ihRDc`oq(0jA)>ouSw{(AkV z=YKs0?EL^c{ubo}NFJzWEkEXA^BlE1FD4Qd?a5}#r?jz z35bZUkk$8OBE5OPxNw$zSzpHo#}49c#sjatv;!A+ZBYGrkFQ&Z!^>x2-~0*KGou(g zCyc`8l2okA8HDBR)4d=$Ow|XS9NPgCqT69?gg?r{eA&Cv3k5yfBCop#`}eV)EPEGb zc4~pNKxYgOXo8`>jWEQ!KI_BPMWV-3=-c`U#JW7H^1wnG{sG;d{%-_5aUVK7T8s5y z9%ZjrUrZU+7wadN;I)lwaQ)ChynpgIK0bGr`vdGz$Z;j(&b9`S@mYg0Uw&vmq(&wA z*JKW;-KEa`hj8@<<3050L@v;;)54zVmN(DAa`p^vu}Axl-1q%~`@Y|E-}k%Yhwv@0 z?>9&G;pU;e`0CX?_~O6|+z;M`&)9qS)0eiWeBckCUyl!Vt-<@-SK?jf{FQH7h->UA zdu8=>TwE~;=N6B}8}o~Ca&|6`u@=6K7vG-zo1X^ zKOvqn*sCu4S-P>WZwE{o7>0T5Teo)1XzX4%1IM{vf1Pvlmv7NW5}VFkGRQuH*mkw% zuiCCVV(!TP%j4AFZ+>Ix^7I3T$X{~As{0Wi(YZ9T^QRvzFTu453Aj2o7FXCC@Nz*9 zT+HiA>1LA)x!rIsw=2%(bj6wME;v29Gfs`_j1yVGDi7os^MH+95axj}7v$A+=7BI5 zWIuC3Bo|O}K_nM&4|BncT#$Cm1@X7#f=GWY-D7N1KV2J0=Ym-Gf^{wk>w>A;VAi@I zx;B*T1I}ihNLyWyp4Pe`%n8tSL3C{}b6tP}RToBT!|_b8bss?Lf{2V{ufCD(8exP; zU}KDpYLBI(2H}M{6L5yH-jClrT@gc+dEB&SuZojqTGg%n^Yq;FHRl+y4b?u6KCTl&Hgiu}SYImWSxGJz_JWp6{QXivFI>p)$uZC!XDMfLx^oN|`G6;w z3-&s50gq9RWCrt0KrqKZ5DrQ%kmQ4za)C5|$p@5NkX;-Dwp<`{E{NoVIm`tydQKU& zfsDE^6}cc))rFDTP|O98x}ZU<3*5dQ@&ma4R~NwYc=mGKTZ2$WNluDTWxbyY-;j%#a;YCu??Kl4m`68^YcgGDCg%- znNM+(eulh`d3>0E7oYO|H%?(yK{|vj`B!&-^!F_ua9Va^R;l8zSyy#y@b7_hc|GuE zZV&SBhSS+r{-Yf6=Xn6;f*z3b0A~KQ0iyqs4`|B;8tkX~%Wah&YdRN<`Cw8TOnS}P za=}cwAi6fx0;vf^ou3oZ0yBFuAFO**<^i-|FIq1wPV9h{LwjL;W-Ok~8;m{E@^FlK zAD4Mf_`{Q&!z9O8_725|5T8Q!0L0Jcb*yw|MOoJ+nDUs{g`t{IMQe-`zbAGUT}KBR6r`B%3e z@JQgFo!rGe znmu1@L2)*m|KNnCl;z`#A+_ttzsgu34MU6Mw)MaH$C~jLhs;g(U;h76VNdps?TPcE z|CEY+;BL$ZXFf1}0T}~EK5#G&(f+G5A*qrNZukJwPfvO(%6Wj@Nz4Uh9{7#{-q@Dd z7SHx|$Hq8Ul@IEUp0~13)XS|QTK)N6v}7(w3oHNFK-$W@)bAd0atb1RM?TpTZ~DlZHdrl#Qfva$GJ+cJD{a5ui^ zdRF?X|HxR#EzVgM+AT{}aX`j?Z07=XERgK0%muO26?@(JSKqgB6Tgsi_{EoYVQzXq z3}zf4k$ueNOkfnxfyc9#`9_WdvF#E=(x1!reAD-^{f++L)U<)@f!&H@;G)6Ys`IkO zxOCtZc(Go9&INJ#(|zP$3(cwj-gWGoy#{Kbv<`oQyy0lbPI z&YouMU-JFvk6fdVdYvLU!PfXsjqAcViUU{0Uu=LW4ydo`zxI~;Epran@1I{fkE0uw zV-?Q;l|^+>bz$P0J*09$A{sq_QQbYUWl9Nc`^(1s)LToA>dW1#MTIpIs{oAg8?e@FYl_j^75z>3eF z--5TwqHuj;BHo>yjt^Ii#Xp$KfAgiS_~FkEKuTrItHls z0VEbEv0vE}(t7|p2CU+M93%FzU>ye*-M5be%Qz7GFEKF(abWYc{H4F!bWrR$bxrcc zzGRMa`D^>IdE6+BY~K|9UH*(gtsgb&0`hhc>qDe>Y=I@Clj+MdW-eg#XcPo8iNL zSmf_0FYv*hjsJS!+e5Fxa^g5}n)>_38Oj@#;=mU3K9G(B%U*zaA3(=~HGdudua3Wr z0~rIt-_bsRJ%3@Z`Rg(8FVKI*L*h5qc=G8jYp`%w6bhLOJgR+T)&_lw_2G^FAQA^0 z==KOw{TpHTyvdC7Ur;`tjtSV<+A-8))An9`zwv`()VZLHUhOz`czsQA1$msvKQ3QF z_ZCk=p9g4LyW&ic*nn2l|CVGgK0pJm0iT&Z5xrYHd4T+-x1IgZBe5-?y!idmqrj|EuCJV?pe`7M%m2_1~Vq%mb$DRny;PE%t5sbzI-~ z0-h}zrs@LbwX4h8;0@Rx!rCLo)*qs-IuDQ=)B>BzM&Ks*msHID4&K*1Hf}P8yD&Qi z-FY6YH_wMI&QG_k8T8}i*7*HnytsS;{8$f2>Vl{%W=5*Z?gu4$SQJ98e8^eJxdN;LER6O}LZm7h+9%H0H#&!-O6#tO?f$C9DfH-*Ng6IR#{>yoQ78HpCh5NW*c%aMo z1Yge%K10J!jZ%FY!y>xxNdGnes>XoWe-Y7pGk@&^$gTDRwEo-k7aJgU-`)?qgbAwhLHOABc#FoNa^T`qnp>M zy+4Pq%P}Ug-~_)G2zdOrQXkfKCeT(Fgy#W0XL_3@gg+{*s_jG?irE}YZ`lll;xM{S&PJrfNgk z)dhLX{!EzGe>oFY!CztkfsG!=$l%t(-~L>P@NYIEz?u9_?6v=AKL+gm05g9*24ozV z*MOS6wgK7)6dNGiwFvv__{$iuvN!4ialV&)5axjVucuYBi67}+$4tcGr8NI$G!be&Yi*3LE%Vb ztYW@E`&xHT zIS%N<7|HqUuA_21s2PT_4t;{B>OrsSRd36KFjXCO)8!1NtidO8*`4udx3z z|BL6?mOad8Uw07jAH*je&C+_m5mGWVpb$J zCi-Fn^8sWZSZV{T;y&O?_6b`qJz{h&2>ZlIj~H_<$SlqQb0gZ|=+dd&>n&Gvh32fU zy}o~^xBB^#^EWA>8g>Pa|7ri>cqJ?pkCV(Eh7E0P*+Vr%%Tmz)yLu`_js3I6N*HyEA%VQ{Oh&l+c#@z+R@h zFh*@4sS9EBiPQY0Pnf&P2bl!l||M@X^V`hEFK_gC@QE#lLes@$S)sJR2UP za>0hMF0Ay2h;RBwEXzq&xt_8{tctt(J7c{U_P&4^x2F_)T^m;MS3M$F8%*iHnZK?J zLjSK4f1U}ot^tL=%>P|o*w@Ul|HtXT$yom#XY5bdYyM&fguB=PM?Rp|f6d=K286rJ z0p>M;RsU7|U+KR1eK+tumJ7qsu)dliHrCbn|3&dQI zgo<1c#b0_vvOd(ZSoRQ1?uu7u72xJu{2X#7{5G-II~fCJj#3+P!SEOiYV{Wk^J1S! z&!<#f;Jlt*tPya~7CWr=_4(OeX6@|GPyJT)i8Fcx8TEmMzp4#ss|{xGS9L*H7e>~B z-i!x$)BdY90ByhW0mxt0fHDU(r~e=0-cmX6kc!rzGh96MG$e{BQA4v5G+AYeI zk9t3jaey$^1=O`6jry>5^`UM2t+j!;4y>pPLH@QipqalB2WrN8kr`1vs*C>^@!umy z0GR{y`p=R6o7oG0^BBZm^Pk_$YPIl$|S(^byD-t%|(8XRMaJ9S>p0%Z3NKv?64 zZ1tgy9zjNJSff6$(IduDeQ0xC7>NTJF#yfqs0$+cFS#HSQU_HR|Ks?gv`VpTm!=bM+l-J$<-&KF*EnhhrJ-ag6x@M~;ulV}l{tErq{ACOXdo3~s$Y1RR3U@ghaQP~3N?otzrMNtk@pk{%LF@~if%o=qRkfjRG51Nu{kR^q)d!YXpvYa~Z`kI~@psNso66F#I6W2% zQ=^s4=k2`V(X9O%fvfvpw4J@I5qr)Zdza2ZU)RS~E=VNvK_V#OwEwC$BKk!MTM~K(}TO8231~lS;x-Q6lX!u(vTxNcVch&p9D*xjjFYl?C|AoKkKKWY| zds+9%Tz?5aFc$jN9_G3;_v7tZsVYz8d`@SaS7!nw7ff=2x-uV}`9L{6a4NqyP8CMr zR7osOjZMI*34?HY>M*=9GaYZt%D|}^={Pw(4acXZ;@H&TI5KG{`47Pxi%M{V=S03b zL%)=D!Bk&Ja~x3O0TK^#6bF`ZP=opWr;p(tKN-DyWIuK>HZXr^C>EzhW09~Q9)jrX=?aZ^vD~hdgfQ+({^m>x?n|Lr~bK8?qzX^X!iok~_4*0AJP-X;YWy zfgV$RV!N>~NLNaQ4_LWAwDgEE_*cXMb$wvj2hh17694~a`3=;mI{!oEf1O-B=a#bh znmzf;p1>{U1bp|}UVOA>lFAQ}b0Cr=IiKI zKStuwvojJ=n$R7keY>N$k4QJx{^*MQxGuNLKTGg=FC zaDCDMTq%v9j*~g_y%lrb%9)_I#zy1X)B(6LXE<)m%fO8VBXE7eNL-yif;}O~p4=~! z`=vP#)3H1)3d^jrBrTHcBe5_gLfHU017i8m@GWi6t;WWv$9%$A z;K^f{k`#fmzTFi25^^t!H`o`Dd46nXvhR$X=+4NF4#w!nAY@TSMsj@-(FvK9^stUd z=^20_UA&RNdSD@}57)lVAK*)y@5}X{^oX(52R7w`$UeZ39__IrZ+Lb2pOO^F{O@|- ze7R|sY>SK_;%x&m{Xyyv6Zw zWllQTr{f~^{Q~9O%v7A6o`N%!%S(#!-nJ$9R&2Y}2xZ()#ef(KQgLA3x9tUJ-Pdto zNBs5tFTS71?ZyE8Z_(HHkM73~a$lCx8>^`AE7GGl1|qREmCRGZv1nL0_AQ=bT~FTO zIS|exr+02baZE>y>Dv{heY&EA`d%F0g>yg`6p(p-OfYgOInhDLjtaskG8Y*c(GerU zJ0LTx1JXl9+9S1hd!&Q}BBfU#hVgb-NP7(E?2Sk-XLN1$I0EbaNyPy@YX1fvwErp> zfc(d$4!T|bx5NOf=RamE+pf+46o=y4l>R86pN_Z5SfreM-*zD7)cG6pGsr&!*XE`x z_E)I$mu9C?QgMOoFU-!shtI9XE$08)@`3a|pm5hB>@|Pc3lQ$w28i9Sj=zipJqAp= zDY~e2R&GBy{u(yrBw|fwG*)LsVHIViV$WXFso_{UJOUewhN^w~n%a8v_g#i^#noCJ6ato)_H-In?!RG9OLmS!6zvG9ok(nUoANPwU+dsUhu@ z{tu%K7}mod$&?}8Dc$@rsH-n)0Q+D7C6VJHtZh^HJ^hg4FMB{MCzRaw{0I4~^Is=t zmEqd7fl9~Asn5c@oJ<{y{(s~42KD|r_5P~xpFJEGrwzgNrG@xx&nDJ}X6#kP{u%q# zdqCzGur&^B(|t$$g}W9R2YMe^`~a>04)|;CV&|{z-Of6Y=~$Z{q8pl6?eL zQ0JEp3#AQ+LHWU#Z2qI|`KIwy-CX|-bBUJbBwr1lCRdw=!>^~cceen{q7@uY6P7;NRP*pqv|U@!Cw z@h=5Q{blY$#_(@=f~B9FgLKj1oV-(FUTkG3tw z_or#wuTrlsU4}*CK{^&}&tJxYwgbXl?11RK7Onqg_Sz40GzQH2Pdoo3dqsS3>;SeG z48pp!FrNR5!n%w|tPvsiRcYZ^K0J)}KMJpMZ^)LMo0kC zDQUg@F}$ZAQpkN6xhHq?L2_3g4517r^Ff`xFo4_>$-Q4tTO@RBgFYSFAf6)pBmG^m zeQHTf&VS0e5a-hH;7>nVGmc{*wMP8qapM2I&G}z?LEU04B8dU%ToA?Gybqw`z%mB3 z{#V6c#)9_$Sn=Mv#4GB>6{R4Q;?`%8KEk*vg*4 za{g26y1vzXtG$(R!nyuDYeP=#+lB0d$)38e*ax9h*ju?P_EzpWT>A<8QNo_wM=};T zf|42Hk92Yu_NhIDy{}?Fl%QEY_210j>;uX;Fx!8z0c39x{=$Mj_q7)`VbA#C*q9!MO=P}tL?kwl z`!nP&?AKE7SEhtuQ+7YRec;6kov)$3R~irh_yW(*9*Z%I15O}!;XfuW2xYOIP|EtC zCG`J_qC23FI$sdk9(fUg$R+a}N_JQ~j0z1vR&RfdAot7=KV;Dk`z9ZamQ5%Ur)Cvo9vZbtL;BjOU)vSjreOFQb&ibU+bn zM2HlSd%m!bXonnf&nEX#Azlu^-2AFov~)L`tdi#fp6(>%a*6cE}5F zhup9L#eTGAAL5GRr;=+~jOmAxC{+PNW? z+(n|O`@=$mEaSQ6yo35rVgnuvZS?2zzi*g}e{5ZX?^yE~XULZ4ffRf5K7i)Wu}~=& zNXCKK|J(5w8({VUguR)+_W#Udfb7+oP_g&a{Tt-|a@i2<7!igYqaqFd)cdW}`)4!5 zv6-?dgFYX7hwUmJf_GV$2(;HV)^WQrpxASMIkV##OzGPRlNEdFKDm!0^RY4QIS;f) zX;dIeBHN)jB7p4Mp&&c}d13yn1?{^Z`Ty&Dp!?|s`**BKLvqs02RLbRU?LRlMn z&EzrMS9rKwm$ne4^YNF5hdIkET$BadjYxUhxsA5w=Z%i z*&#j{)yo@MUt`<5AV_j!#aClXs`#8g4{8rQ)>+F*ct;V{X4j! zf1oS+QTmd1p8yxKcR`$gOT_xMM6_>9MESHpZ;!@!=h$nITAt)yliFWucrY>4sQ((> z`KGG-ZqHxae;EU!_gcj6i)i-R2AIcyX0Ppkb^P@hpzho90BP&r+PoP1N(OKbI700M zKd<;lU?zmtSL zf1g11z2>%)zS3P35jEB@jBC?xj+>U@5vFZuf*hwMj_{V3)KWs&^|Vb8qK^loj* zzYS8!K1JA*yGRn551|a|=!SvR_x|l&kr>#DF<=++cR?R=kK@^ZSV}axNBJ~oJg_-t z=A>Ju4UYOb^<7{keaXF#e+#m2j#%I3WZw)?-p$CqnTr4ITesq8)qhq-fM>*2{rAEV z6?1@ax9$fkyKmNi&0lWy7!dAa1GEnyx1#rE{$?N0ItFZe0K%VpLGLgp@MYEsc_k+j zdnqrGxr~9`!aggELjEH|v2#Qywv+ufj)BYEGq&x^N<6@B4!_g;7g--_a+EL6fwspq z;ZN?9W82a02e2k&0LGL1Sn7OPgdfVn{ZK+F3iUxDCBL^f@_Kn8x0ff`dtx+oKC4Gt zjO^A1BPbcv_cZ3^r&5NK`!F&e8stX3cctFDVsQIb7#Qe+0py-Y?)}I-fwz6gJZ1Bmo=M!08Fgt#~SrS;z>7R3G!4a;Q?kUe0vFDzrg-Ukr-e>?s%7PS9g z4S$svN}adR23%V|i@l-yV_y#UUveW2{@G+td67E5o9thp&OfKv_r{hK)*f3r0pCi# zC)We2K8(ZyekOmd_b<*U!i@Mp#eO<(r^dBY>?cv@75hkk<^lO*jAHLg_N)!6*n6XZ zHA3^rK9B5k6#KT+eJlH}9>}E5OJ9gIp351|T9GN_K8!iK$>g5Id;noTNU?8;{_V(~ zd%+3*&C%Dd8R8XtXM;VNM^Yj@n;^ukJ`QYLV@Yb~QZ5WB!t#!P=m!}6Ulz%QEY_20~2`vCU#|3*2!XO7k1cCNx}1yMN2ywHPrk=U=;Gv6X70(-^w zj|wCIP`r>8iswi6#*Vb^*f%B#A0OREJ!dY4!~#Tg4EPTDYd=rU18-qWaAsTpX7(X} za-T|lpBfW@$<+CY(f*ha=|}c{tO@IjG2uQa4f8=ss5gqFHf)Hel00(HVV&4)av#;b z4YIm%ftPOVfPNKywE3?}zMWImA6pWGA4J%QZ&`Z^=t z#~E?nO%dbO1kq$3*;b@6`@uApIH2X|hL!k*{a<9f$QdE_fBNJ1KT2M>w*6ZF?fJ_X z5bk0N%s!yleMkId9LN~p9AKf8ub+v-1(B==6@^22jKk+?{t?(G_CGtE{KK#(t2fVp zkpGC@ivPQNo;7&OdQf5kvj1b|FE&8r4(5QbuU^8Ufn6}0=YnUF`wWhOY2+^ar^NVU z66b=6QGOUt?qkEfF*b~S#6rEu-b>X5E+qSWG8f71;ei}-AKlFzqsTprGJ@PQI=d-J zWAE_c_j`_6fdC(TCjQDY0IS75iw<#)u^M zh&GK7;#v<23P;|R{!dneVf24v4+^FKRgD2*?})!}*COLUY(KeMggx`Xf8;(v`PykX zIVJ%|^TTn3dVeTC60Zq+(SOMer~QA0++U`=MD8z=|1S0kJ;z$X|GZ59f;}T84xpI- z0{%+xdFD>)LeJ~lUa_BLWj{UEpL*|)Dbaq)511I?g9(&zioF->L3^Q;I$z9O(4vsG zDD2sW?Asu>yRdh+vTuzn)`=d`*%cYo_jGbkBllEtPocgKZQl~f>=`yBkkYO>&j2;U zK*ik|iR9kbrwRIcGe3;n<0vuY9^JMP**8LjM?-|WH$WKY{WqWAdbj$&i2*SBKl(KJ znDKp!%?6nL0L{KS{=#1KXMfo5nIHVYmPI&D=En;oaZH4|e?;`3>=l1<-%q{YH#!ur zjA9RA%AOHD@!HtI`115I@@D@(;cg!X*7jfT1J_Xhh5wOd(=jv3ll1@sFgwm4vnbPJ z{3yPdN}Zn)>4V9U-egY+_rf@G9~CdDFDt_vrExe_9F3Dj(Kt~UrPv=Uh`?d8Ka>}a*K)&fFeelT zvO}?dbZ@+p6@on(-SGFl+o1Z!N(@l;1FGUL?6t`JU(FcM^Zkabc+4aBxs*BNK0D42 zGh+?*)7U$DN|dno!6Ykt=?`eIZ%g)VZ0rkrx|6><>%zB2F6#tkcXh>RvdLiWP~g?%%!cgA3UXADy8o1j10_hVg#zU&>>hZ5)62(e@z)20EUJnEa+ z*F|sFy4W(QQ2M`45oT8VeK&5ze`NpXhtJdZx7cF9!d$Nb&HPP1phd>PW!6e&{@eR& zr{G*!EY1{1;Em!aoGOaMN$UM^au@c>{?gP$`_oMiezaM7D`eGLKenyNBrjh$J z>iiUPpB&+ZiQ%5?4auDU(6$)UyA8@hJW$%p1I6TC*rPQHy1OBt+;ho2o7_i}`zXrD zU>EXliHuGy$-V{IHz)h%7)I{NLSebY4mLI1TOB|Yl&>}xb%CX>-Y0~{;CEG2f%M@-^>2*@!i!tukyjQ z4G{K@_@8HuNA?H!`}%1($MXQ^N~3YMG>ZHq$v;x%gP$y<{pTETjNFgrg_3=5)&%X1 zSIPb0s9rc)+7I8b4inyf$IyG(2dF9+MCN`Gv;D7zzwG@;ec%PL-dNbjU-6$uou5PY zvuW>VQRinwd6T~vrbc>^y(jB}x5Wg?cyb>{?qfpSQA+M5b*&8B*+|$WDt$j0|#dAhVJ7)|HXiD}?kVNi-{2F5*nGc{OdN)J@ZGB(Q z2FwYsk2rFV@u-LB)^!op`e{VCJ&kbJItXpWKIVgBFnw^Oh5g^-g;iA?f8pOBZu93_ z+plg~YwQCFf6dt|SU)srzTB_os^@sQckK zQ4mJ{VFv$PD}SmpKQx=Nu z$N6GjtPkc;=Vwu7MtfsAxlfPu#8m41WOAPr)&>(oJrw(~z1&eoDe2i7#Wwz~$S3<; zvd`)4g3-Y(k!59{*|9k?Iy6H%*{8M__D!k#O_40@{Ts74WFs5<{?z$?4uSa3*_a_J?VT;p`WiB0XZrJ(=7GvscVu>ij_J`~a^8Nc60a zer@ZcZ`*q0Usu(Ij&XmQx?cy8JRcrGoeyjEBzm(>_{*!8Su#7fk^CN4E2AnI-i80T zzwYmx^5zYUFy?;p7xuT93-Y%mMYvoVjw|H;7Da9^a~xbOjl_kL2%IYp$61~YIa3&h z(*>b8$umJG@_OTVZV37J!s)U7@txG+VC>IUANF?qWiF8UU;6-h4CpyP^q%~c&T|ZW z!+N`G1_xnjUtj9J4;IDyDE2Z3%p-g05ipzfer9A_%pm(|!k*kGQznx8crqW?%MD|D zxMB>Yw0kQQcXJ_s7Zh}9iM-A&kQ>|r*+I=Qs#7y$b#%sv4o#8C`k)zsO^`XPoa6=68Zb0^|6YN=!?CYT~x%csSn(UuOEV)ZvfGF1|$^J=%yF7v3 z%^zca5a%t{l3{(%Y_hGcw*Or~uU}4-V^j?eD0rCADBbKM>2P^Ghj9$bON`{gnA+KQEf=KFTbzpUD~_)5AS5EzEf zki|+e5xXyJ{^dXS-lKfWX2E~0RsQZ;o)swSO}&q(QZ7>OsN_eJREomw%Cb%9!A1^YxT zquwu#_r~HlFY@=of*4QCk7|p#QEf0g!UMA?Gs4|5o!qB|w#F24pA_PTiM?DgzGo}y zz6-{%K3HkDmM9_nBC;I=C6xomL(1bmLnjoWHW26T(Vr|%lNFn!O zC@Q*wvyo>b# zR4=`)um{OtPO5)>^TjO1+;P;)+RRKY{F} zF5KAeEm21HrDR{+r8x?No1uV`7ew|QnKSsSB$Q*ILN1g2MY6w86ry^BoaY+w z%U5b+vm`Tujq2)Cy7!fLW#mEfcJOMjT9 zR{o1(+A8+*$$nm>hryrhXOjK&P&Z7Y-cM2NTVY~P7mV-GQn4S?tp!S{^QE1eqo{K; z@^?mlkTdegJ%{?9-J!9n4V@JzJ;E9yBcLJD$v)MuKH1m9FtShf7WPkLuxB0i2PAuP zPxN>a3DkM%6BtkKvDEn(N)&Zo`U8ej@1-ux)0VB*TVO1EhK=dkocx=ixU(~g zSSz$3s44P0H9>C2#$?|Jqscuhup#ThG(aY~r~B7OD!C6A_T)a4+>?Yoxeub=4U<)(Cs616ur7e~hlr)V$B=szbv~l`BM5b_jnaOhmc#3o!ufuuS#s?u|5xVx+l+z7 z-5+w=x|h8Tu8xaUeW5OK94IO1i5oM9;ntg6Cs<>_7QGi>&tGhSh>U^T@fRCl_5o@8 zRZi%KALHzbDXb0WgY}&2*OL1h%BpxztRQ!(54SYB4Hi>`|AL6tyOZU5y~bl=QhY=HEPKRN}1BL1txWGPWH_)zH2kGcSad?Ug`rE2RA_x>qHk& z=kuxaxvUYLO`RXj8sX9-Qn6=^_;l8Ym)bzXz3U*wi?zWh$(~PP2zx_Fe~5vc=li=q zj(%>BA;I-A>i(muE^I9O#6-7XubAd!&)P7916o*KTe}4QyvDrfPg$?Iy8geCf26l? zgHDhB=ImA0GX7-U6bmjie`62m zeSCfPBx?h;XI(%qRTt9e6Da(xeL|%+B-!geaf``b_%9&)d6c=rpX{YR==2a5RUcUR zPbPcm6FH$sq=4p@3ww4!uB}{SN=^DW z|2u}oeT+S~l+XG4lDUe#stYA!z^wmf{=#1KH;(~(Kfs} zHnT_IM$Y?E8+5(3Hk|YcG-^Y7s4<}WM3Vg?D}SRtEc?Wgy{ZpO+h0*1TKa@m)Q27; z{5v;ceefo%5#NM;0!05CvPXdM7yYlVdIbxA=?`J!Pn)mw-&6RrU$E#u*(?664{Gp# zl>Gl{;~z!#LzxR8dN0>ht}UTD>fQA3U|rRF%I9m~SNq=GFHbF_pLfYpX$%N^NBqrW zz|3BBUVH&N{>C2gd$_oA3bwIdpwx!k!ak9kIR+~D8?`}Y4v_k=D`HLjqpbXC|L4=^ z6aAk}`)||-Hu3M_h`-c_xAO1QNZJ29&H;x0lRw9RJ^$gf0V!TjsoIdqock4j)(EYN ze?*f9*&Cp@<&~wgwapj3|FyH%V?ylHQ{tz*BxB$L^G42{vsB6h(zzfq2iV&H;V*N5 zaF^d@3|Pe?q%xPrc);s3d_Hmv4v z^#LmJXMJ$-0qFNn?jiQys{i5xDE+@Zf8_&E|HTG~{Wp97Yo8!bgTK^=75)QSKaNDV zN0kle+v=}~Z&}+iGo_E^(AuTi*L#ZB^Ve$gHSoH)~eZ2;B#NW#PyNho!AA~tz>=7)rVMU}@xahyk0h_G$U-gQ%)`wor`F|z(%NUUQ z&`Zc)>I2)?hj!R2yn8d{1B|EtH;(*e4)|%WaPa|+Ug63Itkf&M!Ur5i_EH}tpoKK&_1AW zmvJE6wdi?(x~}#CStIBp*8h7UDL~0{LjqVAvWi~eT=!SkD|`vpewFx#yJ8O4eliEx zdd15cfcAe9*M7QJ{MfFVzhMK6HGs?kh7Xuc|KC^x(En5V&ozKe|Lefu|0MZ8S;1fY zfBJqIL9Uh~&#X{!J!@>|*RZ~?25*i2OU8i2sQhKW;41r;|3v>~4A}G6>`ifitE;DC z_h8>&*el$$1~BWttO3bh@wcu4r?F?aUIR{4Ye4${T>DFZ5T*YP*MKJe$_FHWUv2+| zzfm7Li9VoN|MPerRQ7VL@q9n)HT!qRc4`E;h7Xb$bu;c&t(rGDn)CS$i^PFcZIEjC zt9@XOfs^Bt@Y2vg?Dr;! zkUjwYKVuERSfBHQIJ9nwMfPyz+VC1VQ~q7?{2HSCc@MMhQPr-?8kDK+T6}hO2lMvX zBUbJI=rLej1Il>-T)U2M*t6*<&jY-|UhyxpM)XVMuX=?`eQ4GOevWMFn|8D#HLA}f-Cct zwoOmy#d-gVMU4SrPqD}??f>WO6@8FBq9I4tPf2)u$%RvpQj(N%f{c|s1Gh{ z0J1mudoczeHR2fuQZWGO5hDC022A~zIH2&S%;)?sYd{qTWE@}y`-B+$xdu@BZ;AnR zF=9X}4ya-PR{o6tR^~5pKofuK8gQ6b9b7xO*CP3P)|@R@>oxh`WbdmTA=W&lhaaxx z)F-TI?Q^@v=P|DPjz#$a*KVME^%VAsXTNxJeemH{{WtTc|EKhy>%eV{0qGb(h5lRl z+j_(p`fujHK=?}>*v8+*<^$?Apo#-?9Vlynv7G?sqlQ~6y-?fH1IRuA*ML_3Wn2eJ97xsxIu0mnKqC&seE{-L z_kNOj!L2Qu%0^24U7q!D{n(nHU&s30|DBir*Ye)H6iyHP<{l@P1`pg@6y5m2?~kpR zkB@h*v>X^N{UJJHpOyb!`T@fK#i8xUpYuQ0fV(J09LTpK4s4AB3V$63uILfOHGtyJ zH6V4rGJhiu{8Ro$98mG+7%<0yEAuzvz@q}F`+jwBX8U?|7Bi;FL*F;}!@WiF9p$@H znIC-#T&x9YzU15$BdGk>)Pr2Y$kwFaR5ryr=|z+3~!K2Sv*(C`6e z4lwTnC?AmQjW`hFfZYFAd%?nA)_)xvVhnS^rpLCk>|x#9cV9n@sjRsopZSUZavCAu z!TMcfZ2#xy&aQyi$lp;Oq2l<}z5ky4uqJ;gpTJt#S6EZ~%hz7CoS4i#fB|0E&OM;* z^!;^@pl4N|D6Rp?UdMrD4WM!XWFJ7S0VM_?djS#$w(?hTK-mW}`+&kwY*w7fak-zV0~O`tczt&u-MjE6X%ZA z-2Yn@=fQmdV;@lG0vIs>@&CB~mmGjz%`v@uQ%vsC5L3H5V@dx`cs3^y`(_qej;@@A zR~B&3acU{XvZkthhQ{|e&5_R}pG`ia^|SKV|NQ)mu7K=?$ylgOapv_7k=oXQe{y;! z*{9JrOGgj=?v3r6Zhijd8NBn#E?n5K5XTpe!T#~7tP>ZFt?41yklY3926e#Nfg+u- zF1agf#Ic@G=}_#ORfN;eEMmX!*YGuCk8kYSdTUuu%6G{=jlYrikoS`Jl=rrN2Kg-i zPwmg~^Zsx7AqurGF8;zJ+#ql9&^=B;kJNJNC%taGpZLRykY-ODh;y%hae#M|kA?-b z_&$v_Hlz=x^uo@fWU}5;dPmmEY}fMp0X|JXit}i2F{JsE2jsc(8uD85n)2H69u#>m z*^8I={?E^^?+VCVA$-JlkoCla6yf#+r5>dbMf~w*R*~Q3Z}NZg7aDT;p^@hb2_tiJDzhCj+ z>I0cRj`~2RkE1@2{e9ENQyCKYrl-=KK7>x4U0#emuXB`L29{+uX18 z_4oyEcfZot~7yLuY5gz`~TbhyL~g||K ztlv<*o#~2L=L_2#1Q^e^y+M(2Uw=dO?c`7UjTf}OJYfCAb*vB9pEy9@H(tQ@bn7Ru bzPmg~eS(UIt9P)yx_TA6`B?p}M*sXDRalY7 delta 1171 zcmb_bUr3Wt6u;lS`?mRy=H~pfx%s(TxJc0DrjyCk!V;lU6p9jZX{FG^f&yi-2_+a5 zj6;-A(u-k4Pb-j~^tB$s-m49I=pjO*zz6eo&fN-o=&cKv-}n2@Ilu4x&b{A<+vcy= z2N=_sU^W|}!LFDX3p2(Hqrg}2{Sv-wX(@6)V|`A>nlJ}LSW$S7z`9{0>K2!eM>7in zF*Oj&B%GPoZDJ%808NXCODCe)E^Uqrqm0A4h=};H2>cZNiuaoW@sUU~$*8rtPs*G{ z$~7TnT9cBofA2KLD2H;XW*cj%KLd9+Zt_JdZG#>?$hihqy;F?&bfjHGZ|c3`lu?4T zm1`R8=tCk>SBlgxeB~Ub&1Z$ouVxY+;lw2Yn7i7>#@nVFl`^@zH-QP9E4r_F!z?>V=z1K7}Ff&0Nv~|mfB$~ zw#`@r>{hwqsNQHwqYDT-4WF6^`NcVrRXiPb0rwxPe(b(iA0vTi}FCMS?LEB}612Khxb z9=k<@ylb(TAAl$B2dD-;Z(Ks|tix#ia!rLv!^ZwzXT0WYohQVFeCWsyHbg3moi4Sk zsA0Jw-uhT9oj#0{6-FrsPjFp~hxbE1_y`+6Af8SR!t#-Oyw-|?J0#X-;xO5Ehc~J@ zif2>9&>XtOJ*61!6yxoF*b2>Zy9H}|mEOy60*ChzDyv6fzWqEO@xoSY3Ql%>*DRTY zgZd)>slvsQl8z&WAn`cxcHuo^49^Mg9L}6DjRpx3SW2a<0z5%HKUJm*H;JQwLKMgm z$4=JvA_}I7Yclowp@4MHDWLv^|BGpo+oP|z2Je%Wa{99 Date: Mon, 4 Jul 2011 11:52:01 +0200 Subject: [PATCH 060/184] Added empty file to run unit tests --- testing/run.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 testing/run.py diff --git a/testing/run.py b/testing/run.py new file mode 100644 index 000000000..e69de29bb From 5b95657fbb027681c4b02490ddaafafda0e8a46d Mon Sep 17 00:00:00 2001 From: Martin Zibricky Date: Mon, 4 Jul 2011 13:27:20 +0200 Subject: [PATCH 061/184] Update windows build script to work with pyinstaller svn version (1.6dev) --- resources/windows/OpenLP.spec | 14 -------- scripts/windows-builder.py | 63 ++++++++++++++++++----------------- 2 files changed, 33 insertions(+), 44 deletions(-) delete mode 100644 resources/windows/OpenLP.spec diff --git a/resources/windows/OpenLP.spec b/resources/windows/OpenLP.spec deleted file mode 100644 index 47a1952f3..000000000 --- a/resources/windows/OpenLP.spec +++ /dev/null @@ -1,14 +0,0 @@ -# -*- mode: python -*- -a = Analysis([ - os.path.join(HOMEPATH, 'support\\_mountzlib.py'), - os.path.join(HOMEPATH, 'support\\useUnicode.py'), - os.path.abspath('openlp.pyw')], - pathex=[os.path.abspath('.')]) -pyz = PYZ(a.pure) -exe = EXE(pyz, a.scripts, exclude_binaries=1, - name=os.path.abspath(os.path.join('build', 'pyi.win32', 'OpenLP', - 'OpenLP.exe')), - debug=False, strip=False, upx=True, console=False, - icon=os.path.abspath(os.path.join('resources', 'images', 'OpenLP.ico'))) -coll = COLLECT(exe, a.binaries, a.zipfiles, a.datas, strip=False, upx=True, - name=os.path.abspath(os.path.join('dist', 'OpenLP'))) diff --git a/scripts/windows-builder.py b/scripts/windows-builder.py index 4ab31f893..dc08a3417 100644 --- a/scripts/windows-builder.py +++ b/scripts/windows-builder.py @@ -32,8 +32,7 @@ Windows Build Script This script is used to build the Windows binary and the accompanying installer. For this script to work out of the box, it depends on a number of things: -Python 2.6 - This build script only works with Python 2.6. +Python 2.6/2.7 PyQt4 You should already have this installed, OpenLP doesn't work without it. The @@ -49,7 +48,7 @@ Inno Setup 5 UPX This is used to compress DLLs and EXEs so that they take up less space, but - still function exactly the same. To install UPS, download it from + still function exactly the same. To install UPX, download it from http://upx.sourceforge.net/, extract it into C:\%PROGRAMFILES%\UPX, and then add that directory to your PATH environment variable. @@ -61,7 +60,7 @@ HTML Help Workshop This is used to create the help file PyInstaller - PyInstaller should be a checkout of revision 844 of trunk, and in a + PyInstaller should be a checkout of revision 1470 of trunk, and in a directory called, "pyinstaller" on the same level as OpenLP's Bazaar shared repository directory. The revision is very important as there is currently a major regression in HEAD. @@ -73,13 +72,8 @@ PyInstaller http://svn.pyinstaller.org/trunk Then you need to copy the two hook-*.py files from the "pyinstaller" - subdirectory in OpenLP's "resources" directory into PyInstaller's "hooks" - directory. - - Once you've done that, open a command prompt (DOS shell), navigate to the - PyInstaller directory and run:: - - C:\Projects\pyinstaller>python Configure.py + subdirectory in OpenLP's "resources" directory into PyInstaller's + "PyInstaller/hooks" directory. Bazaar You need the command line "bzr" client installed. @@ -137,9 +131,11 @@ site_packages = os.path.join(os.path.split(python_exe)[0], u'Lib', # Files and executables pyi_build = os.path.abspath(os.path.join(branch_path, u'..', u'..', - u'pyinstaller', u'Build.py')) + u'pyinstaller', u'pyinstaller.py')) +openlp_main_script = os.path.abspath(os.path.join(branch_path, 'openlp.pyw')) lrelease_exe = os.path.join(site_packages, u'PyQt4', u'bin', u'lrelease.exe') i18n_utils = os.path.join(script_path, u'translation_utils.py') +win32_icon = os.path.join(branch_path, u'resources', u'images', 'OpenLP.ico') # Paths source_path = os.path.join(branch_path, u'openlp') @@ -148,9 +144,9 @@ manual_build_path = os.path.join(manual_path, u'build') helpfile_path = os.path.join(manual_build_path, u'htmlhelp') i18n_path = os.path.join(branch_path, u'resources', u'i18n') winres_path = os.path.join(branch_path, u'resources', u'windows') -build_path = os.path.join(branch_path, u'build', u'pyi.win32', u'OpenLP') -dist_path = os.path.join(branch_path, u'dist', u'OpenLP') -enchant_path = os.path.join(site_packages, u'enchant') +build_path = os.path.join(branch_path, u'build') +dist_path = os.path.join(build_path, u'dist', u'OpenLP') +#enchant_path = os.path.join(site_packages, u'enchant') pptviewlib_path = os.path.join(source_path, u'plugins', u'presentations', u'lib', u'pptviewlib') @@ -174,8 +170,15 @@ def update_code(): def run_pyinstaller(): print u'Running PyInstaller...' os.chdir(branch_path) - pyinstaller = Popen((python_exe, pyi_build, u'-y', u'-o', build_path, - os.path.join(winres_path, u'OpenLP.spec')), stdout=PIPE) + pyinstaller = Popen((python_exe, pyi_build, + u'--noconfirm', + u'--windowed', + u'-o', build_path, + u'-i', win32_icon, + u'-p', branch_path, + u'-n', 'OpenLP', + openlp_main_script), + stdout=PIPE) output, error = pyinstaller.communicate() code = pyinstaller.wait() if code != 0: @@ -208,18 +211,18 @@ def write_version_file(): f.write(versionstring) f.close() -def copy_enchant(): - print u'Copying enchant/pyenchant...' - source = enchant_path - dest = os.path.join(dist_path, u'enchant') - for root, dirs, files in os.walk(source): - for filename in files: - if not filename.endswith(u'.pyc') and not filename.endswith(u'.pyo'): - dest_path = os.path.join(dest, root[len(source) + 1:]) - if not os.path.exists(dest_path): - os.makedirs(dest_path) - copy(os.path.join(root, filename), - os.path.join(dest_path, filename)) +#def copy_enchant(): + #print u'Copying enchant/pyenchant...' + #source = enchant_path + #dest = os.path.join(dist_path, u'enchant') + #for root, dirs, files in os.walk(source): + #for filename in files: + #if not filename.endswith(u'.pyc') and not filename.endswith(u'.pyo'): + #dest_path = os.path.join(dest, root[len(source) + 1:]) + #if not os.path.exists(dest_path): + #os.makedirs(dest_path) + #copy(os.path.join(root, filename), + #os.path.join(dest_path, filename)) def copy_plugins(): print u'Copying plugins...' @@ -353,7 +356,7 @@ def main(): build_pptviewlib() run_pyinstaller() write_version_file() - copy_enchant() + #copy_enchant() copy_plugins() if os.path.exists(manual_path): run_sphinx() From a039a50005444b6f479319bbf0128e295d94d66f Mon Sep 17 00:00:00 2001 From: Martin Zibricky Date: Mon, 4 Jul 2011 14:04:50 +0200 Subject: [PATCH 062/184] Update formating and remove dead enchant code --- scripts/windows-builder.py | 31 ++++++++----------------------- 1 file changed, 8 insertions(+), 23 deletions(-) diff --git a/scripts/windows-builder.py b/scripts/windows-builder.py index dc08a3417..d6f4d42e3 100644 --- a/scripts/windows-builder.py +++ b/scripts/windows-builder.py @@ -146,7 +146,6 @@ i18n_path = os.path.join(branch_path, u'resources', u'i18n') winres_path = os.path.join(branch_path, u'resources', u'windows') build_path = os.path.join(branch_path, u'build') dist_path = os.path.join(build_path, u'dist', u'OpenLP') -#enchant_path = os.path.join(site_packages, u'enchant') pptviewlib_path = os.path.join(source_path, u'plugins', u'presentations', u'lib', u'pptviewlib') @@ -171,14 +170,14 @@ def run_pyinstaller(): print u'Running PyInstaller...' os.chdir(branch_path) pyinstaller = Popen((python_exe, pyi_build, - u'--noconfirm', - u'--windowed', - u'-o', build_path, - u'-i', win32_icon, - u'-p', branch_path, - u'-n', 'OpenLP', - openlp_main_script), - stdout=PIPE) + u'--noconfirm', + u'--windowed', + u'-o', build_path, + u'-i', win32_icon, + u'-p', branch_path, + u'-n', 'OpenLP', + openlp_main_script), + stdout=PIPE) output, error = pyinstaller.communicate() code = pyinstaller.wait() if code != 0: @@ -211,19 +210,6 @@ def write_version_file(): f.write(versionstring) f.close() -#def copy_enchant(): - #print u'Copying enchant/pyenchant...' - #source = enchant_path - #dest = os.path.join(dist_path, u'enchant') - #for root, dirs, files in os.walk(source): - #for filename in files: - #if not filename.endswith(u'.pyc') and not filename.endswith(u'.pyo'): - #dest_path = os.path.join(dest, root[len(source) + 1:]) - #if not os.path.exists(dest_path): - #os.makedirs(dest_path) - #copy(os.path.join(root, filename), - #os.path.join(dest_path, filename)) - def copy_plugins(): print u'Copying plugins...' source = os.path.join(source_path, u'plugins') @@ -356,7 +342,6 @@ def main(): build_pptviewlib() run_pyinstaller() write_version_file() - #copy_enchant() copy_plugins() if os.path.exists(manual_path): run_sphinx() From 36b9c2e386e9c69342cf1853240252dd5f45f77e Mon Sep 17 00:00:00 2001 From: Martin Zibricky Date: Mon, 4 Jul 2011 15:26:39 +0200 Subject: [PATCH 063/184] Remove folder for tests. --- testing/run.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 testing/run.py diff --git a/testing/run.py b/testing/run.py deleted file mode 100644 index e69de29bb..000000000 From 4bf45ad2defe7018062c65abdc1b586e7d241c2e Mon Sep 17 00:00:00 2001 From: Benny Date: Mon, 4 Jul 2011 22:51:43 +0200 Subject: [PATCH 064/184] ewimport: workaround for RTF stripping bug --- openlp/plugins/songs/lib/ewimport.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/openlp/plugins/songs/lib/ewimport.py b/openlp/plugins/songs/lib/ewimport.py index 95533ba94..a50c97f47 100644 --- a/openlp/plugins/songs/lib/ewimport.py +++ b/openlp/plugins/songs/lib/ewimport.py @@ -44,6 +44,14 @@ def strip_rtf(blob, encoding): control = False clear_text = [] control_word = [] + + # workaround for \tx bug: remove one pair of curly braces if \tx is encountered + p = re.compile(r'\{\\tx[^}]*\}') + m = p.search(blob) + if m: + # start and end indices of match are curly braces - filter them out + blob = ''.join([blob[i] for i in xrange(len(blob)) if i != m.start() and i !=m.end()]) + for c in blob: if control: # for delimiters, set control to False From 3c0c9c5b781d80899f1b73543a085c779bfc9ac8 Mon Sep 17 00:00:00 2001 From: Benny Date: Tue, 5 Jul 2011 00:55:57 +0200 Subject: [PATCH 065/184] EasyWorship importer: some work to create more reasonable verse numbers if EW tags are missing or without numbers --- openlp/plugins/songs/lib/ewimport.py | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/openlp/plugins/songs/lib/ewimport.py b/openlp/plugins/songs/lib/ewimport.py index a50c97f47..18b87f9c0 100644 --- a/openlp/plugins/songs/lib/ewimport.py +++ b/openlp/plugins/songs/lib/ewimport.py @@ -267,18 +267,18 @@ class EasyWorshipSongImport(SongImport): self.add_author(author_name.strip()) if words: # Format the lyrics - words = strip_rtf(words, self.encoding) # TODO: convert rtf instead of stripping? - p = re.compile(r'\n *?\n[\n ]*') # at least two newlines, with zero or more space characters between them - verse_type = VerseType.Tags[VerseType.Verse] # TODO!!!: use previous verse type.... + words = strip_rtf(words, self.encoding) # TODO: convert rtf to display tags? + # regex: at least two newlines, with zero or more space characters between them + p = re.compile(r'\n *?\n[\n ]*') + verse_type = VerseType.Tags[VerseType.Verse] for verse in p.split(words): - #for verse in words.split(u'\n\n'): - # ew tags: verse, chorus, pre-chorus, bridge, tag, intro, ending, slide verse = verse.strip() if len(verse) == 0: continue verse_split = verse.split(u'\n', 1) first_line_is_tag = False - for type in VerseType.Names+['tag', 'slide']: # doesnt cover tag, slide + # ew tags: verse, chorus, pre-chorus, bridge, tag, intro, ending, slide + for type in VerseType.Names+['tag', 'slide']: type = type.lower() ew_tag = verse_split[0].strip().lower() if ew_tag.startswith(type): @@ -286,20 +286,24 @@ class EasyWorshipSongImport(SongImport): if type == 'tag' or type == 'slide': verse_type = VerseType.Tags[VerseType.Other] first_line_is_tag = True + number_found = False if len(ew_tag) > len(type): # tag is followed by number and/or note p = re.compile(r'[0-9]+') m = re.search(p, ew_tag) if m: number = m.group() verse_type +=number + number_found = True p = re.compile(r'\(.*?\)') m = re.search(p, ew_tag) if m: self.comments += ew_tag+'\n' + if not number_found: + verse_type += '1' break self.add_verse( - verse_split[-1].strip() if first_line_is_tag else verse, # TODO: hacky: -1 + verse_split[-1].strip() if first_line_is_tag else verse, verse_type) if len(self.comments) > 5: self.comments += unicode(translate('SongsPlugin.EasyWorshipSongImport', From 6436b05240635a5b5c3fd4675e32fad3bf46c7d4 Mon Sep 17 00:00:00 2001 From: Benny Date: Tue, 5 Jul 2011 12:50:55 +0200 Subject: [PATCH 066/184] changes from review (cosmetic & regex performance) --- openlp/plugins/songs/lib/ewimport.py | 54 +++++++++++++++------------- 1 file changed, 30 insertions(+), 24 deletions(-) diff --git a/openlp/plugins/songs/lib/ewimport.py b/openlp/plugins/songs/lib/ewimport.py index 18b87f9c0..732c6e4f0 100644 --- a/openlp/plugins/songs/lib/ewimport.py +++ b/openlp/plugins/songs/lib/ewimport.py @@ -39,18 +39,25 @@ from openlp.plugins.songs.lib import VerseType from openlp.plugins.songs.lib import retrieve_windows_encoding from songimport import SongImport +RTF_STRIPPING_REGEX = re.compile(r'\{\\tx[^}]*\}') +# regex: at least two newlines, can have spaces between them +SLIDE_BREAK_REGEX = re.compile(r'\n *?\n[\n ]*') +NUMBER_REGEX = re.compile(r'[0-9]+') +NOTE_REGEX = re.compile(r'\(.*?\)') + def strip_rtf(blob, encoding): depth = 0 control = False clear_text = [] control_word = [] - # workaround for \tx bug: remove one pair of curly braces if \tx is encountered - p = re.compile(r'\{\\tx[^}]*\}') - m = p.search(blob) - if m: + # workaround for \tx bug: remove one pair of curly braces + # if \tx is encountered + match = RTF_STRIPPING_REGEX.search(blob) + if match: # start and end indices of match are curly braces - filter them out - blob = ''.join([blob[i] for i in xrange(len(blob)) if i != m.start() and i !=m.end()]) + blob = ''.join([blob[i] for i in xrange(len(blob)) + if i != match.start() and i !=match.end()]) for c in blob: if control: @@ -267,17 +274,16 @@ class EasyWorshipSongImport(SongImport): self.add_author(author_name.strip()) if words: # Format the lyrics - words = strip_rtf(words, self.encoding) # TODO: convert rtf to display tags? - # regex: at least two newlines, with zero or more space characters between them - p = re.compile(r'\n *?\n[\n ]*') + words = strip_rtf(words, self.encoding) verse_type = VerseType.Tags[VerseType.Verse] - for verse in p.split(words): + for verse in SLIDE_BREAK_REGEX.split(words): verse = verse.strip() if len(verse) == 0: continue - verse_split = verse.split(u'\n', 1) + verse_split = verse.split(u'\n', 1) first_line_is_tag = False - # ew tags: verse, chorus, pre-chorus, bridge, tag, intro, ending, slide + # EW tags: verse, chorus, pre-chorus, bridge, tag, + # intro, ending, slide for type in VerseType.Names+['tag', 'slide']: type = type.lower() ew_tag = verse_split[0].strip().lower() @@ -287,27 +293,27 @@ class EasyWorshipSongImport(SongImport): verse_type = VerseType.Tags[VerseType.Other] first_line_is_tag = True number_found = False - if len(ew_tag) > len(type): # tag is followed by number and/or note - p = re.compile(r'[0-9]+') - m = re.search(p, ew_tag) - if m: - number = m.group() + # check if tag is followed by number and/or note + if len(ew_tag) > len(type): + match = NUMBER_REGEX.search(ew_tag) + if match: + number = match.group() verse_type +=number number_found = True - - p = re.compile(r'\(.*?\)') - m = re.search(p, ew_tag) - if m: - self.comments += ew_tag+'\n' + match = NOTE_REGEX.search(ew_tag) + if match: + self.comments += ew_tag + u'\n' if not number_found: - verse_type += '1' + verse_type += u'1' break self.add_verse( verse_split[-1].strip() if first_line_is_tag else verse, verse_type) if len(self.comments) > 5: - self.comments += unicode(translate('SongsPlugin.EasyWorshipSongImport', - '\n[above are Song Tags with notes imported from EasyWorship]')) + self.comments += unicode( + translate('SongsPlugin.EasyWorshipSongImport', + '\n[above are Song Tags with notes imported from \ + EasyWorship]')) if self.stop_import_flag: break if not self.finish(): From 1876d520ae4a23899210c6ca5efe3ee474a588ac Mon Sep 17 00:00:00 2001 From: Benny Date: Tue, 5 Jul 2011 14:00:34 +0200 Subject: [PATCH 067/184] review fixes --- openlp/plugins/songs/lib/ewimport.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/openlp/plugins/songs/lib/ewimport.py b/openlp/plugins/songs/lib/ewimport.py index 732c6e4f0..448d629d5 100644 --- a/openlp/plugins/songs/lib/ewimport.py +++ b/openlp/plugins/songs/lib/ewimport.py @@ -278,18 +278,18 @@ class EasyWorshipSongImport(SongImport): verse_type = VerseType.Tags[VerseType.Verse] for verse in SLIDE_BREAK_REGEX.split(words): verse = verse.strip() - if len(verse) == 0: + if not verse: continue verse_split = verse.split(u'\n', 1) first_line_is_tag = False # EW tags: verse, chorus, pre-chorus, bridge, tag, # intro, ending, slide - for type in VerseType.Names+['tag', 'slide']: + for type in VerseType.Names+[u'tag', u'slide']: type = type.lower() ew_tag = verse_split[0].strip().lower() if ew_tag.startswith(type): verse_type = type[0] - if type == 'tag' or type == 'slide': + if type == u'tag' or type == u'slide': verse_type = VerseType.Tags[VerseType.Other] first_line_is_tag = True number_found = False @@ -298,7 +298,7 @@ class EasyWorshipSongImport(SongImport): match = NUMBER_REGEX.search(ew_tag) if match: number = match.group() - verse_type +=number + verse_type += number number_found = True match = NOTE_REGEX.search(ew_tag) if match: From 439b5592698bcda0cb195a1ee5e8576b2bd674c3 Mon Sep 17 00:00:00 2001 From: Raoul Snyman Date: Tue, 5 Jul 2011 22:17:17 +0200 Subject: [PATCH 068/184] Add main script path, make paths more readable. --- scripts/windows-builder.py | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/scripts/windows-builder.py b/scripts/windows-builder.py index d6f4d42e3..f1d53e600 100644 --- a/scripts/windows-builder.py +++ b/scripts/windows-builder.py @@ -96,7 +96,7 @@ psvince.dll the install will fail. The dll can be obtained from here: http://www.vincenzo.net/isxkb/index.php?title=PSVince) -Mako +Mako Mako Templates for Python. This package is required for building the remote plugin. It can be installed by going to your python_directory\scripts\.. and running "easy_install Mako". If you do not @@ -319,17 +319,19 @@ def main(): import sys for arg in sys.argv: if arg == u'-v' or arg == u'--verbose': - print "Script path:", script_path - print "Branch path:", branch_path - print "Source path:", source_path - print "\"dist\" path:", dist_path - print "PyInstaller:", pyi_build + print "OpenLP main script: ......", openlp_main_script + print "Script path: .............", script_path + print "Branch path: .............", branch_path + print "Source path: .............", source_path + print "\"dist\" path: .............", dist_path + print "PyInstaller: .............", pyi_build print "Documentation branch path:", doc_branch_path - print "Help file build path;", helpfile_path - print "Inno Setup path:", innosetup_exe - print "Windows resources:", winres_path - print "VCBuild path:", vcbuild_exe - print "PPTVIEWLIB path:", pptviewlib_path + print "Help file build path: ....", helpfile_path + print "Inno Setup path: .........", innosetup_exe + print "Windows resources: .......", winres_path + print "VCBuild path: ............", vcbuild_exe + print "PPTVIEWLIB path: .........", pptviewlib_path + print "" elif arg == u'--skip-update': skip_update = True elif arg == u'/?' or arg == u'-h' or arg == u'--help': From 447016c1892247fc7a32619546bc110c82614269 Mon Sep 17 00:00:00 2001 From: Raoul Snyman Date: Wed, 6 Jul 2011 20:36:33 +0200 Subject: [PATCH 069/184] Updated Windows build script to work with new PyInstaller and PyQt4 locations. --- scripts/windows-builder.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/scripts/windows-builder.py b/scripts/windows-builder.py index f1d53e600..be1a5fd3e 100644 --- a/scripts/windows-builder.py +++ b/scripts/windows-builder.py @@ -133,7 +133,10 @@ site_packages = os.path.join(os.path.split(python_exe)[0], u'Lib', pyi_build = os.path.abspath(os.path.join(branch_path, u'..', u'..', u'pyinstaller', u'pyinstaller.py')) openlp_main_script = os.path.abspath(os.path.join(branch_path, 'openlp.pyw')) -lrelease_exe = os.path.join(site_packages, u'PyQt4', u'bin', u'lrelease.exe') +if os.path.exists(os.path.join(site_packages, u'PyQt4', u'bin')): + lrelease_exe = os.path.join(site_packages, u'PyQt4', u'bin', u'lrelease.exe') +else: + lrelease_exe = os.path.join(site_packages, u'PyQt4', u'lrelease.exe') i18n_utils = os.path.join(script_path, u'translation_utils.py') win32_icon = os.path.join(branch_path, u'resources', u'images', 'OpenLP.ico') @@ -145,7 +148,7 @@ helpfile_path = os.path.join(manual_build_path, u'htmlhelp') i18n_path = os.path.join(branch_path, u'resources', u'i18n') winres_path = os.path.join(branch_path, u'resources', u'windows') build_path = os.path.join(branch_path, u'build') -dist_path = os.path.join(build_path, u'dist', u'OpenLP') +dist_path = os.path.join(branch_path, u'dist', u'OpenLP') pptviewlib_path = os.path.join(source_path, u'plugins', u'presentations', u'lib', u'pptviewlib') @@ -172,7 +175,7 @@ def run_pyinstaller(): pyinstaller = Popen((python_exe, pyi_build, u'--noconfirm', u'--windowed', - u'-o', build_path, + u'-o', branch_path, #build_path, u'-i', win32_icon, u'-p', branch_path, u'-n', 'OpenLP', From 3e8c91cbd593c47d655c086f85331837e7c7e5e4 Mon Sep 17 00:00:00 2001 From: Andreas Preikschat Date: Thu, 7 Jul 2011 16:53:05 +0200 Subject: [PATCH 070/184] refactor some code --- openlp/core/lib/imagemanager.py | 45 ++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 21 deletions(-) diff --git a/openlp/core/lib/imagemanager.py b/openlp/core/lib/imagemanager.py index 5970efd4f..61be16b91 100644 --- a/openlp/core/lib/imagemanager.py +++ b/openlp/core/lib/imagemanager.py @@ -112,17 +112,29 @@ class PriorityQueue(Queue.PriorityQueue): """ Customised ``Queue.PriorityQueue``. """ - def remove(self, item): + def modify_priority(self, image, new_priority): """ - Removes the given ``item`` from the queue. + Modifies the priority of the given ``image``. - ``item`` - The item to remove. This should be a tuple:: + ``image`` + The image to remove. This should be an ``Image`` instance. - ``(Priority, Image)`` + ``new_priority`` + The new priority for the image. """ - if item in self.queue: - self.queue.remove(item) + self.remove(image) + image.priority = new_priority + self.put((image.priority, image)) + + def remove(self, image): + """ + Removes the given ``image`` from the queue. + + ``image`` + The image to remove. This should be an ``Image`` instance. + """ + if (image.priority, image) in self.queue: + self.queue.remove((image.priority, image)) class ImageManager(QtCore.QObject): @@ -168,9 +180,7 @@ class ImageManager(QtCore.QObject): log.debug(u'get_image %s' % name) image = self._cache[name] if image.image is None: - self._conversion_queue.remove((image.priority, image)) - image.priority = Priority.High - self._conversion_queue.put((image.priority, image)) + self._conversion_queue.modify_priority(image, Priority.High) while image.image is None: log.debug(u'get_image - waiting') time.sleep(0.1) @@ -184,9 +194,7 @@ class ImageManager(QtCore.QObject): log.debug(u'get_image_bytes %s' % name) image = self._cache[name] if image.image_bytes is None: - self._conversion_queue.remove((image.priority, image)) - image.priority = Priority.Urgent - self._conversion_queue.put((image.priority, image)) + self._conversion_queue.modify_priority(image, Priority.Urgent) while image.image_bytes is None: log.debug(u'get_image_bytes - waiting') time.sleep(0.1) @@ -198,8 +206,7 @@ class ImageManager(QtCore.QObject): """ log.debug(u'del_image %s' % name) if name in self._cache: - self._conversion_queue.remove( - (self._cache[name].priority, self._cache[name])) + self._conversion_queue.remove(self._cache[name]) del self._cache[name] def add_image(self, name, path): @@ -238,18 +245,14 @@ class ImageManager(QtCore.QObject): # Set the priority to Lowest and stop here as we need to process # more important images first. if image.priority == Priority.Normal: - self._conversion_queue.remove((image.priority, image)) - image.priority = Priority.Lowest - self._conversion_queue.put((image.priority, image)) + self._conversion_queue.modify_priority(image, Priority.Lowest) return # For image with high priority we set the priority to Low, as the # byte stream might be needed earlier the byte stream of image with # Normal priority. We stop here as we need to process more important # images first. elif image.priority == Priority.High: - self._conversion_queue.remove((image.priority, image)) - image.priority = Priority.Low - self._conversion_queue.put((image.priority, image)) + self._conversion_queue.modify_priority(image, Priority.Low) return # Generate the byte stream for the image. if image.image_bytes is None: From 2b419d8a4eb279ca5a4af5f3f73561539f540c62 Mon Sep 17 00:00:00 2001 From: Andreas Preikschat Date: Thu, 7 Jul 2011 17:15:48 +0200 Subject: [PATCH 071/184] implementation fix: set priority to low instead of lowerest when the image was requested --- openlp/core/lib/imagemanager.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/openlp/core/lib/imagemanager.py b/openlp/core/lib/imagemanager.py index 61be16b91..bde464586 100644 --- a/openlp/core/lib/imagemanager.py +++ b/openlp/core/lib/imagemanager.py @@ -184,6 +184,12 @@ class ImageManager(QtCore.QObject): while image.image is None: log.debug(u'get_image - waiting') time.sleep(0.1) + elif image.image_bytes is None: + # Set the priority to Low, because the image was requested but the + # byte stream was not generated yet. However, we only need to do + # this, when the image was generated before it was requested + # (otherwise this is already taken care of). + self._conversion_queue.modify_priority(image, Priority.Low) return image.image def get_image_bytes(self, name): From 1ffd5713b03b67ee35ac4d8e4678b4772b6c5147 Mon Sep 17 00:00:00 2001 From: Stevan Pettit Date: Thu, 7 Jul 2011 11:23:55 -0400 Subject: [PATCH 072/184] Modified slide controller to change loop button icons when selecting slide loops --- openlp/core/lib/ui.py | 4 ++++ openlp/core/ui/slidecontroller.py | 22 ++++++++++++++++++---- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/openlp/core/lib/ui.py b/openlp/core/lib/ui.py index 973c76660..1d7f8ae3f 100644 --- a/openlp/core/lib/ui.py +++ b/openlp/core/lib/ui.py @@ -103,6 +103,8 @@ class UiStrings(object): self.OpenLPStart = translate('OpenLP.Ui', 'OpenLP is already running. ' 'Do you wish to continue?') self.OpenService = translate('OpenLP.Ui', 'Open service.') + self.PlaySlidesInLoop = translate('OpenLP.Ui','Play Slides in Loop') + self.PlaySlidesToEnd = translate('OpenLP.Ui','Play Slides to End') self.Preview = translate('OpenLP.Ui', 'Preview') self.PrintService = translate('OpenLP.Ui', 'Print Service') self.ReplaceBG = translate('OpenLP.Ui', 'Replace Background') @@ -124,6 +126,8 @@ class UiStrings(object): self.SplitToolTip = translate('OpenLP.Ui', 'Split a slide into two ' 'only if it does not fit on the screen as one slide.') self.StartTimeCode = unicode(translate('OpenLP.Ui', 'Start %s')) + self.StopPlaySlidesInLoop = translate('OpenLP.Ui','Stop Play Slides in Loop') + self.StopPlaySlidesToEnd = translate('OpenLP.Ui','Stop Play Slides to End') self.Theme = translate('OpenLP.Ui', 'Theme', 'Singular') self.Themes = translate('OpenLP.Ui', 'Themes', 'Plural') self.Tools = translate('OpenLP.Ui', 'Tools') diff --git a/openlp/core/ui/slidecontroller.py b/openlp/core/ui/slidecontroller.py index 8e2c199a1..57e14179a 100644 --- a/openlp/core/ui/slidecontroller.py +++ b/openlp/core/ui/slidecontroller.py @@ -193,13 +193,11 @@ class SlideController(QtGui.QWidget): self.playSlidesLoop = shortcut_action(self.playSlidesMenu, u'playSlidesLoop', [], self.onPlaySlidesLoop, u':/media/media_time.png', False, UiStrings().LiveToolbar) - self.playSlidesLoop.setText( - translate('OpenLP.SlideController', 'Play Slides in Loop')) + self.playSlidesLoop.setText(UiStrings().PlaySlidesInLoop) self.playSlidesOnce = shortcut_action(self.playSlidesMenu, u'playSlidesOnce', [], self.onPlaySlidesOnce, u':/media/media_time.png', False, UiStrings().LiveToolbar) - self.playSlidesOnce.setText( - translate('OpenLP.SlideController', 'Play Slides to End')) + self.playSlidesOnce.setText(UiStrings().PlaySlidesToEnd) if QtCore.QSettings().value(self.parent().generalSettingsSection + u'/enable slide loop', QtCore.QVariant(True)).toBool(): self.playSlidesMenu.setDefaultAction(self.playSlidesLoop) @@ -1056,6 +1054,14 @@ class SlideController(QtGui.QWidget): else: self.playSlidesLoop.setChecked(checked) log.debug(u'onPlaySlidesLoop %s' % checked) + if checked: + self.playSlidesLoop.setIcon(QtGui.QIcon(u':/media/media_stop.png')) + self.playSlidesLoop.setText(UiStrings().StopPlaySlidesInLoop) + self.playSlidesOnce.setIcon(QtGui.QIcon(u':/media/media_time.png')) + self.playSlidesOnce.setText(UiStrings().PlaySlidesToEnd) + else: + self.playSlidesLoop.setIcon(QtGui.QIcon(u':/media/media_time.png')) + self.playSlidesLoop.setText(UiStrings().PlaySlidesInLoop) self.playSlidesMenu.setDefaultAction(self.playSlidesLoop) self.playSlidesOnce.setChecked(False) self.onToggleLoop() @@ -1069,6 +1075,14 @@ class SlideController(QtGui.QWidget): else: self.playSlidesOnce.setChecked(checked) log.debug(u'onPlaySlidesOnce %s' % checked) + if checked: + self.playSlidesOnce.setIcon(QtGui.QIcon(u':/media/media_stop.png')) + self.playSlidesOnce.setText(UiStrings().StopPlaySlidesToEnd) + self.playSlidesLoop.setIcon(QtGui.QIcon(u':/media/media_time.png')) + self.playSlidesLoop.setText(UiStrings().PlaySlidesInLoop) + else: + self.playSlidesOnce.setIcon(QtGui.QIcon(u':/media/media_time')) + self.playSlidesOnce.setText(UiStrings().PlaySlidesToEnd) self.playSlidesMenu.setDefaultAction(self.playSlidesOnce) self.playSlidesLoop.setChecked(False) self.onToggleLoop() From f7ab82518bad72f66cc96540b28137412e2988f0 Mon Sep 17 00:00:00 2001 From: Andreas Preikschat Date: Thu, 7 Jul 2011 17:37:43 +0200 Subject: [PATCH 073/184] doc --- openlp/core/lib/imagemanager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openlp/core/lib/imagemanager.py b/openlp/core/lib/imagemanager.py index bde464586..37d1de79c 100644 --- a/openlp/core/lib/imagemanager.py +++ b/openlp/core/lib/imagemanager.py @@ -120,7 +120,7 @@ class PriorityQueue(Queue.PriorityQueue): The image to remove. This should be an ``Image`` instance. ``new_priority`` - The new priority for the image. + The image's new priority. """ self.remove(image) image.priority = new_priority From 37fdcc62a4cafab83919aeabfebe30a92568d911 Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Thu, 7 Jul 2011 18:03:38 +0100 Subject: [PATCH 074/184] Fix comment --- openlp/plugins/songs/lib/mediaitem.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openlp/plugins/songs/lib/mediaitem.py b/openlp/plugins/songs/lib/mediaitem.py index e9335a684..a2814a1df 100644 --- a/openlp/plugins/songs/lib/mediaitem.py +++ b/openlp/plugins/songs/lib/mediaitem.py @@ -387,7 +387,8 @@ class SongMediaItem(MediaManagerItem): new_song_id = self.openLyrics.xml_to_song(song_xml) new_song = self.plugin.manager.get_object(Song, new_song_id) new_song.title = u'%s <%s>' % (new_song.title, - translate('SongsPlugin.MediaItem', 'copy')) + translate('SongsPlugin.MediaItem', 'copy', + 'For song cloning')) self.plugin.manager.save_object(new_song) self.onSongListLoad() From 856d44270f1e98d322102d5a738c46263579b548 Mon Sep 17 00:00:00 2001 From: Stevan Pettit Date: Thu, 7 Jul 2011 13:38:13 -0400 Subject: [PATCH 075/184] Changed use of Qicon to build_icon in slidecontroller --- openlp/core/ui/slidecontroller.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/openlp/core/ui/slidecontroller.py b/openlp/core/ui/slidecontroller.py index 57e14179a..0068a7d75 100644 --- a/openlp/core/ui/slidecontroller.py +++ b/openlp/core/ui/slidecontroller.py @@ -32,7 +32,7 @@ from PyQt4 import QtCore, QtGui from PyQt4.phonon import Phonon from openlp.core.lib import OpenLPToolbar, Receiver, resize_image, \ - ItemCapabilities, translate + ItemCapabilities, translate, build_icon from openlp.core.lib.ui import UiStrings, shortcut_action from openlp.core.ui import HideMode, MainDisplay, ScreenList from openlp.core.utils.actions import ActionList, CategoryOrder @@ -1055,12 +1055,12 @@ class SlideController(QtGui.QWidget): self.playSlidesLoop.setChecked(checked) log.debug(u'onPlaySlidesLoop %s' % checked) if checked: - self.playSlidesLoop.setIcon(QtGui.QIcon(u':/media/media_stop.png')) + self.playSlidesLoop.setIcon(build_icon(u':/media/media_stop.png')) self.playSlidesLoop.setText(UiStrings().StopPlaySlidesInLoop) - self.playSlidesOnce.setIcon(QtGui.QIcon(u':/media/media_time.png')) + self.playSlidesOnce.setIcon(build_icon(u':/media/media_time.png')) self.playSlidesOnce.setText(UiStrings().PlaySlidesToEnd) else: - self.playSlidesLoop.setIcon(QtGui.QIcon(u':/media/media_time.png')) + self.playSlidesLoop.setIcon(build_icon(u':/media/media_time.png')) self.playSlidesLoop.setText(UiStrings().PlaySlidesInLoop) self.playSlidesMenu.setDefaultAction(self.playSlidesLoop) self.playSlidesOnce.setChecked(False) @@ -1076,12 +1076,12 @@ class SlideController(QtGui.QWidget): self.playSlidesOnce.setChecked(checked) log.debug(u'onPlaySlidesOnce %s' % checked) if checked: - self.playSlidesOnce.setIcon(QtGui.QIcon(u':/media/media_stop.png')) + self.playSlidesOnce.setIcon(build_icon(u':/media/media_stop.png')) self.playSlidesOnce.setText(UiStrings().StopPlaySlidesToEnd) - self.playSlidesLoop.setIcon(QtGui.QIcon(u':/media/media_time.png')) + self.playSlidesLoop.setIcon(build_icon(u':/media/media_time.png')) self.playSlidesLoop.setText(UiStrings().PlaySlidesInLoop) else: - self.playSlidesOnce.setIcon(QtGui.QIcon(u':/media/media_time')) + self.playSlidesOnce.setIcon(build_icon(u':/media/media_time')) self.playSlidesOnce.setText(UiStrings().PlaySlidesToEnd) self.playSlidesMenu.setDefaultAction(self.playSlidesOnce) self.playSlidesLoop.setChecked(False) From 623b56742c291cec32263d8ea6b198f75dc4ebf7 Mon Sep 17 00:00:00 2001 From: Jon Tibble Date: Thu, 7 Jul 2011 19:03:12 +0100 Subject: [PATCH 076/184] Cleanups --- openlp/core/lib/pluginmanager.py | 2 +- openlp/core/lib/spelltextedit.py | 2 +- openlp/core/lib/theme.py | 3 +-- openlp/core/ui/displaytagdialog.py | 2 +- openlp/core/ui/firsttimewizard.py | 6 +++--- openlp/core/ui/settingsform.py | 2 +- openlp/core/ui/slidecontroller.py | 4 ++-- openlp/plugins/alerts/alertsplugin.py | 2 +- openlp/plugins/bibles/forms/bibleimportform.py | 3 +-- openlp/plugins/bibles/forms/bibleupgradeform.py | 3 +-- openlp/plugins/bibles/lib/db.py | 2 +- openlp/plugins/bibles/lib/http.py | 4 +--- openlp/plugins/bibles/lib/manager.py | 2 +- openlp/plugins/songs/lib/db.py | 2 +- openlp/plugins/songs/lib/easislidesimport.py | 3 --- openlp/plugins/songs/lib/ewimport.py | 1 - openlp/plugins/songs/lib/songbeamerimport.py | 1 - openlp/plugins/songs/lib/songimport.py | 3 +-- openlp/plugins/songs/lib/wowimport.py | 1 - openlp/plugins/songusage/songusageplugin.py | 2 +- 20 files changed, 19 insertions(+), 31 deletions(-) diff --git a/openlp/core/lib/pluginmanager.py b/openlp/core/lib/pluginmanager.py index 7a54b4c64..2248d0ddd 100644 --- a/openlp/core/lib/pluginmanager.py +++ b/openlp/core/lib/pluginmanager.py @@ -31,7 +31,7 @@ import os import sys import logging -from openlp.core.lib import Plugin, StringContent, PluginStatus +from openlp.core.lib import Plugin, PluginStatus log = logging.getLogger(__name__) diff --git a/openlp/core/lib/spelltextedit.py b/openlp/core/lib/spelltextedit.py index 57a176a69..0d277b9fe 100644 --- a/openlp/core/lib/spelltextedit.py +++ b/openlp/core/lib/spelltextedit.py @@ -57,7 +57,7 @@ class SpellTextEdit(QtGui.QPlainTextEdit): self.dictionary = enchant.Dict() self.highlighter = Highlighter(self.document()) self.highlighter.spellingDictionary = self.dictionary - except Error, DictNotFoundError: + except (Error, DictNotFoundError): ENCHANT_AVAILABLE = False log.debug(u'Could not load default dictionary') diff --git a/openlp/core/lib/theme.py b/openlp/core/lib/theme.py index 7ad50490d..c87f9aa2e 100644 --- a/openlp/core/lib/theme.py +++ b/openlp/core/lib/theme.py @@ -34,8 +34,7 @@ import logging from xml.dom.minidom import Document from lxml import etree, objectify -from openlp.core.lib import str_to_bool, translate -from openlp.core.lib.ui import UiStrings +from openlp.core.lib import str_to_bool log = logging.getLogger(__name__) diff --git a/openlp/core/ui/displaytagdialog.py b/openlp/core/ui/displaytagdialog.py index 65e900bbb..328fcd137 100644 --- a/openlp/core/ui/displaytagdialog.py +++ b/openlp/core/ui/displaytagdialog.py @@ -28,7 +28,7 @@ from PyQt4 import QtCore, QtGui from openlp.core.lib import translate -from openlp.core.lib.ui import UiStrings, create_accept_reject_button_box +from openlp.core.lib.ui import UiStrings class Ui_DisplayTagDialog(object): diff --git a/openlp/core/ui/firsttimewizard.py b/openlp/core/ui/firsttimewizard.py index 3644ed07b..59fe41537 100644 --- a/openlp/core/ui/firsttimewizard.py +++ b/openlp/core/ui/firsttimewizard.py @@ -49,7 +49,7 @@ class Ui_FirstTimeWizard(object): FirstTimeWizard.resize(550, 386) FirstTimeWizard.setModal(True) FirstTimeWizard.setWizardStyle(QtGui.QWizard.ModernStyle) - FirstTimeWizard.setOptions(QtGui.QWizard.IndependentPages| + FirstTimeWizard.setOptions(QtGui.QWizard.IndependentPages | QtGui.QWizard.NoBackButtonOnStartPage | QtGui.QWizard.NoBackButtonOnLastPage) self.finishButton = self.button(QtGui.QWizard.FinishButton) @@ -81,9 +81,9 @@ class Ui_FirstTimeWizard(object): self.pluginLayout.addWidget(self.imageCheckBox) self.presentationCheckBox = QtGui.QCheckBox(self.pluginPage) if sys.platform == "darwin": - self.presentationCheckBox.setChecked(False) + self.presentationCheckBox.setChecked(False) else: - self.presentationCheckBox.setChecked(True) + self.presentationCheckBox.setChecked(True) self.presentationCheckBox.setObjectName(u'presentationCheckBox') self.pluginLayout.addWidget(self.presentationCheckBox) self.mediaCheckBox = QtGui.QCheckBox(self.pluginPage) diff --git a/openlp/core/ui/settingsform.py b/openlp/core/ui/settingsform.py index 711cac7c2..49d27a466 100644 --- a/openlp/core/ui/settingsform.py +++ b/openlp/core/ui/settingsform.py @@ -29,7 +29,7 @@ The :mod:`settingsform` provides a user interface for the OpenLP settings """ import logging -from PyQt4 import QtGui, QtCore +from PyQt4 import QtGui from openlp.core.lib import Receiver, build_icon, PluginStatus from openlp.core.ui import AdvancedTab, GeneralTab, ThemesTab diff --git a/openlp/core/ui/slidecontroller.py b/openlp/core/ui/slidecontroller.py index 8e2c199a1..03a35b1fb 100644 --- a/openlp/core/ui/slidecontroller.py +++ b/openlp/core/ui/slidecontroller.py @@ -31,8 +31,8 @@ import os from PyQt4 import QtCore, QtGui from PyQt4.phonon import Phonon -from openlp.core.lib import OpenLPToolbar, Receiver, resize_image, \ - ItemCapabilities, translate +from openlp.core.lib import OpenLPToolbar, Receiver, ItemCapabilities, \ + translate from openlp.core.lib.ui import UiStrings, shortcut_action from openlp.core.ui import HideMode, MainDisplay, ScreenList from openlp.core.utils.actions import ActionList, CategoryOrder diff --git a/openlp/plugins/alerts/alertsplugin.py b/openlp/plugins/alerts/alertsplugin.py index 41c2e2211..19d5107f2 100644 --- a/openlp/plugins/alerts/alertsplugin.py +++ b/openlp/plugins/alerts/alertsplugin.py @@ -27,7 +27,7 @@ import logging -from PyQt4 import QtCore, QtGui +from PyQt4 import QtCore from openlp.core.lib import Plugin, StringContent, build_icon, translate from openlp.core.lib.db import Manager diff --git a/openlp/plugins/bibles/forms/bibleimportform.py b/openlp/plugins/bibles/forms/bibleimportform.py index de1574eaa..b5478e514 100644 --- a/openlp/plugins/bibles/forms/bibleimportform.py +++ b/openlp/plugins/bibles/forms/bibleimportform.py @@ -27,7 +27,6 @@ """ The bible import functions for OpenLP """ -import csv import logging import os import os.path @@ -39,7 +38,7 @@ from openlp.core.lib import Receiver, translate from openlp.core.lib.db import delete_database from openlp.core.lib.ui import UiStrings, critical_error_message_box from openlp.core.ui.wizard import OpenLPWizard, WizardStrings -from openlp.core.utils import AppLocation, string_is_unicode +from openlp.core.utils import AppLocation from openlp.plugins.bibles.lib.manager import BibleFormat from openlp.plugins.bibles.lib.db import BiblesResourcesDB, clean_filename diff --git a/openlp/plugins/bibles/forms/bibleupgradeform.py b/openlp/plugins/bibles/forms/bibleupgradeform.py index 14936a340..d396bce8d 100644 --- a/openlp/plugins/bibles/forms/bibleupgradeform.py +++ b/openlp/plugins/bibles/forms/bibleupgradeform.py @@ -28,7 +28,6 @@ The bible import functions for OpenLP """ import logging import os.path -import re import shutil from PyQt4 import QtCore, QtGui @@ -39,7 +38,7 @@ from openlp.core.lib.db import delete_database from openlp.core.lib.ui import UiStrings, critical_error_message_box from openlp.core.ui.wizard import OpenLPWizard, WizardStrings from openlp.core.utils import AppLocation, delete_file -from openlp.plugins.bibles.lib.db import BibleDB, BibleMeta, OldBibleDB,\ +from openlp.plugins.bibles.lib.db import BibleDB, BibleMeta, OldBibleDB, \ BiblesResourcesDB, clean_filename from openlp.plugins.bibles.lib.http import BSExtract, BGExtract, CWExtract diff --git a/openlp/plugins/bibles/lib/db.py b/openlp/plugins/bibles/lib/db.py index 68f105dff..5273f670c 100644 --- a/openlp/plugins/bibles/lib/db.py +++ b/openlp/plugins/bibles/lib/db.py @@ -36,7 +36,7 @@ from sqlalchemy import Column, ForeignKey, or_, Table, types from sqlalchemy.orm import class_mapper, mapper, relation from sqlalchemy.orm.exc import UnmappedClassError -from openlp.core.lib import Receiver, translate, check_directory_exists +from openlp.core.lib import Receiver, translate from openlp.core.lib.db import BaseModel, init_db, Manager from openlp.core.lib.ui import critical_error_message_box from openlp.core.utils import AppLocation diff --git a/openlp/plugins/bibles/lib/http.py b/openlp/plugins/bibles/lib/http.py index 03b094e82..8a46b75c4 100644 --- a/openlp/plugins/bibles/lib/http.py +++ b/openlp/plugins/bibles/lib/http.py @@ -29,9 +29,7 @@ The :mod:`http` module enables OpenLP to retrieve scripture from bible websites. """ import logging -import os import re -import sqlite3 import socket import urllib from HTMLParser import HTMLParseError @@ -40,7 +38,7 @@ from BeautifulSoup import BeautifulSoup, NavigableString, Tag from openlp.core.lib import Receiver, translate from openlp.core.lib.ui import critical_error_message_box -from openlp.core.utils import AppLocation, get_web_page +from openlp.core.utils import get_web_page from openlp.plugins.bibles.lib import SearchResults from openlp.plugins.bibles.lib.db import BibleDB, BiblesResourcesDB, \ Book diff --git a/openlp/plugins/bibles/lib/manager.py b/openlp/plugins/bibles/lib/manager.py index 9a0b20820..354332083 100644 --- a/openlp/plugins/bibles/lib/manager.py +++ b/openlp/plugins/bibles/lib/manager.py @@ -34,7 +34,7 @@ from openlp.core.lib import Receiver, SettingsManager, translate from openlp.core.lib.ui import critical_error_message_box from openlp.core.utils import AppLocation, delete_file from openlp.plugins.bibles.lib import parse_reference -from openlp.plugins.bibles.lib.db import BibleDB, BibleMeta, OldBibleDB +from openlp.plugins.bibles.lib.db import BibleDB, BibleMeta from csvbible import CSVBible from http import HTTPBible from opensong import OpenSongBible diff --git a/openlp/plugins/songs/lib/db.py b/openlp/plugins/songs/lib/db.py index 93d56a05a..c5c019c3c 100644 --- a/openlp/plugins/songs/lib/db.py +++ b/openlp/plugins/songs/lib/db.py @@ -29,7 +29,7 @@ The :mod:`db` module provides the database and schema that is the backend for the Songs plugin """ -from sqlalchemy import Column, ForeignKey, Index, Table, types +from sqlalchemy import Column, ForeignKey, Table, types from sqlalchemy.orm import mapper, relation from openlp.core.lib.db import BaseModel, init_db diff --git a/openlp/plugins/songs/lib/easislidesimport.py b/openlp/plugins/songs/lib/easislidesimport.py index b1eaceeaf..b24287130 100644 --- a/openlp/plugins/songs/lib/easislidesimport.py +++ b/openlp/plugins/songs/lib/easislidesimport.py @@ -26,13 +26,10 @@ ############################################################################### import logging -import os import re from lxml import etree, objectify -from openlp.core.lib import translate -from openlp.core.ui.wizard import WizardStrings from openlp.plugins.songs.lib import VerseType from openlp.plugins.songs.lib.songimport import SongImport diff --git a/openlp/plugins/songs/lib/ewimport.py b/openlp/plugins/songs/lib/ewimport.py index 09f84fbe2..251068fb4 100644 --- a/openlp/plugins/songs/lib/ewimport.py +++ b/openlp/plugins/songs/lib/ewimport.py @@ -33,7 +33,6 @@ import os import struct from openlp.core.lib import translate -from openlp.core.ui.wizard import WizardStrings from openlp.plugins.songs.lib import VerseType from openlp.plugins.songs.lib import retrieve_windows_encoding from songimport import SongImport diff --git a/openlp/plugins/songs/lib/songbeamerimport.py b/openlp/plugins/songs/lib/songbeamerimport.py index 3a8d63783..400db8f9a 100644 --- a/openlp/plugins/songs/lib/songbeamerimport.py +++ b/openlp/plugins/songs/lib/songbeamerimport.py @@ -36,7 +36,6 @@ import re from openlp.plugins.songs.lib import VerseType from openlp.plugins.songs.lib.songimport import SongImport -from openlp.plugins.songs.lib.ui import SongStrings log = logging.getLogger(__name__) diff --git a/openlp/plugins/songs/lib/songimport.py b/openlp/plugins/songs/lib/songimport.py index 781321fe4..dc45764e4 100644 --- a/openlp/plugins/songs/lib/songimport.py +++ b/openlp/plugins/songs/lib/songimport.py @@ -29,9 +29,8 @@ import re from PyQt4 import QtCore -from openlp.core.lib import Receiver, translate, check_directory_exists +from openlp.core.lib import Receiver, translate from openlp.core.ui.wizard import WizardStrings -from openlp.core.utils import AppLocation from openlp.plugins.songs.lib import clean_song, VerseType from openlp.plugins.songs.lib.db import Song, Author, Topic, Book, MediaFile from openlp.plugins.songs.lib.ui import SongStrings diff --git a/openlp/plugins/songs/lib/wowimport.py b/openlp/plugins/songs/lib/wowimport.py index 0648abe66..e2a5820a5 100644 --- a/openlp/plugins/songs/lib/wowimport.py +++ b/openlp/plugins/songs/lib/wowimport.py @@ -31,7 +31,6 @@ Worship songs into the OpenLP database. import os import logging -from openlp.core.ui.wizard import WizardStrings from openlp.plugins.songs.lib.songimport import SongImport BLOCK_TYPES = (u'V', u'C', u'B') diff --git a/openlp/plugins/songusage/songusageplugin.py b/openlp/plugins/songusage/songusageplugin.py index 7304b5196..c94b70554 100644 --- a/openlp/plugins/songusage/songusageplugin.py +++ b/openlp/plugins/songusage/songusageplugin.py @@ -33,7 +33,7 @@ from PyQt4 import QtCore, QtGui from openlp.core.lib import Plugin, StringContent, Receiver, build_icon, \ translate from openlp.core.lib.db import Manager -from openlp.core.lib.ui import base_action, shortcut_action, UiStrings +from openlp.core.lib.ui import base_action, shortcut_action from openlp.core.utils.actions import ActionList from openlp.plugins.songusage.forms import SongUsageDetailForm, \ SongUsageDeleteForm From e6cf76b7b98f6ed966ee880a99cc3a4c6a8e4229 Mon Sep 17 00:00:00 2001 From: Raoul Snyman Date: Thu, 7 Jul 2011 20:18:35 +0200 Subject: [PATCH 077/184] Added comments for explanation of some code. Fixed the build directory due to the new way PyInstaller works. --- scripts/windows-builder.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/scripts/windows-builder.py b/scripts/windows-builder.py index be1a5fd3e..9c96fe251 100644 --- a/scripts/windows-builder.py +++ b/scripts/windows-builder.py @@ -134,8 +134,12 @@ pyi_build = os.path.abspath(os.path.join(branch_path, u'..', u'..', u'pyinstaller', u'pyinstaller.py')) openlp_main_script = os.path.abspath(os.path.join(branch_path, 'openlp.pyw')) if os.path.exists(os.path.join(site_packages, u'PyQt4', u'bin')): + # Older versions of the PyQt4 Windows installer put their binaries in the + # "bin" directory lrelease_exe = os.path.join(site_packages, u'PyQt4', u'bin', u'lrelease.exe') else: + # Newer versions of the PyQt4 Windows installer put their binaries in the + # base directory of the installation lrelease_exe = os.path.join(site_packages, u'PyQt4', u'lrelease.exe') i18n_utils = os.path.join(script_path, u'translation_utils.py') win32_icon = os.path.join(branch_path, u'resources', u'images', 'OpenLP.ico') @@ -175,7 +179,7 @@ def run_pyinstaller(): pyinstaller = Popen((python_exe, pyi_build, u'--noconfirm', u'--windowed', - u'-o', branch_path, #build_path, + u'-o', branch_path, u'-i', win32_icon, u'-p', branch_path, u'-n', 'OpenLP', From 1899961965967246797083071f1da707099e6d18 Mon Sep 17 00:00:00 2001 From: Jon Tibble Date: Thu, 7 Jul 2011 22:22:41 +0100 Subject: [PATCH 078/184] Long lines --- openlp/core/ui/mainwindow.py | 6 +++--- openlp/core/ui/shortcutlistform.py | 6 ++++-- openlp/plugins/bibles/lib/mediaitem.py | 3 ++- openlp/plugins/remotes/lib/httpserver.py | 3 ++- 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/openlp/core/ui/mainwindow.py b/openlp/core/ui/mainwindow.py index e850ef335..b182452bc 100644 --- a/openlp/core/ui/mainwindow.py +++ b/openlp/core/ui/mainwindow.py @@ -291,9 +291,9 @@ class Ui_MainWindow(object): self.onHelpLocalHelpClicked, u':/system/system_about.png', category=UiStrings().Help) self.helpOnlineHelpItem = shortcut_action( - mainWindow, u'helpOnlineHelpItem', [QtGui.QKeySequence(u'Alt+F1')], - self.onHelpOnlineHelpClicked, u':/system/system_online_help.png', - category=UiStrings().Help) + mainWindow, u'helpOnlineHelpItem', + [QtGui.QKeySequence(u'Alt+F1')], self.onHelpOnlineHelpClicked, + u':/system/system_online_help.png', category=UiStrings().Help) else: self.helpOnlineHelpItem = shortcut_action( mainWindow, u'helpOnlineHelpItem', [QtGui.QKeySequence(u'F1')], diff --git a/openlp/core/ui/shortcutlistform.py b/openlp/core/ui/shortcutlistform.py index 6bdcc46bc..1eccddc95 100644 --- a/openlp/core/ui/shortcutlistform.py +++ b/openlp/core/ui/shortcutlistform.py @@ -247,7 +247,8 @@ class ShortcutListForm(QtGui.QDialog, Ui_ShortcutListDialog): alternate_label_text = action.defaultShortcuts[1].toString() shortcuts = self._actionShortcuts(action) # We do not want to loose pending changes, that is why we have to - # keep the text when, this function has not been triggered by a signal. + # keep the text when, this function has not been triggered by a + # signal. if item is None: primary_text = self.primaryPushButton.text() alternate_text = self.alternatePushButton.text() @@ -280,7 +281,8 @@ class ShortcutListForm(QtGui.QDialog, Ui_ShortcutListDialog): """ Restores all default shortcuts. """ - if self.buttonBox.buttonRole(button) != QtGui.QDialogButtonBox.ResetRole: + if self.buttonBox.buttonRole(button) != \ + QtGui.QDialogButtonBox.ResetRole: return if QtGui.QMessageBox.question(self, translate('OpenLP.ShortcutListDialog', 'Restore Default Shortcuts'), diff --git a/openlp/plugins/bibles/lib/mediaitem.py b/openlp/plugins/bibles/lib/mediaitem.py index cb8273327..1c731ec6e 100644 --- a/openlp/plugins/bibles/lib/mediaitem.py +++ b/openlp/plugins/bibles/lib/mediaitem.py @@ -983,7 +983,8 @@ class BibleMediaItem(MediaManagerItem): Search for some Bible verses (by reference). """ bible = unicode(self.quickVersionComboBox.currentText()) - search_results = self.plugin.manager.get_verses(bible, string, False, False) + search_results = self.plugin.manager.get_verses( + bible, string, False, False) if search_results: versetext = u' '.join([verse.text for verse in search_results]) return [[string, versetext]] diff --git a/openlp/plugins/remotes/lib/httpserver.py b/openlp/plugins/remotes/lib/httpserver.py index 34271019d..836b3d0ae 100644 --- a/openlp/plugins/remotes/lib/httpserver.py +++ b/openlp/plugins/remotes/lib/httpserver.py @@ -357,7 +357,8 @@ class HttpConnection(object): if ext == u'.html': mimetype = u'text/html' variables = self.template_vars - html = Template(filename=path, input_encoding=u'utf-8', output_encoding=u'utf-8').render(**variables) + html = Template(filename=path, input_encoding=u'utf-8', + output_encoding=u'utf-8').render(**variables) elif ext == u'.css': mimetype = u'text/css' elif ext == u'.js': From ce1abaf3322ffd09a03461b7365a950f0ab6445b Mon Sep 17 00:00:00 2001 From: Raoul Snyman Date: Fri, 8 Jul 2011 07:57:39 +0200 Subject: [PATCH 079/184] Fixed bug #803031: If UTF-8 decoding fails, try the standard Windows codepage. --- openlp/plugins/bibles/lib/http.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/openlp/plugins/bibles/lib/http.py b/openlp/plugins/bibles/lib/http.py index 03b094e82..28ceaad68 100644 --- a/openlp/plugins/bibles/lib/http.py +++ b/openlp/plugins/bibles/lib/http.py @@ -147,7 +147,10 @@ class BGExtract(object): send_error_message(u'download') return None page_source = page.read() - page_source = unicode(page_source, 'utf8') + try: + page_source = unicode(page_source, u'utf8') + except UnicodeDecodeError: + page_source = unicode(page_source, u'cp1251') page_source_temp = re.search(u'.*?'\ u'
', page_source, re.DOTALL) if page_source_temp: From 1a611dcd6088d1edd1f56807bd9301a64e020212 Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Fri, 8 Jul 2011 07:03:09 +0100 Subject: [PATCH 080/184] Add tooltip --- openlp/plugins/songusage/songusageplugin.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/openlp/plugins/songusage/songusageplugin.py b/openlp/plugins/songusage/songusageplugin.py index ad79870b8..b94c57346 100644 --- a/openlp/plugins/songusage/songusageplugin.py +++ b/openlp/plugins/songusage/songusageplugin.py @@ -181,10 +181,14 @@ class SongUsagePlugin(Plugin): self.songUsageActiveButton.setIcon(self.activeIcon) self.songUsageStatus.setChecked(True) self.songUsageActiveButton.setChecked(True) + self.songUsageActiveButton.setToolTip(translate('SongUsagePlugin', + 'Song usage is active.')) else: self.songUsageActiveButton.setIcon(self.inactiveIcon) self.songUsageStatus.setChecked(False) self.songUsageActiveButton.setChecked(False) + self.songUsageActiveButton.setToolTip(translate('SongUsagePlugin', + 'Song usage is inactive.')) self.songUsageActiveButton.blockSignals(False) self.songUsageStatus.blockSignals(False) From 897f7a7dbbda3b379b8b33ca7f9aa725e63a06ee Mon Sep 17 00:00:00 2001 From: Raoul Snyman Date: Fri, 8 Jul 2011 08:31:34 +0200 Subject: [PATCH 081/184] Fixed bug #794971: Typecast the buffer object to a unicode object. --- openlp/plugins/songs/lib/__init__.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/openlp/plugins/songs/lib/__init__.py b/openlp/plugins/songs/lib/__init__.py index 308ff6aa1..409564553 100644 --- a/openlp/plugins/songs/lib/__init__.py +++ b/openlp/plugins/songs/lib/__init__.py @@ -267,6 +267,10 @@ def clean_song(manager, song): ``song`` The song object. """ + if not isinstance(song.title, basestring): + song.title = unicode(song.title) + if not isinstance(song.lyrics, basestring): + song.lyrics = unicode(song.lyrics) song.title = song.title.rstrip() if song.title else u'' if song.alternate_title is None: song.alternate_title = u'' From 5581a74034097a98abd8d5c055daba4a1afc123d Mon Sep 17 00:00:00 2001 From: Raoul Snyman Date: Fri, 8 Jul 2011 08:40:50 +0200 Subject: [PATCH 082/184] Changed typecast to rather check for buffer. --- openlp/plugins/songs/lib/__init__.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/openlp/plugins/songs/lib/__init__.py b/openlp/plugins/songs/lib/__init__.py index 409564553..e2996ff8f 100644 --- a/openlp/plugins/songs/lib/__init__.py +++ b/openlp/plugins/songs/lib/__init__.py @@ -267,9 +267,11 @@ def clean_song(manager, song): ``song`` The song object. """ - if not isinstance(song.title, basestring): + if isinstance(song.title, buffer): song.title = unicode(song.title) - if not isinstance(song.lyrics, basestring): + if isinstance(song.alternate_title, buffer): + song.alternate_title = unicode(song.alternate_title) + if isinstance(song.lyrics, buffer): song.lyrics = unicode(song.lyrics) song.title = song.title.rstrip() if song.title else u'' if song.alternate_title is None: From f264cc4c4e0be7f2d6880eb1254a26ca78f1a067 Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Fri, 8 Jul 2011 16:07:53 +0100 Subject: [PATCH 083/184] correct tooltip text --- openlp/plugins/songusage/songusageplugin.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openlp/plugins/songusage/songusageplugin.py b/openlp/plugins/songusage/songusageplugin.py index b94c57346..575295f37 100644 --- a/openlp/plugins/songusage/songusageplugin.py +++ b/openlp/plugins/songusage/songusageplugin.py @@ -182,13 +182,13 @@ class SongUsagePlugin(Plugin): self.songUsageStatus.setChecked(True) self.songUsageActiveButton.setChecked(True) self.songUsageActiveButton.setToolTip(translate('SongUsagePlugin', - 'Song usage is active.')) + 'Song usage tracking is active.')) else: self.songUsageActiveButton.setIcon(self.inactiveIcon) self.songUsageStatus.setChecked(False) self.songUsageActiveButton.setChecked(False) self.songUsageActiveButton.setToolTip(translate('SongUsagePlugin', - 'Song usage is inactive.')) + 'Song usage tracking is inactive.')) self.songUsageActiveButton.blockSignals(False) self.songUsageStatus.blockSignals(False) From b94115d4b29e80874abd724aff076e9e39f6bb2c Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Fri, 8 Jul 2011 21:55:18 +0100 Subject: [PATCH 084/184] Amend tooltips so show theme for service item if present. Fixes: https://launchpad.net/bugs/806834 --- openlp/core/ui/servicemanager.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/openlp/core/ui/servicemanager.py b/openlp/core/ui/servicemanager.py index cccbed399..e46a6f0f8 100644 --- a/openlp/core/ui/servicemanager.py +++ b/openlp/core/ui/servicemanager.py @@ -956,7 +956,14 @@ class ServiceManager(QtGui.QWidget): treewidgetitem.setIcon(0, build_icon(u':/general/general_delete.png')) treewidgetitem.setText(0, serviceitem.get_display_title()) - treewidgetitem.setToolTip(0, serviceitem.notes) + tips = [] + if serviceitem.theme and serviceitem.theme != -1: + tips.append(unicode(translate('OpenLP.ServiceManager', + 'Slide theme : %s')) % serviceitem.theme) + if serviceitem.notes: + tips.append(unicode(translate('OpenLP.ServiceManager', + 'Notes : %s')) % unicode(serviceitem.notes)) + treewidgetitem.setToolTip(0, u'\n'.join(tips)) treewidgetitem.setData(0, QtCore.Qt.UserRole, QtCore.QVariant(item[u'order'])) treewidgetitem.setSelected(item[u'selected']) From cf9355d7250cbc5af51b68b0442740600fb8c009 Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Sat, 9 Jul 2011 07:03:52 +0100 Subject: [PATCH 085/184] Add some formatting --- openlp/core/ui/servicemanager.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/openlp/core/ui/servicemanager.py b/openlp/core/ui/servicemanager.py index e46a6f0f8..f22ff6fc8 100644 --- a/openlp/core/ui/servicemanager.py +++ b/openlp/core/ui/servicemanager.py @@ -957,13 +957,16 @@ class ServiceManager(QtGui.QWidget): build_icon(u':/general/general_delete.png')) treewidgetitem.setText(0, serviceitem.get_display_title()) tips = [] + # does not work with tooltips it needs if serviceitem.theme and serviceitem.theme != -1: - tips.append(unicode(translate('OpenLP.ServiceManager', - 'Slide theme : %s')) % serviceitem.theme) + tips.append(u'%s : %s' % + (unicode(translate('OpenLP.ServiceManager', 'Slide theme')), + serviceitem.theme)) if serviceitem.notes: - tips.append(unicode(translate('OpenLP.ServiceManager', - 'Notes : %s')) % unicode(serviceitem.notes)) - treewidgetitem.setToolTip(0, u'\n'.join(tips)) + tips.append(u'%s : %s' % + (unicode(translate('OpenLP.ServiceManager', 'Notes')), + unicode(serviceitem.notes))) + treewidgetitem.setToolTip(0, u'
'.join(tips)) treewidgetitem.setData(0, QtCore.Qt.UserRole, QtCore.QVariant(item[u'order'])) treewidgetitem.setSelected(item[u'selected']) From e9fb8e59c16b212060fa5c0da3186f438cadba03 Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Sat, 9 Jul 2011 08:43:35 +0100 Subject: [PATCH 086/184] Allow service item themes to change and be added back to slide controller Break object link between saved item in slide controller and service manager. Fixes: https://launchpad.net/bugs/806829 --- openlp/core/lib/serviceitem.py | 14 ++++++++++++++ openlp/core/ui/servicemanager.py | 2 +- openlp/core/ui/slidecontroller.py | 4 +++- 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/openlp/core/lib/serviceitem.py b/openlp/core/lib/serviceitem.py index ad762e326..0810e292d 100644 --- a/openlp/core/lib/serviceitem.py +++ b/openlp/core/lib/serviceitem.py @@ -352,6 +352,9 @@ class ServiceItem(object): Updates the _uuid with the value from the original one The _uuid is unique for a given service item but this allows one to replace an original version. + + ``other`` + The service item to be merged with """ self._uuid = other._uuid self.notes = other.notes @@ -461,3 +464,14 @@ class ServiceItem(object): else: return u'%s : %s' % (start, end) + def update_theme(self, theme): + """ + updates the theme in the service item + + ``theme`` + The new theme to be replaced in the service item + """ + self.theme = theme + self._new_item() + self.render() + diff --git a/openlp/core/ui/servicemanager.py b/openlp/core/ui/servicemanager.py index f22ff6fc8..88dc0603a 100644 --- a/openlp/core/ui/servicemanager.py +++ b/openlp/core/ui/servicemanager.py @@ -1348,7 +1348,7 @@ class ServiceManager(QtGui.QWidget): if not theme: theme = None item = self.findServiceItem()[0] - self.serviceItems[item][u'service_item'].theme = theme + self.serviceItems[item][u'service_item'].update_theme(theme) self.regenerateServiceItems() def _getParentItemData(self, item): diff --git a/openlp/core/ui/slidecontroller.py b/openlp/core/ui/slidecontroller.py index e86e2e760..8a7912b01 100644 --- a/openlp/core/ui/slidecontroller.py +++ b/openlp/core/ui/slidecontroller.py @@ -28,6 +28,7 @@ import logging import os import time +import copy from PyQt4 import QtCore, QtGui from PyQt4.phonon import Phonon @@ -600,7 +601,8 @@ class SlideController(QtGui.QWidget): log.debug(u'processManagerItem live = %s' % self.isLive) self.onStopLoop() old_item = self.serviceItem - self.serviceItem = serviceItem + # take a copy not a link to the servicemeanager copy. + self.serviceItem = copy.copy(serviceItem) if old_item and self.isLive and old_item.is_capable( ItemCapabilities.ProvidesOwnDisplay): self._resetBlank() From a71ea86e4d93bde6ecb7d4e48e4456fbfae3021c Mon Sep 17 00:00:00 2001 From: Martin Zibricky Date: Sat, 9 Jul 2011 16:51:06 +0200 Subject: [PATCH 087/184] add script to check openlp dependencies --- scripts/check_dependencies.py | 148 ++++++++++++++++++++++++++++++++++ 1 file changed, 148 insertions(+) create mode 100755 scripts/check_dependencies.py diff --git a/scripts/check_dependencies.py b/scripts/check_dependencies.py new file mode 100755 index 000000000..967ff2185 --- /dev/null +++ b/scripts/check_dependencies.py @@ -0,0 +1,148 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4 + +############################################################################### +# OpenLP - Open Source Lyrics Projection # +# --------------------------------------------------------------------------- # +# Copyright (c) 2011 Raoul Snyman # +# --------------------------------------------------------------------------- # +# 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 # +############################################################################### + +""" +This script is used to check dependencies of OpenLP. It checks availability +of required python modules and their version. To verify availability of Python +modules, simply run this script:: + + @:~$ ./check_dependencies.py + +""" +import os +import sys + +is_win = sys.platform.startswith('win') + +VERS = { + 'Python': '2.6', + 'PyQt4': '4.6', + 'Qt4': '4.6', + 'sqlalchemy': '0.5', + # pyenchant 1.6 required on Windows + 'enchant': '1.6' if is_win else '1.3' + } + +# pywin32 +WIN32_MODULES = [ + 'win32com', + 'win32ui', + 'pywintypes', + ] + +MODULES = [ + 'PyQt4', + 'PyQt4.QtCore', + 'PyQt4.QtGui', + 'PyQt4.QtNetwork', + 'PyQt4.QtOpenGL', + 'PyQt4.QtSvg', + 'PyQt4.QtTest', + 'PyQt4.QtWebKit', + 'PyQt4.phonon', + 'sqlalchemy', + 'sqlite3', + 'lxml', + 'chardet', + 'enchant', + 'BeautifulSoup', + 'mako', + ] + + +OPTIONAL_MODULES = [ + ('sqlite', ' (SQLite 2 support)'), + ('MySQLdb', ' (MySQL support)'), + ('psycopg2', ' (PostgreSQL support)'), + ] + +w = sys.stdout.write + + +def check_vers(version, required, text): + if type(version) is str: + version = version.split('.') + version = [int(x) for x in version] + if type(required) is str: + required = required.split('.') + required = [int(x) for x in required] + w(' %s >= %s ... ' % (text, '.'.join([str(x) for x in required]))) + if version >= required: + w('.'.join([str(x) for x in version]) + os.linesep) + return True + else: + w('FAIL' + os.linesep) + return False + + +def verify_python(): + if not check_vers(list(sys.version_info), VERS['Python'], text='Python'): + exit(1) + + +def verify_versions(): + print('Verifying version of modules...') + from PyQt4 import QtCore + check_vers(QtCore.PYQT_VERSION_STR, VERS['PyQt4'], + 'PyQt4') + check_vers(QtCore.qVersion(), VERS['Qt4'], + 'Qt4') + check_vers(__import__('sqlalchemy').__version__, VERS['sqlalchemy'], + 'sqlalchemy') + check_vers(__import__('enchant').__version__, VERS['enchant'], + 'enchant') + + +def check_module(mod, text='', indent=' '): + space = (30 - len(mod) - len(text)) * ' ' + w(indent + '%s%s... ' % (mod, text) + space) + try: + __import__(mod) + w('OK') + except ImportError: + w('FAIL') + w(os.linesep) + + +def main(): + + verify_python() + + print('Checking for modules...') + for m in MODULES: + check_module(m) + + print('Checking for optional modules...') + for m in OPTIONAL_MODULES: + check_module(m[0], text=m[1]) + + if sys.platform.startswith('win'): + print('Checking for Windows specific modules...') + for m in WIN32_MODULES: + check_module(m) + + verify_versions() + + +if __name__ == u'__main__': + main() From 5951d2c2a32f90f611f4402dab60cc5919ad41c8 Mon Sep 17 00:00:00 2001 From: Martin Zibricky Date: Sat, 9 Jul 2011 22:13:33 +0200 Subject: [PATCH 088/184] Update script to check openlp dependecies by info about supported image formats, enchant backends and available languages --- scripts/check_dependencies.py | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/scripts/check_dependencies.py b/scripts/check_dependencies.py index 967ff2185..c60bf6842 100755 --- a/scripts/check_dependencies.py +++ b/scripts/check_dependencies.py @@ -107,10 +107,10 @@ def verify_versions(): 'PyQt4') check_vers(QtCore.qVersion(), VERS['Qt4'], 'Qt4') - check_vers(__import__('sqlalchemy').__version__, VERS['sqlalchemy'], - 'sqlalchemy') - check_vers(__import__('enchant').__version__, VERS['enchant'], - 'enchant') + import sqlalchemy + check_vers(sqlalchemy.__version__, VERS['sqlalchemy'], 'sqlalchemy') + import enchant + check_vers(enchant.__version__, VERS['enchant'], 'enchant') def check_module(mod, text='', indent=' '): @@ -124,6 +124,27 @@ def check_module(mod, text='', indent=' '): w(os.linesep) +def verify_pyenchant(): + print('Enchant...') + import enchant + backends = ', '.join([x.name for x in enchant.Broker().describe()]) + print(' available backends: %s' % backends) + langs = ', '.join(enchant.list_languages()) + print(' available languages: %s' % langs) + + +def verify_pyqt(): + print('Qt4 image formats...') + from PyQt4 import QtGui + read_f = ', '.join([unicode(format).lower() \ + for format in QtGui.QImageReader.supportedImageFormats()]) + write_f= ', '.join([unicode(format).lower() \ + for format in QtGui.QImageWriter.supportedImageFormats()]) + print(' read: %s' % read_f) + print(' write: %s' % write_f) + from PyQt4 import phonon + + def main(): verify_python() @@ -142,6 +163,8 @@ def main(): check_module(m) verify_versions() + verify_pyqt() + verify_pyenchant() if __name__ == u'__main__': From dd302537ecf84c6c5a42c3b811c95ecf87757175 Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Sun, 10 Jul 2011 07:58:15 +0100 Subject: [PATCH 089/184] Fix code --- openlp/core/ui/servicemanager.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/openlp/core/ui/servicemanager.py b/openlp/core/ui/servicemanager.py index 88dc0603a..337de3bb8 100644 --- a/openlp/core/ui/servicemanager.py +++ b/openlp/core/ui/servicemanager.py @@ -957,15 +957,14 @@ class ServiceManager(QtGui.QWidget): build_icon(u':/general/general_delete.png')) treewidgetitem.setText(0, serviceitem.get_display_title()) tips = [] - # does not work with tooltips it needs if serviceitem.theme and serviceitem.theme != -1: - tips.append(u'%s : %s' % - (unicode(translate('OpenLP.ServiceManager', 'Slide theme')), - serviceitem.theme)) + tips.append(u'%s : %s' % + (unicode(translate('OpenLP.ServiceManager', 'Slide theme')), + serviceitem.theme)) if serviceitem.notes: - tips.append(u'%s : %s' % - (unicode(translate('OpenLP.ServiceManager', 'Notes')), - unicode(serviceitem.notes))) + tips.append(u'%s : %s' % + (unicode(translate('OpenLP.ServiceManager', 'Notes')), + unicode(serviceitem.notes))) treewidgetitem.setToolTip(0, u'
'.join(tips)) treewidgetitem.setData(0, QtCore.Qt.UserRole, QtCore.QVariant(item[u'order'])) From 3c63ffd4a67cd6b2ae00dbabdfdc058ac11680e5 Mon Sep 17 00:00:00 2001 From: Andreas Preikschat Date: Sun, 10 Jul 2011 12:45:52 +0200 Subject: [PATCH 090/184] fixed bug 805082 Fixes: https://launchpad.net/bugs/805082 --- openlp/core/ui/mainwindow.py | 45 +++++++++++++----------------------- 1 file changed, 16 insertions(+), 29 deletions(-) diff --git a/openlp/core/ui/mainwindow.py b/openlp/core/ui/mainwindow.py index e850ef335..ce5eaf7e9 100644 --- a/openlp/core/ui/mainwindow.py +++ b/openlp/core/ui/mainwindow.py @@ -276,29 +276,20 @@ class Ui_MainWindow(object): u'settingsConfigureItem', u':/system/system_settings.png', category=UiStrings().Settings) action_list.add_category(UiStrings().Help, CategoryOrder.standardMenu) - self.helpDocumentationItem = icon_action(mainWindow, - u'helpDocumentationItem', u':/system/system_help_contents.png', - category=None)#UiStrings().Help) - self.helpDocumentationItem.setEnabled(False) self.helpAboutItem = shortcut_action(mainWindow, u'helpAboutItem', [QtGui.QKeySequence(u'Ctrl+F1')], self.onHelpAboutItemClicked, u':/system/system_about.png', category=UiStrings().Help) if os.name == u'nt': self.localHelpFile = os.path.join( AppLocation.get_directory(AppLocation.AppDir), 'OpenLP.chm') - self.helpLocalHelpItem = shortcut_action( - mainWindow, u'helpLocalHelpItem', [QtGui.QKeySequence(u'F1')], - self.onHelpLocalHelpClicked, u':/system/system_about.png', - category=UiStrings().Help) - self.helpOnlineHelpItem = shortcut_action( - mainWindow, u'helpOnlineHelpItem', [QtGui.QKeySequence(u'Alt+F1')], - self.onHelpOnlineHelpClicked, u':/system/system_online_help.png', - category=UiStrings().Help) - else: - self.helpOnlineHelpItem = shortcut_action( - mainWindow, u'helpOnlineHelpItem', [QtGui.QKeySequence(u'F1')], - self.onHelpOnlineHelpClicked, u':/system/system_online_help.png', - category=UiStrings().Help) + self.offlineHelpItem = shortcut_action( + mainWindow, u'offlineHelpItem', [QtGui.QKeySequence(u'F1')], + self.onOfflineHelpClicked, + u':/system/system_help_contents.png', category=UiStrings().Help) + self.onlineHelpItem = shortcut_action( + mainWindow, u'onlineHelpItem', + [QtGui.QKeySequence(u'Alt+F1')], self.onOnlineHelpClicked, + u':/system/system_online_help.png', category=UiStrings().Help) self.helpWebSiteItem = base_action( mainWindow, u'helpWebSiteItem', category=UiStrings().Help) add_actions(self.fileImportMenu, @@ -333,13 +324,12 @@ class Ui_MainWindow(object): add_actions(self.toolsMenu, (self.toolsAddToolItem, None)) add_actions(self.toolsMenu, (self.toolsOpenDataFolder, None)) add_actions(self.toolsMenu, [self.updateThemeImages]) - add_actions(self.helpMenu, (self.helpDocumentationItem, None)) if os.name == u'nt': - add_actions(self.helpMenu, (self.helpLocalHelpItem, - self.helpOnlineHelpItem, None, self.helpWebSiteItem, + add_actions(self.helpMenu, (self.offlineHelpItem, + self.onlineHelpItem, None, self.helpWebSiteItem, self.helpAboutItem)) else: - add_actions(self.helpMenu, (self.helpOnlineHelpItem, None, + add_actions(self.helpMenu, (self.onlineHelpItem, None, self.helpWebSiteItem, self.helpAboutItem)) add_actions(self.menuBar, (self.fileMenu.menuAction(), self.viewMenu.menuAction(), self.toolsMenu.menuAction(), @@ -355,7 +345,6 @@ class Ui_MainWindow(object): self.toolsAddToolItem.setVisible(False) self.importLanguageItem.setVisible(False) self.exportLanguageItem.setVisible(False) - self.helpDocumentationItem.setVisible(False) self.setLockPanel(panelLocked) def retranslateUi(self, mainWindow): @@ -456,15 +445,13 @@ class Ui_MainWindow(object): '&Plugin List')) self.settingsPluginListItem.setStatusTip( translate('OpenLP.MainWindow', 'List the Plugins')) - self.helpDocumentationItem.setText( - translate('OpenLP.MainWindow', '&User Guide')) self.helpAboutItem.setText(translate('OpenLP.MainWindow', '&About')) self.helpAboutItem.setStatusTip( translate('OpenLP.MainWindow', 'More information about OpenLP')) if os.name == u'nt': - self.helpLocalHelpItem.setText( - translate('OpenLP.MainWindow', '&Help')) - self.helpOnlineHelpItem.setText( + self.offlineHelpItem.setText( + translate('OpenLP.MainWindow', '&User Guide')) + self.onlineHelpItem.setText( translate('OpenLP.MainWindow', '&Online Help')) self.helpWebSiteItem.setText( translate('OpenLP.MainWindow', '&Web Site')) @@ -762,13 +749,13 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): import webbrowser webbrowser.open_new(u'http://openlp.org/') - def onHelpLocalHelpClicked(self): + def onOfflineHelpClicked(self): """ Load the local OpenLP help file """ os.startfile(self.localHelpFile) - def onHelpOnlineHelpClicked(self): + def onOnlineHelpClicked(self): """ Load the online OpenLP manual """ From 50bc672f59a900721b6f1f3f0927b2c8f1f0252b Mon Sep 17 00:00:00 2001 From: Andreas Preikschat Date: Sun, 10 Jul 2011 12:52:30 +0200 Subject: [PATCH 091/184] removed the trailing 'help' --- openlp/core/ui/mainwindow.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/openlp/core/ui/mainwindow.py b/openlp/core/ui/mainwindow.py index ce5eaf7e9..c88508672 100644 --- a/openlp/core/ui/mainwindow.py +++ b/openlp/core/ui/mainwindow.py @@ -276,8 +276,8 @@ class Ui_MainWindow(object): u'settingsConfigureItem', u':/system/system_settings.png', category=UiStrings().Settings) action_list.add_category(UiStrings().Help, CategoryOrder.standardMenu) - self.helpAboutItem = shortcut_action(mainWindow, u'helpAboutItem', - [QtGui.QKeySequence(u'Ctrl+F1')], self.onHelpAboutItemClicked, + self.aboutItem = shortcut_action(mainWindow, u'aboutItem', + [QtGui.QKeySequence(u'Ctrl+F1')], self.onAboutItemClicked, u':/system/system_about.png', category=UiStrings().Help) if os.name == u'nt': self.localHelpFile = os.path.join( @@ -290,8 +290,8 @@ class Ui_MainWindow(object): mainWindow, u'onlineHelpItem', [QtGui.QKeySequence(u'Alt+F1')], self.onOnlineHelpClicked, u':/system/system_online_help.png', category=UiStrings().Help) - self.helpWebSiteItem = base_action( - mainWindow, u'helpWebSiteItem', category=UiStrings().Help) + self.webSiteItem = base_action( + mainWindow, u'webSiteItem', category=UiStrings().Help) add_actions(self.fileImportMenu, (self.importThemeItem, self.importLanguageItem)) add_actions(self.fileExportMenu, @@ -326,11 +326,11 @@ class Ui_MainWindow(object): add_actions(self.toolsMenu, [self.updateThemeImages]) if os.name == u'nt': add_actions(self.helpMenu, (self.offlineHelpItem, - self.onlineHelpItem, None, self.helpWebSiteItem, - self.helpAboutItem)) + self.onlineHelpItem, None, self.webSiteItem, + self.aboutItem)) else: add_actions(self.helpMenu, (self.onlineHelpItem, None, - self.helpWebSiteItem, self.helpAboutItem)) + self.webSiteItem, self.aboutItem)) add_actions(self.menuBar, (self.fileMenu.menuAction(), self.viewMenu.menuAction(), self.toolsMenu.menuAction(), self.settingsMenu.menuAction(), self.helpMenu.menuAction())) @@ -445,15 +445,15 @@ class Ui_MainWindow(object): '&Plugin List')) self.settingsPluginListItem.setStatusTip( translate('OpenLP.MainWindow', 'List the Plugins')) - self.helpAboutItem.setText(translate('OpenLP.MainWindow', '&About')) - self.helpAboutItem.setStatusTip( + self.aboutItem.setText(translate('OpenLP.MainWindow', '&About')) + self.aboutItem.setStatusTip( translate('OpenLP.MainWindow', 'More information about OpenLP')) if os.name == u'nt': self.offlineHelpItem.setText( translate('OpenLP.MainWindow', '&User Guide')) self.onlineHelpItem.setText( translate('OpenLP.MainWindow', '&Online Help')) - self.helpWebSiteItem.setText( + self.webSiteItem.setText( translate('OpenLP.MainWindow', '&Web Site')) for item in self.languageGroup.actions(): item.setText(item.objectName()) @@ -542,7 +542,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): QtCore.QObject.connect(self.themeManagerDock, QtCore.SIGNAL(u'visibilityChanged(bool)'), self.viewThemeManagerItem.setChecked) - QtCore.QObject.connect(self.helpWebSiteItem, + QtCore.QObject.connect(self.webSiteItem, QtCore.SIGNAL(u'triggered()'), self.onHelpWebSiteClicked) QtCore.QObject.connect(self.toolsOpenDataFolder, QtCore.SIGNAL(u'triggered()'), self.onToolsOpenDataFolderClicked) @@ -762,7 +762,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): import webbrowser webbrowser.open_new(u'http://manual.openlp.org/') - def onHelpAboutItemClicked(self): + def onAboutItemClicked(self): """ Show the About form """ From 4651ec35b60145b42afcfbc08433b3401dedc7b4 Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Sun, 10 Jul 2011 12:59:23 +0100 Subject: [PATCH 092/184] Fixes --- openlp/core/lib/serviceitem.py | 10 ++++++---- openlp/core/lib/ui.py | 2 -- openlp/core/ui/servicemanager.py | 12 +++++------- 3 files changed, 11 insertions(+), 13 deletions(-) diff --git a/openlp/core/lib/serviceitem.py b/openlp/core/lib/serviceitem.py index 0810e292d..1245988b4 100644 --- a/openlp/core/lib/serviceitem.py +++ b/openlp/core/lib/serviceitem.py @@ -35,7 +35,7 @@ import logging import os import uuid -from openlp.core.lib import build_icon, clean_tags, expand_tags +from openlp.core.lib import build_icon, clean_tags, expand_tags, translate from openlp.core.lib.ui import UiStrings log = logging.getLogger(__name__) @@ -450,10 +450,12 @@ class ServiceItem(object): start = None end = None if self.start_time != 0: - start = UiStrings().StartTimeCode % \ + start = unicode(translate('OpenLP.ServiceItem', + 'Start: %s')) % \ unicode(datetime.timedelta(seconds=self.start_time)) if self.media_length != 0: - end = UiStrings().LengthTime % \ + end = unicode(translate('OpenLP.ServiceItem', + 'Length: %s')) % \ unicode(datetime.timedelta(seconds=self.media_length)) if not start and not end: return None @@ -462,7 +464,7 @@ class ServiceItem(object): elif not start and end: return end else: - return u'%s : %s' % (start, end) + return u'%s
%s' % (start, end) def update_theme(self, theme): """ diff --git a/openlp/core/lib/ui.py b/openlp/core/lib/ui.py index 973c76660..812e5815d 100644 --- a/openlp/core/lib/ui.py +++ b/openlp/core/lib/ui.py @@ -83,7 +83,6 @@ class UiStrings(object): self.Image = translate('OpenLP.Ui', 'Image') self.Import = translate('OpenLP.Ui', 'Import') self.LayoutStyle = translate('OpenLP.Ui', 'Layout style:') - self.LengthTime = unicode(translate('OpenLP.Ui', 'Length %s')) self.Live = translate('OpenLP.Ui', 'Live') self.LiveBGError = translate('OpenLP.Ui', 'Live Background Error') self.LiveToolbar = translate('OpenLP.Ui', 'Live Toolbar') @@ -123,7 +122,6 @@ class UiStrings(object): self.Split = translate('OpenLP.Ui', '&Split') self.SplitToolTip = translate('OpenLP.Ui', 'Split a slide into two ' 'only if it does not fit on the screen as one slide.') - self.StartTimeCode = unicode(translate('OpenLP.Ui', 'Start %s')) self.Theme = translate('OpenLP.Ui', 'Theme', 'Singular') self.Themes = translate('OpenLP.Ui', 'Themes', 'Plural') self.Tools = translate('OpenLP.Ui', 'Tools') diff --git a/openlp/core/ui/servicemanager.py b/openlp/core/ui/servicemanager.py index 337de3bb8..9a758df61 100644 --- a/openlp/core/ui/servicemanager.py +++ b/openlp/core/ui/servicemanager.py @@ -958,13 +958,16 @@ class ServiceManager(QtGui.QWidget): treewidgetitem.setText(0, serviceitem.get_display_title()) tips = [] if serviceitem.theme and serviceitem.theme != -1: - tips.append(u'%s : %s' % + tips.append(u'%s: %s' % (unicode(translate('OpenLP.ServiceManager', 'Slide theme')), serviceitem.theme)) if serviceitem.notes: - tips.append(u'%s : %s' % + tips.append(u'%s %s' % (unicode(translate('OpenLP.ServiceManager', 'Notes')), unicode(serviceitem.notes))) + if item[u'service_item'] \ + .is_capable(ItemCapabilities.AllowsVariableStartTime): + tips.append(item[u'service_item'].get_media_time()) treewidgetitem.setToolTip(0, u'
'.join(tips)) treewidgetitem.setData(0, QtCore.Qt.UserRole, QtCore.QVariant(item[u'order'])) @@ -975,11 +978,6 @@ class ServiceManager(QtGui.QWidget): text = frame[u'title'].replace(u'\n', u' ') child.setText(0, text[:40]) child.setData(0, QtCore.Qt.UserRole, QtCore.QVariant(count)) - if item[u'service_item'] \ - .is_capable(ItemCapabilities.AllowsVariableStartTime): - tip = item[u'service_item'].get_media_time() - if tip: - child.setToolTip(0, tip) if serviceItem == itemcount: if item[u'expanded'] and serviceItemChild == count: self.serviceManagerList.setCurrentItem(child) From cfb1a06bd3fc2398a1c1f94a1dd8b987aeb37794 Mon Sep 17 00:00:00 2001 From: Martin Zibricky Date: Sun, 10 Jul 2011 14:00:58 +0200 Subject: [PATCH 093/184] Update script to check openlp dependecies - catching all imports properly --- scripts/check_dependencies.py | 71 +++++++++++++++++++++++------------ 1 file changed, 46 insertions(+), 25 deletions(-) diff --git a/scripts/check_dependencies.py b/scripts/check_dependencies.py index c60bf6842..4abd1504d 100755 --- a/scripts/check_dependencies.py +++ b/scripts/check_dependencies.py @@ -95,6 +95,10 @@ def check_vers(version, required, text): return False +def print_vers_fail(required, text): + print(' %s >= %s ... FAIL' % (text, required)) + + def verify_python(): if not check_vers(list(sys.version_info), VERS['Python'], text='Python'): exit(1) @@ -102,15 +106,25 @@ def verify_python(): def verify_versions(): print('Verifying version of modules...') - from PyQt4 import QtCore - check_vers(QtCore.PYQT_VERSION_STR, VERS['PyQt4'], - 'PyQt4') - check_vers(QtCore.qVersion(), VERS['Qt4'], - 'Qt4') - import sqlalchemy - check_vers(sqlalchemy.__version__, VERS['sqlalchemy'], 'sqlalchemy') - import enchant - check_vers(enchant.__version__, VERS['enchant'], 'enchant') + try: + from PyQt4 import QtCore + check_vers(QtCore.PYQT_VERSION_STR, VERS['PyQt4'], + 'PyQt4') + check_vers(QtCore.qVersion(), VERS['Qt4'], + 'Qt4') + except ImportError: + print_vers_fail(VERS['PyQt4'], 'PyQt4') + print_vers_fail(VERS['Qt4'], 'Qt4') + try: + import sqlalchemy + check_vers(sqlalchemy.__version__, VERS['sqlalchemy'], 'sqlalchemy') + except ImportError: + print_vers_fail(VERS['sqlalchemy'], 'sqlalchemy') + try: + import enchant + check_vers(enchant.__version__, VERS['enchant'], 'enchant') + except ImportError: + print_vers_fail(VERS['enchant'], 'enchant') def check_module(mod, text='', indent=' '): @@ -125,24 +139,31 @@ def check_module(mod, text='', indent=' '): def verify_pyenchant(): - print('Enchant...') - import enchant - backends = ', '.join([x.name for x in enchant.Broker().describe()]) - print(' available backends: %s' % backends) - langs = ', '.join(enchant.list_languages()) - print(' available languages: %s' % langs) + w('Enchant (spell checker)... ') + try: + import enchant + w(os.linesep) + backends = ', '.join([x.name for x in enchant.Broker().describe()]) + print(' available backends: %s' % backends) + langs = ', '.join(enchant.list_languages()) + print(' available languages: %s' % langs) + except ImportError: + w('FAIL' + os.linesep) def verify_pyqt(): - print('Qt4 image formats...') - from PyQt4 import QtGui - read_f = ', '.join([unicode(format).lower() \ - for format in QtGui.QImageReader.supportedImageFormats()]) - write_f= ', '.join([unicode(format).lower() \ - for format in QtGui.QImageWriter.supportedImageFormats()]) - print(' read: %s' % read_f) - print(' write: %s' % write_f) - from PyQt4 import phonon + w('Qt4 image formats... ') + try: + from PyQt4 import QtGui + read_f = ', '.join([unicode(format).lower() \ + for format in QtGui.QImageReader.supportedImageFormats()]) + write_f= ', '.join([unicode(format).lower() \ + for format in QtGui.QImageWriter.supportedImageFormats()]) + w(os.linesep) + print(' read: %s' % read_f) + print(' write: %s' % write_f) + except ImportError: + w('FAIL' + os.linesep) def main(): @@ -157,7 +178,7 @@ def main(): for m in OPTIONAL_MODULES: check_module(m[0], text=m[1]) - if sys.platform.startswith('win'): + if is_win: print('Checking for Windows specific modules...') for m in WIN32_MODULES: check_module(m) From 7d21d45764e405a06f5ec6dc3798dfc04bedf0e8 Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Sun, 10 Jul 2011 13:02:58 +0100 Subject: [PATCH 094/184] missing : --- openlp/core/ui/servicemanager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openlp/core/ui/servicemanager.py b/openlp/core/ui/servicemanager.py index 9a758df61..fa7c9ef55 100644 --- a/openlp/core/ui/servicemanager.py +++ b/openlp/core/ui/servicemanager.py @@ -962,7 +962,7 @@ class ServiceManager(QtGui.QWidget): (unicode(translate('OpenLP.ServiceManager', 'Slide theme')), serviceitem.theme)) if serviceitem.notes: - tips.append(u'%s %s' % + tips.append(u'%s: %s' % (unicode(translate('OpenLP.ServiceManager', 'Notes')), unicode(serviceitem.notes))) if item[u'service_item'] \ From b83048ff4e7ee43a5699d793a4b2513dd819931e Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Mon, 11 Jul 2011 17:32:25 +0100 Subject: [PATCH 095/184] Fix outstanding strings in Error for translations Fixes: https://launchpad.net/bugs/796440 --- openlp/core/ui/firsttimewizard.py | 2 +- openlp/core/ui/generaltab.py | 2 +- openlp/core/ui/themestab.py | 2 +- openlp/plugins/alerts/alertsplugin.py | 2 +- openlp/plugins/alerts/forms/alertform.py | 8 +++--- openlp/plugins/bibles/bibleplugin.py | 4 +-- .../plugins/bibles/forms/bibleupgradeform.py | 6 ++-- openlp/plugins/bibles/lib/csvbible.py | 7 +++-- openlp/plugins/bibles/lib/http.py | 28 +++++++++---------- openlp/plugins/bibles/lib/mediaitem.py | 8 +++--- 10 files changed, 35 insertions(+), 34 deletions(-) diff --git a/openlp/core/ui/firsttimewizard.py b/openlp/core/ui/firsttimewizard.py index 3644ed07b..64d9cbf8d 100644 --- a/openlp/core/ui/firsttimewizard.py +++ b/openlp/core/ui/firsttimewizard.py @@ -209,7 +209,7 @@ class Ui_FirstTimeWizard(object): 'Select the Plugins you wish to use. ')) self.songsCheckBox.setText(translate('OpenLP.FirstTimeWizard', 'Songs')) self.customCheckBox.setText(translate('OpenLP.FirstTimeWizard', - 'Custom Text')) + 'Custom Slides')) self.bibleCheckBox.setText(translate('OpenLP.FirstTimeWizard', 'Bible')) self.imageCheckBox.setText(translate('OpenLP.FirstTimeWizard', 'Images')) diff --git a/openlp/core/ui/generaltab.py b/openlp/core/ui/generaltab.py index 925e3d31f..9a241473a 100644 --- a/openlp/core/ui/generaltab.py +++ b/openlp/core/ui/generaltab.py @@ -44,7 +44,7 @@ class GeneralTab(SettingsTab): """ self.screens = ScreenList.get_instance() self.icon_path = u':/icon/openlp-logo-16x16.png' - generalTranslated = translate('GeneralTab', 'General') + generalTranslated = translate('OpenLP.GeneralTab', 'General') SettingsTab.__init__(self, parent, u'General', generalTranslated) def setupUi(self): diff --git a/openlp/core/ui/themestab.py b/openlp/core/ui/themestab.py index 86087e82f..572efdf4b 100644 --- a/openlp/core/ui/themestab.py +++ b/openlp/core/ui/themestab.py @@ -37,7 +37,7 @@ class ThemesTab(SettingsTab): """ def __init__(self, parent, mainwindow): self.mainwindow = mainwindow - generalTranslated = translate('ThemeTab', 'Themes') + generalTranslated = translate('OpenLP.ThemesTab', 'Themes') SettingsTab.__init__(self, parent, u'Themes', generalTranslated) self.icon_path = u':/themes/theme_new.png' diff --git a/openlp/plugins/alerts/alertsplugin.py b/openlp/plugins/alerts/alertsplugin.py index 41c2e2211..f0bf2d93e 100644 --- a/openlp/plugins/alerts/alertsplugin.py +++ b/openlp/plugins/alerts/alertsplugin.py @@ -104,7 +104,7 @@ class AlertsPlugin(Plugin): def about(self): about_text = translate('AlertsPlugin', 'Alerts Plugin' '
The alert plugin controls the displaying of nursery alerts ' - 'on the display screen') + 'on the display screen.') return about_text def setPluginTextStrings(self): diff --git a/openlp/plugins/alerts/forms/alertform.py b/openlp/plugins/alerts/forms/alertform.py index 8de7744aa..45d283f28 100644 --- a/openlp/plugins/alerts/forms/alertform.py +++ b/openlp/plugins/alerts/forms/alertform.py @@ -176,8 +176,8 @@ class AlertForm(QtGui.QDialog, Ui_AlertDialog): # We found '<>' in the alert text, but the ParameterEdit field is empty. if text.find(u'<>') != -1 and not self.parameterEdit.text() and \ QtGui.QMessageBox.question(self, - translate('AlertPlugin.AlertForm', 'No Parameter Found'), - translate('AlertPlugin.AlertForm', 'You have not entered a ' + translate('AlertsPlugin.AlertForm', 'No Parameter Found'), + translate('AlertsPlugin.AlertForm', 'You have not entered a ' 'parameter to be replaced.\nDo you want to continue anyway?'), QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.No | QtGui.QMessageBox.Yes)) == QtGui.QMessageBox.No: @@ -187,8 +187,8 @@ class AlertForm(QtGui.QDialog, Ui_AlertDialog): # in the alert text. elif text.find(u'<>') == -1 and self.parameterEdit.text() and \ QtGui.QMessageBox.question(self, - translate('AlertPlugin.AlertForm', 'No Placeholder Found'), - translate('AlertPlugin.AlertForm', 'The alert text does not' + translate('AlertsPlugin.AlertForm', 'No Placeholder Found'), + translate('AlertsPlugin.AlertForm', 'The alert text does not' ' contain \'<>\'.\nDo you want to continue anyway?'), QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.No | QtGui.QMessageBox.Yes)) == QtGui.QMessageBox.No: diff --git a/openlp/plugins/bibles/bibleplugin.py b/openlp/plugins/bibles/bibleplugin.py index a5abc32d2..da7658c12 100644 --- a/openlp/plugins/bibles/bibleplugin.py +++ b/openlp/plugins/bibles/bibleplugin.py @@ -117,9 +117,9 @@ class BiblePlugin(Plugin): self.toolsUpgradeItem = QtGui.QAction(tools_menu) self.toolsUpgradeItem.setObjectName(u'toolsUpgradeItem') self.toolsUpgradeItem.setText( - translate('BiblePlugin', '&Upgrade older Bibles')) + translate('BiblesPlugin', '&Upgrade older Bibles')) self.toolsUpgradeItem.setStatusTip( - translate('BiblePlugin', 'Upgrade the Bible databases to the ' + translate('BiblesPlugin', 'Upgrade the Bible databases to the ' 'latest format.')) tools_menu.addAction(self.toolsUpgradeItem) QtCore.QObject.connect(self.toolsUpgradeItem, diff --git a/openlp/plugins/bibles/forms/bibleupgradeform.py b/openlp/plugins/bibles/forms/bibleupgradeform.py index 14936a340..14e20e37f 100644 --- a/openlp/plugins/bibles/forms/bibleupgradeform.py +++ b/openlp/plugins/bibles/forms/bibleupgradeform.py @@ -413,7 +413,7 @@ class BibleUpgradeForm(OpenLPWizard): if not backup_path: critical_error_message_box(UiStrings().EmptyField, translate('BiblesPlugin.UpgradeWizardForm', - 'You need to specify a Backup Directory for your ' + 'You need to specify a backup Directory for your ' 'Bibles.')) self.backupDirectoryEdit.setFocus() return False @@ -520,7 +520,7 @@ class BibleUpgradeForm(OpenLPWizard): OpenLPWizard.preWizard(self) self.progressLabel.setText(translate( 'BiblesPlugin.UpgradeWizardForm', - 'Starting Bible upgrade...')) + 'Starting upgrade...')) Receiver.send_message(u'openlp_process_events') def performWizard(self): @@ -532,7 +532,7 @@ class BibleUpgradeForm(OpenLPWizard): if self.maxBibles == 0: self.progressLabel.setText( translate('BiblesPlugin.UpgradeWizardForm', 'There are no ' - 'Bibles available to upgrade.')) + 'Bibles that need to be upgraded.')) self.progressBar.hide() return self.maxBibles = 0 diff --git a/openlp/plugins/bibles/lib/csvbible.py b/openlp/plugins/bibles/lib/csvbible.py index 83b52971c..6735a7344 100644 --- a/openlp/plugins/bibles/lib/csvbible.py +++ b/openlp/plugins/bibles/lib/csvbible.py @@ -115,7 +115,8 @@ class CSVBible(BibleDB): if self.stop_import_flag: break self.wizard.incrementProgressBar(unicode( - translate('BibleDB.Wizard', 'Importing books... %s')) % + translate('BiblesPlugin.CSVBible', + 'Importing books... %s')) % unicode(line[2], details['encoding'])) book_ref_id = self.get_book_ref_id_by_name( unicode(line[2], details['encoding']), 67, language_id) @@ -155,7 +156,7 @@ class CSVBible(BibleDB): book = self.get_book(line_book) book_ptr = book.name self.wizard.incrementProgressBar(unicode(translate( - 'BibleDB.Wizard', 'Importing verses from %s...', + 'BiblesPlugin.CSVBible', 'Importing verses from %s...', 'Importing verses from ...')) % book.name) self.session.commit() try: @@ -163,7 +164,7 @@ class CSVBible(BibleDB): except UnicodeError: verse_text = unicode(line[3], u'cp1252') self.create_verse(book.id, line[1], line[2], verse_text) - self.wizard.incrementProgressBar(translate('BibleDB.Wizard', + self.wizard.incrementProgressBar(translate('BiblesPlugin.CSVBible', 'Importing verses... done.')) Receiver.send_message(u'openlp_process_events') self.session.commit() diff --git a/openlp/plugins/bibles/lib/http.py b/openlp/plugins/bibles/lib/http.py index 28ceaad68..ee644a8d5 100644 --- a/openlp/plugins/bibles/lib/http.py +++ b/openlp/plugins/bibles/lib/http.py @@ -69,10 +69,10 @@ class BGExtract(object): ``chapter`` Chapter number. """ - log.debug(u'BGExtract.get_bible_chapter("%s", "%s", "%s")', version, + log.debug(u'BGExtract.get_bible_chapter("%s", "%s", "%s")', version, bookname, chapter) urlbookname = urllib.quote(bookname.encode("utf-8")) - url_params = u'search=%s+%s&version=%s' % (urlbookname, chapter, + url_params = u'search=%s+%s&version=%s' % (urlbookname, chapter, version) cleaner = [(re.compile(' |
|\'\+\''), lambda match: '')] soup = get_soup_for_bible_ref( @@ -203,7 +203,7 @@ class BSExtract(object): ``chapter`` Chapter number """ - log.debug(u'BSExtract.get_bible_chapter("%s", "%s", "%s")', version, + log.debug(u'BSExtract.get_bible_chapter("%s", "%s", "%s")', version, bookname, chapter) urlversion = urllib.quote(version.encode("utf-8")) urlbookname = urllib.quote(bookname.encode("utf-8")) @@ -230,7 +230,7 @@ class BSExtract(object): def get_books_from_http(self, version): """ - Load a list of all books a Bible contains from Bibleserver mobile + Load a list of all books a Bible contains from Bibleserver mobile website. ``version`` @@ -276,7 +276,7 @@ class CWExtract(object): ``chapter`` Chapter number """ - log.debug(u'CWExtract.get_bible_chapter("%s", "%s", "%s")', version, + log.debug(u'CWExtract.get_bible_chapter("%s", "%s", "%s")', version, bookname, chapter) urlbookname = bookname.replace(u' ', u'-') urlbookname = urlbookname.lower() @@ -389,7 +389,7 @@ class HTTPBible(BibleDB): """ self.wizard.progressBar.setMaximum(68) self.wizard.incrementProgressBar(unicode(translate( - 'BiblesPlugin.HTTPBible', + 'BiblesPlugin.HTTPBible', 'Registering Bible and loading books...'))) self.create_meta(u'download source', self.download_source) self.create_meta(u'download name', self.download_name) @@ -415,7 +415,7 @@ class HTTPBible(BibleDB): self.wizard.progressBar.setMaximum(len(books)+2) self.wizard.incrementProgressBar(unicode(translate( 'BiblesPlugin.HTTPBible', 'Registering Language...'))) - bible = BiblesResourcesDB.get_webbible(self.download_name, + bible = BiblesResourcesDB.get_webbible(self.download_name, self.download_source.lower()) if bible[u'language_id']: language_id = bible[u'language_id'] @@ -432,14 +432,14 @@ class HTTPBible(BibleDB): self.wizard.incrementProgressBar(unicode(translate( 'BiblesPlugin.HTTPBible', 'Importing %s...', 'Importing ...')) % book) - book_ref_id = self.get_book_ref_id_by_name(book, len(books), + book_ref_id = self.get_book_ref_id_by_name(book, len(books), language_id) if not book_ref_id: log.exception(u'Importing books from %s - download name: "%s" '\ 'failed' % (self.download_source, self.download_name)) return False book_details = BiblesResourcesDB.get_book_by_id(book_ref_id) - log.debug(u'Book details: Name:%s; id:%s; testament_id:%s', + log.debug(u'Book details: Name:%s; id:%s; testament_id:%s', book, book_ref_id, book_details[u'testament_id']) self.create_book(book, book_ref_id, book_details[u'testament_id']) if self.stop_import_flag: @@ -524,7 +524,7 @@ class HTTPBible(BibleDB): def get_chapter_count(self, book): """ Return the number of chapters in a particular book. - + ``book`` The book object to get the chapter count for. """ @@ -597,14 +597,14 @@ def send_error_message(error_type): """ if error_type == u'download': critical_error_message_box( - translate('BiblePlugin.HTTPBible', 'Download Error'), - translate('BiblePlugin.HTTPBible', 'There was a ' + translate('BiblesPlugin.HTTPBible', 'Download Error'), + translate('BiblesPlugin.HTTPBible', 'There was a ' 'problem downloading your verse selection. Please check your ' 'Internet connection, and if this error continues to occur ' 'please consider reporting a bug.')) elif error_type == u'parse': critical_error_message_box( - translate('BiblePlugin.HTTPBible', 'Parse Error'), - translate('BiblePlugin.HTTPBible', 'There was a ' + translate('BiblesPlugin.HTTPBible', 'Parse Error'), + translate('BiblesPlugin.HTTPBible', 'There was a ' 'problem extracting your verse selection. If this error continues ' 'to occur please consider reporting a bug.')) diff --git a/openlp/plugins/bibles/lib/mediaitem.py b/openlp/plugins/bibles/lib/mediaitem.py index 0734df818..82ee4430c 100644 --- a/openlp/plugins/bibles/lib/mediaitem.py +++ b/openlp/plugins/bibles/lib/mediaitem.py @@ -87,7 +87,7 @@ class BibleMediaItem(MediaManagerItem): not second_bible: self.displayResults(bible, second_bible) elif critical_error_message_box( - message=translate('BiblePlugin.MediaItem', + message=translate('BiblesPlugin.MediaItem', 'You cannot combine single and dual Bible verse search results. ' 'Do you want to delete your search results and start a new ' 'search?'), @@ -437,7 +437,7 @@ class BibleMediaItem(MediaManagerItem): if verse_count == 0: self.advancedSearchButton.setEnabled(False) critical_error_message_box( - message=translate('BiblePlugin.MediaItem', + message=translate('BiblesPlugin.MediaItem', 'Bible not fully loaded.')) else: self.advancedSearchButton.setEnabled(True) @@ -694,8 +694,8 @@ class BibleMediaItem(MediaManagerItem): verse.verse, verse.verse)) if passage_not_found: QtGui.QMessageBox.information(self, - translate('BiblePlugin.MediaItem', 'Information'), - unicode(translate('BiblePlugin.MediaItem', + translate('BiblesPlugin.MediaItem', 'Information'), + unicode(translate('BiblesPlugin.MediaItem', 'The second Bible does not contain all the verses ' 'that are in the main Bible. Only verses found in both ' 'Bibles will be shown. %d verses have not been ' From b98e36aff28298b3c28c06e7ecc07adc9efd5d32 Mon Sep 17 00:00:00 2001 From: Andreas Preikschat Date: Wed, 13 Jul 2011 15:32:19 +0200 Subject: [PATCH 096/184] regex clean ups --- openlp/core/utils/__init__.py | 7 +++---- openlp/plugins/bibles/forms/bibleupgradeform.py | 6 ++---- openlp/plugins/songs/forms/editverseform.py | 7 ++++--- openlp/plugins/songs/lib/xml.py | 5 +++-- 4 files changed, 12 insertions(+), 13 deletions(-) diff --git a/openlp/core/utils/__init__.py b/openlp/core/utils/__init__.py index 317083799..081870587 100644 --- a/openlp/core/utils/__init__.py +++ b/openlp/core/utils/__init__.py @@ -53,6 +53,7 @@ APPLICATION_VERSION = {} IMAGES_FILTER = None UNO_CONNECTION_TYPE = u'pipe' #UNO_CONNECTION_TYPE = u'socket' +VERSION_SPLITTER = re.compile(r'([0-9]+).([0-9]+).([0-9]+)(?:-bzr([0-9]+))?') class VersionThread(QtCore.QThread): """ @@ -61,8 +62,6 @@ class VersionThread(QtCore.QThread): """ def __init__(self, parent): QtCore.QThread.__init__(self, parent) - self.version_splitter = re.compile( - r'([0-9]+).([0-9]+).([0-9]+)(?:-bzr([0-9]+))?') def run(self): """ @@ -73,7 +72,7 @@ class VersionThread(QtCore.QThread): version = check_latest_version(app_version) remote_version = {} local_version = {} - match = self.version_splitter.match(version) + match = VERSION_SPLITTER.match(version) if match: remote_version[u'major'] = int(match.group(1)) remote_version[u'minor'] = int(match.group(2)) @@ -82,7 +81,7 @@ class VersionThread(QtCore.QThread): remote_version[u'revision'] = int(match.group(4)) else: return - match = self.version_splitter.match(app_version[u'full']) + match = VERSION_SPLITTER.match(app_version[u'full']) if match: local_version[u'major'] = int(match.group(1)) local_version[u'minor'] = int(match.group(2)) diff --git a/openlp/plugins/bibles/forms/bibleupgradeform.py b/openlp/plugins/bibles/forms/bibleupgradeform.py index 14936a340..aeff6f3cc 100644 --- a/openlp/plugins/bibles/forms/bibleupgradeform.py +++ b/openlp/plugins/bibles/forms/bibleupgradeform.py @@ -27,8 +27,7 @@ The bible import functions for OpenLP """ import logging -import os.path -import re +import os import shutil from PyQt4 import QtCore, QtGui @@ -70,8 +69,7 @@ class BibleUpgradeForm(OpenLPWizard): self.mediaItem = bibleplugin.mediaItem self.suffix = u'.sqlite' self.settingsSection = u'bibles' - self.path = AppLocation.get_section_data_path( - self.settingsSection) + self.path = AppLocation.get_section_data_path(self.settingsSection) self.files = self.manager.old_bible_databases self.success = {} self.newbibles = {} diff --git a/openlp/plugins/songs/forms/editverseform.py b/openlp/plugins/songs/forms/editverseform.py index 79b2b295a..1845bc0e3 100644 --- a/openlp/plugins/songs/forms/editverseform.py +++ b/openlp/plugins/songs/forms/editverseform.py @@ -37,6 +37,8 @@ from editversedialog import Ui_EditVerseDialog log = logging.getLogger(__name__) +VERSE_REGEX = re.compile(r'---\[(.+):\D*(\d*)\D*.*\]---') + class EditVerseForm(QtGui.QDialog, Ui_EditVerseDialog): """ This is the form that is used to edit the verses of the song. @@ -60,7 +62,6 @@ class EditVerseForm(QtGui.QDialog, Ui_EditVerseDialog): QtCore.QObject.connect(self.verseTypeComboBox, QtCore.SIGNAL(u'currentIndexChanged(int)'), self.onVerseTypeComboBoxChanged) - self.verse_regex = re.compile(r'---\[(.+):\D*(\d*)\D*.*\]---') def contextMenu(self, point): item = self.serviceManagerList.itemAt(point) @@ -105,7 +106,7 @@ class EditVerseForm(QtGui.QDialog, Ui_EditVerseDialog): if position == -1: return text = text[:position + 4] - match = self.verse_regex.match(text) + match = VERSE_REGEX.match(text) if match: verse_tag = match.group(1) try: @@ -136,7 +137,7 @@ class EditVerseForm(QtGui.QDialog, Ui_EditVerseDialog): if position == -1: return text = text[:position + 4] - match = self.verse_regex.match(text) + match = VERSE_REGEX.match(text) if match: verse_type = match.group(1) verse_type_index = VerseType.from_loose_input(verse_type) diff --git a/openlp/plugins/songs/lib/xml.py b/openlp/plugins/songs/lib/xml.py index c5bf85ad8..3635fd7e7 100644 --- a/openlp/plugins/songs/lib/xml.py +++ b/openlp/plugins/songs/lib/xml.py @@ -73,6 +73,8 @@ from openlp.core.utils import get_application_version log = logging.getLogger(__name__) +CHORD_REGEX = re.compile(u'') + class SongXML(object): """ This class builds and parses the XML used to describe songs. @@ -234,7 +236,6 @@ class OpenLyrics(object): IMPLEMENTED_VERSION = u'0.7' def __init__(self, manager): self.manager = manager - self.chord_regex = re.compile(u'') def song_to_xml(self, song): """ @@ -319,7 +320,7 @@ class OpenLyrics(object): if xml[:5] == u' Date: Wed, 13 Jul 2011 15:41:32 +0200 Subject: [PATCH 097/184] use map instead of list comprehension; blank lines --- scripts/check_dependencies.py | 30 +++++++++--------------------- 1 file changed, 9 insertions(+), 21 deletions(-) diff --git a/scripts/check_dependencies.py b/scripts/check_dependencies.py index 4abd1504d..bf9e97d88 100755 --- a/scripts/check_dependencies.py +++ b/scripts/check_dependencies.py @@ -74,44 +74,38 @@ OPTIONAL_MODULES = [ ('sqlite', ' (SQLite 2 support)'), ('MySQLdb', ' (MySQL support)'), ('psycopg2', ' (PostgreSQL support)'), - ] +] w = sys.stdout.write - def check_vers(version, required, text): if type(version) is str: version = version.split('.') - version = [int(x) for x in version] + version = map(int, version) if type(required) is str: required = required.split('.') - required = [int(x) for x in required] - w(' %s >= %s ... ' % (text, '.'.join([str(x) for x in required]))) + required = map(int, required) + w(' %s >= %s ... ' % (text, '.'.join(map(str, required)))) if version >= required: - w('.'.join([str(x) for x in version]) + os.linesep) + w('.'.join(map(str, version)) + os.linesep) return True else: w('FAIL' + os.linesep) return False - def print_vers_fail(required, text): print(' %s >= %s ... FAIL' % (text, required)) - def verify_python(): if not check_vers(list(sys.version_info), VERS['Python'], text='Python'): exit(1) - def verify_versions(): print('Verifying version of modules...') try: from PyQt4 import QtCore - check_vers(QtCore.PYQT_VERSION_STR, VERS['PyQt4'], - 'PyQt4') - check_vers(QtCore.qVersion(), VERS['Qt4'], - 'Qt4') + check_vers(QtCore.PYQT_VERSION_STR, VERS['PyQt4'], 'PyQt4') + check_vers(QtCore.qVersion(), VERS['Qt4'], 'Qt4') except ImportError: print_vers_fail(VERS['PyQt4'], 'PyQt4') print_vers_fail(VERS['Qt4'], 'Qt4') @@ -126,7 +120,6 @@ def verify_versions(): except ImportError: print_vers_fail(VERS['enchant'], 'enchant') - def check_module(mod, text='', indent=' '): space = (30 - len(mod) - len(text)) * ' ' w(indent + '%s%s... ' % (mod, text) + space) @@ -137,7 +130,6 @@ def check_module(mod, text='', indent=' '): w('FAIL') w(os.linesep) - def verify_pyenchant(): w('Enchant (spell checker)... ') try: @@ -150,14 +142,13 @@ def verify_pyenchant(): except ImportError: w('FAIL' + os.linesep) - def verify_pyqt(): w('Qt4 image formats... ') try: from PyQt4 import QtGui - read_f = ', '.join([unicode(format).lower() \ + read_f = ', '.join([unicode(format).lower() for format in QtGui.QImageReader.supportedImageFormats()]) - write_f= ', '.join([unicode(format).lower() \ + write_f = ', '.join([unicode(format).lower() for format in QtGui.QImageWriter.supportedImageFormats()]) w(os.linesep) print(' read: %s' % read_f) @@ -165,9 +156,7 @@ def verify_pyqt(): except ImportError: w('FAIL' + os.linesep) - def main(): - verify_python() print('Checking for modules...') @@ -187,6 +176,5 @@ def main(): verify_pyqt() verify_pyenchant() - if __name__ == u'__main__': main() From f1cf256d99890f53b6d8d7aa3ad9717d5c89de65 Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Wed, 13 Jul 2011 18:41:37 +0100 Subject: [PATCH 098/184] Fix --- openlp/plugins/bibles/forms/bibleupgradeform.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openlp/plugins/bibles/forms/bibleupgradeform.py b/openlp/plugins/bibles/forms/bibleupgradeform.py index 14e20e37f..85f3437a4 100644 --- a/openlp/plugins/bibles/forms/bibleupgradeform.py +++ b/openlp/plugins/bibles/forms/bibleupgradeform.py @@ -413,7 +413,7 @@ class BibleUpgradeForm(OpenLPWizard): if not backup_path: critical_error_message_box(UiStrings().EmptyField, translate('BiblesPlugin.UpgradeWizardForm', - 'You need to specify a backup Directory for your ' + 'You need to specify a backup directory for your ' 'Bibles.')) self.backupDirectoryEdit.setFocus() return False From 68c1c86ac5acfcc571e93a5574e936b269447883 Mon Sep 17 00:00:00 2001 From: Matthias Hub Date: Wed, 13 Jul 2011 22:41:54 +0200 Subject: [PATCH 099/184] - fixed view adjustments for os x 10.6 - added compatibility with the file extension on os x - started to work on the "open with" file event on os x --- openlp.pyw | 23 +++++ resources/osx/Info.plist.master | 93 ++++++++++++++++++ .../osx/applescript-adjustview-10-5.master | 2 +- .../osx/applescript-adjustview-10-6.master | 14 ++- resources/osx/build.py | 12 ++- resources/osx/openlp-logo-with-text.icns | Bin resources/osx/openlp.spec.master | 2 +- 7 files changed, 135 insertions(+), 11 deletions(-) mode change 100755 => 100644 resources/osx/openlp-logo-with-text.icns diff --git a/openlp.pyw b/openlp.pyw index a39f6cf65..d1627a8a6 100755 --- a/openlp.pyw +++ b/openlp.pyw @@ -90,6 +90,7 @@ class OpenLP(QtGui.QApplication): """ Run the OpenLP application. """ + self.eventQueue = [] # On Windows, the args passed into the constructor are # ignored. Not very handy, so set the ones we want to use. self.args = args @@ -135,6 +136,9 @@ class OpenLP(QtGui.QApplication): VersionThread(self.mainWindow).start() Receiver.send_message(u'maindisplay_blank_check') self.mainWindow.appStartup() + # do a check for queued events + for e in self.eventQueue: + self.event(e) DelayStartThread(self.mainWindow).start() return self.exec_() @@ -180,6 +184,25 @@ class OpenLP(QtGui.QApplication): """ self.restoreOverrideCursor() + def event(self, event): + """ + Enables direct file opening on OS X + """ + if event.type() == QtCore.QEvent.FileOpen: + file_name = event.file() + log.debug(u'Got open file event for %s!', file_name) + log.error(file_name) + try: + self.mainWindow.serviceManagerContents.loadFile(file_name) + return True + except AttributeError, NameError: + log.debug(u'The main window is not initialized yet,\ + will queue event!') + self.eventQueue.append(event) + return False + else: + return QtGui.QApplication.event(self, event) + def main(): """ The main function which parses command line options and then runs diff --git a/resources/osx/Info.plist.master b/resources/osx/Info.plist.master index 45aab92a5..5fc3aa48f 100755 --- a/resources/osx/Info.plist.master +++ b/resources/osx/Info.plist.master @@ -2,6 +2,99 @@ + + CFBundleDocumentTypes + + + CFBundleTypeExtension + + osz + + CFBundleTypeIconFiles + + openlp-logo-with-text.icns + + CFBundleTypeName + OpenLP Service + CFBundleTypeRole + Viewer + LSHandlerRank + Owner + LSItemContentTypes + + org.openlp.osz + + + + CFBundleTypeExtension + + otz + + CFBundleTypeIconFiles + + openlp-logo-with-text.icns + + CFBundleTypeName + OpenLP Theme + CFBundleTypeRole + Viewer + LSHandlerRank + Owner + LSItemContentTypes + + org.openlp.otz + + + + + UTExportedTypeDeclarations + + + UTTypeIdentifier + org.openlp.osz + UTTypeDescription + OpenLP Service + UTTypeConformsTo + + public.data + public.content + + UTTypeTagSpecification + + public.filename-extension + + osz + + public.mime-type + + application/x-openlp-service + + + + + UTTypeIdentifier + org.openlp.otz + UTTypeDescription + OpenLP Theme + UTTypeConformsTo + + public.data + public.content + + UTTypeTagSpecification + + public.filename-extension + + otz + + public.mime-type + + application/x-openlp-theme + + + + + CFBundleIdentifier org.openlp CFBundleShortVersionString diff --git a/resources/osx/applescript-adjustview-10-5.master b/resources/osx/applescript-adjustview-10-5.master index abc0e5a8d..19be239d0 100755 --- a/resources/osx/applescript-adjustview-10-5.master +++ b/resources/osx/applescript-adjustview-10-5.master @@ -48,7 +48,7 @@ on run set theViewOptions to the icon view options of container window set arrangement of theViewOptions to not arranged set icon size of theViewOptions to 128 - set background picture of theViewOptions to file ".installer-background.png" + set background picture of theViewOptions to file ".background:installer-background.png" if not exists file "Applications" then make new alias file at container window to POSIX file "/Applications" with properties {name:"Applications"} end if diff --git a/resources/osx/applescript-adjustview-10-6.master b/resources/osx/applescript-adjustview-10-6.master index 2b5a0c000..170842564 100755 --- a/resources/osx/applescript-adjustview-10-6.master +++ b/resources/osx/applescript-adjustview-10-6.master @@ -49,15 +49,19 @@ on run set theViewOptions to the icon view options of container window set arrangement of theViewOptions to not arranged set icon size of theViewOptions to 128 - set background picture of theViewOptions to file ".installer-background.png" - make new alias file at container window to POSIX file "/Applications" with properties {name:"Applications"} - delay 5 + set background picture of theViewOptions to file ".background:installer-background.png" + if not exists file "Applications" then + make new alias file at container window to POSIX file "/Applications" with properties {name:"Applications"} + end if + delay 1 set position of item "%s" of container window to {160, 200} set position of item ".Trashes" of container window to {100, 500} - set position of item ".installer-background.png" of container window to {200, 500} + set position of item ".background" of container window to {200, 500} set position of item ".DS_Store" of container window to {400, 500} set position of item "Applications" of container window to {550, 200} - set position of item ".VolumeIcon.icns" of container window to {500, 500} + if exists file ".VolumeIcon.icns" then + set position of item ".VolumeIcon.icns" of container window to {500, 500} + end if set position of item ".fseventsd" of container window to {300, 500} if exists POSIX file ".SymAVx86QSFile" then set position of item ".SymAVx86QSFile" of container window to {600, 500} diff --git a/resources/osx/build.py b/resources/osx/build.py index ff7f6bdfd..38e56e42a 100644 --- a/resources/osx/build.py +++ b/resources/osx/build.py @@ -93,8 +93,12 @@ script_name = "build" def build_application(settings, app_name_lower, app_dir): logging.info('[%s] now building the app with pyinstaller at "%s"...', script_name, settings['pyinstaller_basedir']) - result = os.system('python %s/pyinstaller.py openlp.spec' \ - % settings['pyinstaller_basedir']) + full_python_dir = os.path.join('/opt/local/Library/Frameworks', + 'Python.framework/Versions/2.6/Resources/', + 'Python.app/Contents/MacOS/Python') + result = os.system('arch -i386 %s %s/pyinstaller.py openlp.spec' \ + % ( full_python_dir, + settings['pyinstaller_basedir']) ) if (result != 0): logging.error('[%s] The pyinstaller build reported an error, cannot \ continue!', script_name) @@ -219,10 +223,10 @@ def create_dmg(settings): sys.exit(1) logging.info('[%s] copying the background image...', script_name) - # os.mkdir(volume_basedir + '/.background') + os.mkdir(volume_basedir + '/.background') result = os.system('CpMac %s %s' % (settings['installer_backgroundimage_file'], - volume_basedir + '/.installer-background.png')) + volume_basedir + '/.background/installer-background.png')) if (result != 0): logging.error('[%s] could not copy the background image, dmg creation\ failed!', script_name) diff --git a/resources/osx/openlp-logo-with-text.icns b/resources/osx/openlp-logo-with-text.icns old mode 100755 new mode 100644 diff --git a/resources/osx/openlp.spec.master b/resources/osx/openlp.spec.master index 94aec2a60..eb743c40b 100755 --- a/resources/osx/openlp.spec.master +++ b/resources/osx/openlp.spec.master @@ -1,5 +1,5 @@ # -*- mode: python -*- -a = Analysis([os.path.join(HOMEPATH,'support/_mountzlib.py'), os.path.join(HOMEPATH,'support/useUnicode.py'), '%(openlp_basedir)s/openlp.pyw'], +a = Analysis([os.path.join(HOMEPATH,'support/_mountzlib.py'), os.path.join(CONFIGDIR,'support/useUnicode.py'), '%(openlp_basedir)s/openlp.pyw'], pathex=['%(pyinstaller_basedir)s'], hookspath=['%(openlp_basedir)s/resources/pyinstaller']) pyz = PYZ(a.pure) exe = EXE(pyz, From 42acff98abd19c13b40dbc90f60f712fabedb267 Mon Sep 17 00:00:00 2001 From: Jon Tibble Date: Wed, 13 Jul 2011 22:00:35 +0100 Subject: [PATCH 100/184] Unused import --- openlp/core/lib/serviceitem.py | 1 - 1 file changed, 1 deletion(-) diff --git a/openlp/core/lib/serviceitem.py b/openlp/core/lib/serviceitem.py index 1245988b4..2aa1efbc2 100644 --- a/openlp/core/lib/serviceitem.py +++ b/openlp/core/lib/serviceitem.py @@ -36,7 +36,6 @@ import os import uuid from openlp.core.lib import build_icon, clean_tags, expand_tags, translate -from openlp.core.lib.ui import UiStrings log = logging.getLogger(__name__) From 3d3114b56dabc026d35793c71a879c41bf788d95 Mon Sep 17 00:00:00 2001 From: Andreas Preikschat Date: Fri, 15 Jul 2011 19:38:09 +0200 Subject: [PATCH 101/184] fixed copyright Fixes: https://launchpad.net/bugs/810633 --- scripts/check_dependencies.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/scripts/check_dependencies.py b/scripts/check_dependencies.py index bf9e97d88..7048ceeab 100755 --- a/scripts/check_dependencies.py +++ b/scripts/check_dependencies.py @@ -5,7 +5,12 @@ ############################################################################### # OpenLP - Open Source Lyrics Projection # # --------------------------------------------------------------------------- # -# Copyright (c) 2011 Raoul Snyman # +# Copyright (c) 2008-2011 Raoul Snyman # +# Portions copyright (c) 2008-2011 Tim Bentley, Gerald Britton, Jonathan # +# Corwin, Michael Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, # +# Armin Köhler, Joshua Millar, Stevan Pettit, Andreas Preikschat, Mattias # +# Põldaru, Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, # +# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund # # --------------------------------------------------------------------------- # # This program is free software; you can redistribute it and/or modify it # # under the terms of the GNU General Public License as published by the Free # From bc5d2cce46768b25d23067619fdd7ad4e94eb31d Mon Sep 17 00:00:00 2001 From: Andreas Preikschat Date: Fri, 15 Jul 2011 20:18:11 +0200 Subject: [PATCH 102/184] removed zip support for OpenSong importer Fixes: https://launchpad.net/bugs/795027 --- openlp/plugins/songs/lib/opensongimport.py | 44 ++-------------------- 1 file changed, 4 insertions(+), 40 deletions(-) diff --git a/openlp/plugins/songs/lib/opensongimport.py b/openlp/plugins/songs/lib/opensongimport.py index 3c8b46d4e..834255fd0 100644 --- a/openlp/plugins/songs/lib/opensongimport.py +++ b/openlp/plugins/songs/lib/opensongimport.py @@ -28,7 +28,6 @@ import logging import os import re -from zipfile import ZipFile from lxml import objectify from lxml.etree import Error, LxmlError @@ -110,48 +109,13 @@ class OpenSongImport(SongImport): SongImport.__init__(self, manager, **kwargs) def do_import(self): - """ - Import either each of the files in self.import_source - each element of - which can be either a single opensong file, or a zipfile containing - multiple opensong files. - """ - numfiles = 0 - for filename in self.import_source: - ext = os.path.splitext(filename)[1] - if ext.lower() == u'.zip': - z = ZipFile(filename, u'r') - numfiles += len(z.infolist()) - z.close() - else: - numfiles += 1 - log.debug(u'Total number of files: %d', numfiles) - self.import_wizard.progressBar.setMaximum(numfiles) + self.import_wizard.progressBar.setMaximum(len(self.import_source)) for filename in self.import_source: if self.stop_import_flag: return - ext = os.path.splitext(filename)[1] - if ext.lower() == u'.zip': - log.debug(u'Zipfile found %s', filename) - z = ZipFile(filename, u'r') - for song in z.infolist(): - if self.stop_import_flag: - z.close() - return - parts = os.path.split(song.filename) - if parts[-1] == u'': - # No final part => directory - continue - log.info(u'Zip importing %s', parts[-1]) - song_file = z.open(song) - self.do_import_file(song_file) - song_file.close() - z.close() - else: - # not a zipfile - log.info(u'Direct import %s', filename) - song_file = open(filename) - self.do_import_file(song_file) - song_file.close() + song_file = open(filename) + self.do_import_file(song_file) + song_file.close() def do_import_file(self, file): """ From b51f9b2a0c524502d951ba20d026941465f8b565 Mon Sep 17 00:00:00 2001 From: Andreas Preikschat Date: Sat, 16 Jul 2011 09:20:13 +0200 Subject: [PATCH 103/184] - do not set a service modified when using the up/down arrows to change the selected service item - only set the service modified when an item is selected while using the 'move button' and 'delete button' --- openlp/core/ui/servicemanager.py | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/openlp/core/ui/servicemanager.py b/openlp/core/ui/servicemanager.py index f6c069525..c6dfe77aa 100644 --- a/openlp/core/ui/servicemanager.py +++ b/openlp/core/ui/servicemanager.py @@ -802,7 +802,6 @@ class ServiceManager(QtGui.QWidget): # Top Item was selected so set the last one if setLastItem: lastItem.setSelected(True) - self.setModified() def onMoveSelectionDown(self): """ @@ -824,7 +823,6 @@ class ServiceManager(QtGui.QWidget): serviceIterator += 1 if setSelected: firstItem.setSelected(True) - self.setModified() def onCollapseAll(self): """ @@ -863,12 +861,12 @@ class ServiceManager(QtGui.QWidget): Move the current ServiceItem to the top of the list. """ item, child = self.findServiceItem() - if item < len(self.serviceItems) and item is not -1: + if item < len(self.serviceItems) and item != -1: temp = self.serviceItems[item] self.serviceItems.remove(self.serviceItems[item]) self.serviceItems.insert(0, temp) self.repaintServiceList(0, child) - self.setModified() + self.setModified() def onServiceUp(self): """ @@ -880,31 +878,31 @@ class ServiceManager(QtGui.QWidget): self.serviceItems.remove(self.serviceItems[item]) self.serviceItems.insert(item - 1, temp) self.repaintServiceList(item - 1, child) - self.setModified() + self.setModified() def onServiceDown(self): """ Move the current ServiceItem one position down in the list. """ item, child = self.findServiceItem() - if item < len(self.serviceItems) and item is not -1: + if item < len(self.serviceItems) and item != -1: temp = self.serviceItems[item] self.serviceItems.remove(self.serviceItems[item]) self.serviceItems.insert(item + 1, temp) self.repaintServiceList(item + 1, child) - self.setModified() + self.setModified() def onServiceEnd(self): """ Move the current ServiceItem to the bottom of the list. """ item, child = self.findServiceItem() - if item < len(self.serviceItems) and item is not -1: + if item < len(self.serviceItems) and item != -1: temp = self.serviceItems[item] self.serviceItems.remove(self.serviceItems[item]) self.serviceItems.insert(len(self.serviceItems), temp) self.repaintServiceList(len(self.serviceItems) - 1, child) - self.setModified() + self.setModified() def onDeleteFromService(self): """ @@ -914,7 +912,7 @@ class ServiceManager(QtGui.QWidget): if item != -1: self.serviceItems.remove(self.serviceItems[item]) self.repaintServiceList(item - 1, -1) - self.setModified() + self.setModified() def repaintServiceList(self, serviceItem, serviceItemChild): """ From 47e43404aaab2684f0fe2cfb19db01784289df28 Mon Sep 17 00:00:00 2001 From: Andreas Preikschat Date: Sat, 16 Jul 2011 11:00:30 +0200 Subject: [PATCH 104/184] - added doctype to html - added encoding to html - changed
to
- removed obsolete language attribute --- openlp/core/lib/__init__.py | 2 +- openlp/core/lib/displaytags.py | 2 +- openlp/core/lib/htmlbuilder.py | 8 ++++-- openlp/core/lib/renderer.py | 45 +++++++++++++++++++++--------- openlp/core/lib/serviceitem.py | 6 ++-- openlp/core/ui/printserviceform.py | 2 +- openlp/core/ui/servicemanager.py | 2 +- 7 files changed, 44 insertions(+), 23 deletions(-) diff --git a/openlp/core/lib/__init__.py b/openlp/core/lib/__init__.py index 187226272..7fbd5243c 100644 --- a/openlp/core/lib/__init__.py +++ b/openlp/core/lib/__init__.py @@ -202,7 +202,7 @@ def clean_tags(text): """ Remove Tags from text for display """ - text = text.replace(u'
', u'\n') + text = text.replace(u'
', u'\n') text = text.replace(u'{br}', u'\n') text = text.replace(u' ', u' ') for tag in DisplayTags.get_html_tags(): diff --git a/openlp/core/lib/displaytags.py b/openlp/core/lib/displaytags.py index addab4d75..95ce13bda 100644 --- a/openlp/core/lib/displaytags.py +++ b/openlp/core/lib/displaytags.py @@ -111,7 +111,7 @@ class DisplayTags(object): u'start html': u'', u'end tag': u'{/u}', u'end html': u'', u'protected': True}) base_tags.append({u'desc': translate('OpenLP.DisplayTags', 'Break'), - u'start tag': u'{br}', u'start html': u'
', u'end tag': u'', + u'start tag': u'{br}', u'start html': u'
', u'end tag': u'', u'end html': u'', u'protected': True}) DisplayTags.add_html_tags(base_tags) diff --git a/openlp/core/lib/htmlbuilder.py b/openlp/core/lib/htmlbuilder.py index 1f50e0d65..295a6c1ad 100644 --- a/openlp/core/lib/htmlbuilder.py +++ b/openlp/core/lib/htmlbuilder.py @@ -35,8 +35,10 @@ from openlp.core.lib.theme import BackgroundType, BackgroundGradientType, \ log = logging.getLogger(__name__) HTMLSRC = u""" + + OpenLP Display - +
""" % \ (build_lyrics_format_css(self.theme_data, self.page_width, self.page_height), build_lyrics_outline_css(self.theme_data)) + self.web.setHtml(html) def _paginate_slide(self, lines, line_end): """ @@ -334,10 +340,8 @@ class Renderer(object): previous_raw = u'' separator = u'
' html_lines = map(expand_tags, lines) - html = self.page_shell + separator.join(html_lines) + HTML_END - self.web.setHtml(html) # Text too long so go to next page. - if self.web_frame.contentsSize().height() > self.page_height: + if self._text_fits_on_slide(separator.join(html_lines)): html_text, previous_raw = self._binary_chop(formatted, previous_html, previous_raw, html_lines, lines, separator, u'') else: @@ -368,27 +372,19 @@ class Renderer(object): for line in lines: line = line.strip() html_line = expand_tags(line) - html = self.page_shell + previous_html + html_line + HTML_END - self.web.setHtml(html) # Text too long so go to next page. - if self.web_frame.contentsSize().height() > self.page_height: + if self._text_fits_on_slide(previous_html + html_line): # Check if there was a verse before the current one and append # it, when it fits on the page. if previous_html: - html = self.page_shell + previous_html + HTML_END - self.web.setHtml(html) - if self.web_frame.contentsSize().height() <= \ - self.page_height: + if not self._text_fits_on_slide(previous_html): formatted.append(previous_raw) previous_html = u'' previous_raw = u'' - html = self.page_shell + html_line + HTML_END - self.web.setHtml(html) # Now check if the current verse will fit, if it does # not we have to start to process the verse word by # word. - if self.web_frame.contentsSize().height() <= \ - self.page_height: + if not self._text_fits_on_slide(html_line): previous_html = html_line + line_end previous_raw = line + line_end continue @@ -445,10 +441,8 @@ class Renderer(object): highest_index = len(html_list) - 1 index = int(highest_index / 2) while True: - html = self.page_shell + previous_html + \ - separator.join(html_list[:index + 1]).strip() + HTML_END - self.web.setHtml(html) - if self.web_frame.contentsSize().height() > self.page_height: + if self._text_fits_on_slide( + previous_html + separator.join(html_list[:index + 1]).strip()): # We know that it does not fit, so change/calculate the # new index and highest_index accordingly. highest_index = index @@ -470,10 +464,8 @@ class Renderer(object): else: continue # Check if the remaining elements fit on the slide. - html = self.page_shell + \ - separator.join(html_list[index + 1:]).strip() + HTML_END - self.web.setHtml(html) - if self.web_frame.contentsSize().height() <= self.page_height: + if not self._text_fits_on_slide( + separator.join(html_list[index + 1:]).strip()): previous_html = separator.join( html_list[index + 1:]).strip() + line_end previous_raw = separator.join( @@ -489,6 +481,18 @@ class Renderer(object): index = int(highest_index / 2) return previous_html, previous_raw + def _text_fits_on_slide(self, text): + """ + Checks if the given ``text`` fits on a slide. If it does, ``True`` is + returned, otherwise ``False``. + + ``text`` + The text to check. It can contain HTML tags. + """ + self.web_frame.evaluateJavaScript(u'show_text("%s")' % + text.replace(u'\\', u'\\\\').replace(u'\"', u'\\\"')) + return self.web_frame.contentsSize().height() > self.page_height + def _words_split(self, line): """ Split the slide up by word so can wrap better diff --git a/openlp/core/ui/maindisplay.py b/openlp/core/ui/maindisplay.py index d5603c31f..9904868ce 100644 --- a/openlp/core/ui/maindisplay.py +++ b/openlp/core/ui/maindisplay.py @@ -188,7 +188,7 @@ class MainDisplay(QtGui.QGraphicsView): while not self.webLoaded: Receiver.send_message(u'openlp_process_events') self.setGeometry(self.screen[u'size']) - self.frame.evaluateJavaScript(u'show_text("%s")' % \ + self.frame.evaluateJavaScript(u'show_text("%s")' % slide.replace(u'\\', u'\\\\').replace(u'\"', u'\\\"')) return self.preview() From 77f7581d22633f70421144ff4896425920643a50 Mon Sep 17 00:00:00 2001 From: Andreas Preikschat Date: Sat, 30 Jul 2011 09:14:39 +0200 Subject: [PATCH 135/184] change 'Display Tag' strings to 'Formatting Tag' Fixes: https://launchpad.net/bugs/816382 --- openlp/core/ui/mainwindow.py | 2 +- openlp/core/ui/shortcutlistdialog.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/openlp/core/ui/mainwindow.py b/openlp/core/ui/mainwindow.py index c88508672..f3a5e2cb9 100644 --- a/openlp/core/ui/mainwindow.py +++ b/openlp/core/ui/mainwindow.py @@ -404,7 +404,7 @@ class Ui_MainWindow(object): self.settingsShortcutsItem.setText( translate('OpenLP.MainWindow', 'Configure &Shortcuts...')) self.displayTagItem.setText( - translate('OpenLP.MainWindow', '&Configure Display Tags')) + translate('OpenLP.MainWindow', '&Configure Formatting Tags...')) self.settingsConfigureItem.setText( translate('OpenLP.MainWindow', '&Configure OpenLP...')) self.viewMediaManagerItem.setText( diff --git a/openlp/core/ui/shortcutlistdialog.py b/openlp/core/ui/shortcutlistdialog.py index 6d877358f..a9b9b22cf 100644 --- a/openlp/core/ui/shortcutlistdialog.py +++ b/openlp/core/ui/shortcutlistdialog.py @@ -123,7 +123,7 @@ class Ui_ShortcutListDialog(object): def retranslateUi(self, shortcutListDialog): shortcutListDialog.setWindowTitle( - translate('OpenLP.ShortcutListDialog', 'Customize Shortcuts')) + translate('OpenLP.ShortcutListDialog', 'Configure Shortcuts')) self.descriptionLabel.setText(translate('OpenLP.ShortcutListDialog', 'Select an action and click one of the buttons below to start ' 'capturing a new primary or alternate shortcut, respectively.')) From 06d32e51083b34c2d9dd1289b2c39994719d4e78 Mon Sep 17 00:00:00 2001 From: Andreas Preikschat Date: Sat, 30 Jul 2011 09:19:16 +0200 Subject: [PATCH 136/184] change 'Display Tag' strings to 'Formatting Tag' Fixes: https://launchpad.net/bugs/816382 --- openlp/core/lib/displaytags.py | 2 +- openlp/core/lib/renderer.py | 4 ++-- openlp/core/ui/displaytagdialog.py | 2 +- openlp/core/ui/displaytagform.py | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/openlp/core/lib/displaytags.py b/openlp/core/lib/displaytags.py index 95ce13bda..aa6f3b5a7 100644 --- a/openlp/core/lib/displaytags.py +++ b/openlp/core/lib/displaytags.py @@ -25,7 +25,7 @@ # Temple Place, Suite 330, Boston, MA 02111-1307 USA # ############################################################################### """ -Provide Html Tag management and Display Tag access class +Provide HTML Tag management and Formatting Tag access class """ from openlp.core.lib import translate diff --git a/openlp/core/lib/renderer.py b/openlp/core/lib/renderer.py index e9e28bcf6..1b94e7896 100644 --- a/openlp/core/lib/renderer.py +++ b/openlp/core/lib/renderer.py @@ -422,7 +422,7 @@ class Renderer(object): to the list of slides. (unicode string) ``previous_raw`` - The raw text (with display tags) which is know to fit on a slide, + The raw text (with formatting tags) which is know to fit on a slide, but is not yet added to the list of slides. (unicode string) ``html_list`` @@ -431,7 +431,7 @@ class Renderer(object): ``raw_list`` The elements which do not fit on a slide and needs to be processed - using the binary chop. The elements can contain display tags. + using the binary chop. The elements can contain formatting tags. ``separator`` The separator for the elements. For lines this is ``u'
'`` and diff --git a/openlp/core/ui/displaytagdialog.py b/openlp/core/ui/displaytagdialog.py index 328fcd137..093e0c167 100644 --- a/openlp/core/ui/displaytagdialog.py +++ b/openlp/core/ui/displaytagdialog.py @@ -122,7 +122,7 @@ class Ui_DisplayTagDialog(object): def retranslateUi(self, displayTagDialog): displayTagDialog.setWindowTitle(translate('OpenLP.displayTagDialog', - 'Configure Display Tags')) + 'Configure Formatting Tags')) self.editGroupBox.setTitle( translate('OpenLP.DisplayTagDialog', 'Edit Selection')) self.savePushButton.setText( diff --git a/openlp/core/ui/displaytagform.py b/openlp/core/ui/displaytagform.py index 22ac38f06..9456f1028 100644 --- a/openlp/core/ui/displaytagform.py +++ b/openlp/core/ui/displaytagform.py @@ -177,7 +177,7 @@ class DisplayTagForm(QtGui.QDialog, Ui_DisplayTagDialog): def _saveTable(self): """ - Saves all display tags except protected ones. + Saves all formatting tags except protected ones. """ tags = [] for tag in DisplayTags.get_html_tags(): From c0976a4690f43655548c3c6dc3ece0edc0ff5e0f Mon Sep 17 00:00:00 2001 From: Andreas Preikschat Date: Sat, 30 Jul 2011 09:34:37 +0200 Subject: [PATCH 137/184] moved files and changed code to reflect string changes Fixes: https://launchpad.net/bugs/816382 --- openlp/core/lib/__init__.py | 6 +-- .../lib/{displaytags.py => formattingtags.py} | 44 ++++++++-------- openlp/core/lib/spelltextedit.py | 6 +-- openlp/core/ui/__init__.py | 2 +- ...laytagdialog.py => formattingtagdialog.py} | 50 +++++++++---------- ...displaytagform.py => formattingtagform.py} | 48 +++++++++--------- openlp/core/ui/mainwindow.py | 21 ++++---- 7 files changed, 88 insertions(+), 89 deletions(-) rename openlp/core/lib/{displaytags.py => formattingtags.py} (78%) rename openlp/core/ui/{displaytagdialog.py => formattingtagdialog.py} (82%) rename openlp/core/ui/{displaytagform.py => formattingtagform.py} (87%) diff --git a/openlp/core/lib/__init__.py b/openlp/core/lib/__init__.py index 7fbd5243c..620d5dafd 100644 --- a/openlp/core/lib/__init__.py +++ b/openlp/core/lib/__init__.py @@ -205,7 +205,7 @@ def clean_tags(text): text = text.replace(u'
', u'\n') text = text.replace(u'{br}', u'\n') text = text.replace(u' ', u' ') - for tag in DisplayTags.get_html_tags(): + for tag in FormattingTags.get_html_tags(): text = text.replace(tag[u'start tag'], u'') text = text.replace(tag[u'end tag'], u'') return text @@ -214,7 +214,7 @@ def expand_tags(text): """ Expand tags HTML for display """ - for tag in DisplayTags.get_html_tags(): + for tag in FormattingTags.get_html_tags(): text = text.replace(tag[u'start tag'], tag[u'start html']) text = text.replace(tag[u'end tag'], tag[u'end html']) return text @@ -234,7 +234,7 @@ def check_directory_exists(dir): pass from listwidgetwithdnd import ListWidgetWithDnD -from displaytags import DisplayTags +from formattingtags import FormattingTags from eventreceiver import Receiver from spelltextedit import SpellTextEdit from settingsmanager import SettingsManager diff --git a/openlp/core/lib/displaytags.py b/openlp/core/lib/formattingtags.py similarity index 78% rename from openlp/core/lib/displaytags.py rename to openlp/core/lib/formattingtags.py index aa6f3b5a7..9fd42a605 100644 --- a/openlp/core/lib/displaytags.py +++ b/openlp/core/lib/formattingtags.py @@ -30,7 +30,7 @@ Provide HTML Tag management and Formatting Tag access class from openlp.core.lib import translate -class DisplayTags(object): +class FormattingTags(object): """ Static Class to HTML Tags to be access around the code the list is managed by the Options Tab. @@ -42,89 +42,89 @@ class DisplayTags(object): """ Provide access to the html_expands list. """ - return DisplayTags.html_expands + return FormattingTags.html_expands @staticmethod def reset_html_tags(): """ Resets the html_expands list. """ - DisplayTags.html_expands = [] + FormattingTags.html_expands = [] base_tags = [] # Append the base tags. # Hex Color tags from http://www.w3schools.com/html/html_colornames.asp - base_tags.append({u'desc': translate('OpenLP.DisplayTags', 'Red'), + base_tags.append({u'desc': translate('OpenLP.FormattingTags', 'Red'), u'start tag': u'{r}', u'start html': u'', u'end tag': u'{/r}', u'end html': u'', u'protected': True}) - base_tags.append({u'desc': translate('OpenLP.DisplayTags', 'Black'), + base_tags.append({u'desc': translate('OpenLP.FormattingTags', 'Black'), u'start tag': u'{b}', u'start html': u'', u'end tag': u'{/b}', u'end html': u'', u'protected': True}) - base_tags.append({u'desc': translate('OpenLP.DisplayTags', 'Blue'), + base_tags.append({u'desc': translate('OpenLP.FormattingTags', 'Blue'), u'start tag': u'{bl}', u'start html': u'', u'end tag': u'{/bl}', u'end html': u'', u'protected': True}) - base_tags.append({u'desc': translate('OpenLP.DisplayTags', 'Yellow'), + base_tags.append({u'desc': translate('OpenLP.FormattingTags', 'Yellow'), u'start tag': u'{y}', u'start html': u'', u'end tag': u'{/y}', u'end html': u'', u'protected': True}) - base_tags.append({u'desc': translate('OpenLP.DisplayTags', 'Green'), + base_tags.append({u'desc': translate('OpenLP.FormattingTags', 'Green'), u'start tag': u'{g}', u'start html': u'', u'end tag': u'{/g}', u'end html': u'', u'protected': True}) - base_tags.append({u'desc': translate('OpenLP.DisplayTags', 'Pink'), + base_tags.append({u'desc': translate('OpenLP.FormattingTags', 'Pink'), u'start tag': u'{pk}', u'start html': u'', u'end tag': u'{/pk}', u'end html': u'', u'protected': True}) - base_tags.append({u'desc': translate('OpenLP.DisplayTags', 'Orange'), + base_tags.append({u'desc': translate('OpenLP.FormattingTags', 'Orange'), u'start tag': u'{o}', u'start html': u'', u'end tag': u'{/o}', u'end html': u'', u'protected': True}) - base_tags.append({u'desc': translate('OpenLP.DisplayTags', 'Purple'), + base_tags.append({u'desc': translate('OpenLP.FormattingTags', 'Purple'), u'start tag': u'{pp}', u'start html': u'', u'end tag': u'{/pp}', u'end html': u'', u'protected': True}) - base_tags.append({u'desc': translate('OpenLP.DisplayTags', 'White'), + base_tags.append({u'desc': translate('OpenLP.FormattingTags', 'White'), u'start tag': u'{w}', u'start html': u'', u'end tag': u'{/w}', u'end html': u'', u'protected': True}) base_tags.append({ - u'desc': translate('OpenLP.DisplayTags', 'Superscript'), + u'desc': translate('OpenLP.FormattingTags', 'Superscript'), u'start tag': u'{su}', u'start html': u'', u'end tag': u'{/su}', u'end html': u'', u'protected': True}) - base_tags.append({u'desc': translate('OpenLP.DisplayTags', 'Subscript'), + base_tags.append({u'desc': translate('OpenLP.FormattingTags', 'Subscript'), u'start tag': u'{sb}', u'start html': u'', u'end tag': u'{/sb}', u'end html': u'', u'protected': True}) - base_tags.append({u'desc': translate('OpenLP.DisplayTags', 'Paragraph'), + base_tags.append({u'desc': translate('OpenLP.FormattingTags', 'Paragraph'), u'start tag': u'{p}', u'start html': u'

', u'end tag': u'{/p}', u'end html': u'

', u'protected': True}) - base_tags.append({u'desc': translate('OpenLP.DisplayTags', 'Bold'), + base_tags.append({u'desc': translate('OpenLP.FormattingTags', 'Bold'), u'start tag': u'{st}', u'start html': u'', u'end tag': u'{/st}', u'end html': u'', u'protected': True}) - base_tags.append({u'desc': translate('OpenLP.DisplayTags', 'Italics'), + base_tags.append({u'desc': translate('OpenLP.FormattingTags', 'Italics'), u'start tag': u'{it}', u'start html': u'', u'end tag': u'{/it}', u'end html': u'', u'protected': True}) - base_tags.append({u'desc': translate('OpenLP.DisplayTags', 'Underline'), + base_tags.append({u'desc': translate('OpenLP.FormattingTags', 'Underline'), u'start tag': u'{u}', u'start html': u'', u'end tag': u'{/u}', u'end html': u'', u'protected': True}) - base_tags.append({u'desc': translate('OpenLP.DisplayTags', 'Break'), + base_tags.append({u'desc': translate('OpenLP.FormattingTags', 'Break'), u'start tag': u'{br}', u'start html': u'
', u'end tag': u'', u'end html': u'', u'protected': True}) - DisplayTags.add_html_tags(base_tags) + FormattingTags.add_html_tags(base_tags) @staticmethod def add_html_tags(tags): """ Add a list of tags to the list """ - DisplayTags.html_expands.extend(tags) + FormattingTags.html_expands.extend(tags) @staticmethod def remove_html_tag(tag_id): """ Removes an individual html_expands tag. """ - DisplayTags.html_expands.pop(tag_id) + FormattingTags.html_expands.pop(tag_id) diff --git a/openlp/core/lib/spelltextedit.py b/openlp/core/lib/spelltextedit.py index 0d277b9fe..b0bb61e92 100644 --- a/openlp/core/lib/spelltextedit.py +++ b/openlp/core/lib/spelltextedit.py @@ -39,7 +39,7 @@ except ImportError: from PyQt4 import QtCore, QtGui -from openlp.core.lib import translate, DisplayTags +from openlp.core.lib import translate, FormattingTags from openlp.core.lib.ui import checkable_action log = logging.getLogger(__name__) @@ -114,7 +114,7 @@ class SpellTextEdit(QtGui.QPlainTextEdit): popupMenu.insertMenu(popupMenu.actions()[0], spell_menu) tagMenu = QtGui.QMenu(translate('OpenLP.SpellTextEdit', 'Formatting Tags')) - for html in DisplayTags.get_html_tags(): + for html in FormattingTags.get_html_tags(): action = SpellAction(html[u'desc'], tagMenu) action.correct.connect(self.htmlTag) tagMenu.addAction(action) @@ -148,7 +148,7 @@ class SpellTextEdit(QtGui.QPlainTextEdit): """ Replaces the selected text with word. """ - for html in DisplayTags.get_html_tags(): + for html in FormattingTags.get_html_tags(): if tag == html[u'desc']: cursor = self.textCursor() if self.textCursor().hasSelection(): diff --git a/openlp/core/ui/__init__.py b/openlp/core/ui/__init__.py index 7aebcb1df..e754480e0 100644 --- a/openlp/core/ui/__init__.py +++ b/openlp/core/ui/__init__.py @@ -69,7 +69,7 @@ from advancedtab import AdvancedTab from aboutform import AboutForm from pluginform import PluginForm from settingsform import SettingsForm -from displaytagform import DisplayTagForm +from formattingtagform import FormattingTagForm from shortcutlistform import ShortcutListForm from mediadockmanager import MediaDockManager from servicemanager import ServiceManager diff --git a/openlp/core/ui/displaytagdialog.py b/openlp/core/ui/formattingtagdialog.py similarity index 82% rename from openlp/core/ui/displaytagdialog.py rename to openlp/core/ui/formattingtagdialog.py index 093e0c167..186f4739b 100644 --- a/openlp/core/ui/displaytagdialog.py +++ b/openlp/core/ui/formattingtagdialog.py @@ -30,15 +30,15 @@ from PyQt4 import QtCore, QtGui from openlp.core.lib import translate from openlp.core.lib.ui import UiStrings -class Ui_DisplayTagDialog(object): +class Ui_FormattingTagDialog(object): - def setupUi(self, displayTagDialog): - displayTagDialog.setObjectName(u'displayTagDialog') - displayTagDialog.resize(725, 548) - self.listdataGridLayout = QtGui.QGridLayout(displayTagDialog) + def setupUi(self, formattingTagDialog): + formattingTagDialog.setObjectName(u'formattingTagDialog') + formattingTagDialog.resize(725, 548) + self.listdataGridLayout = QtGui.QGridLayout(formattingTagDialog) self.listdataGridLayout.setMargin(8) self.listdataGridLayout.setObjectName(u'listdataGridLayout') - self.tagTableWidget = QtGui.QTableWidget(displayTagDialog) + self.tagTableWidget = QtGui.QTableWidget(formattingTagDialog) self.tagTableWidget.setHorizontalScrollBarPolicy( QtCore.Qt.ScrollBarAlwaysOff) self.tagTableWidget.setEditTriggers( @@ -67,11 +67,11 @@ class Ui_DisplayTagDialog(object): spacerItem = QtGui.QSpacerItem(40, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum) self.horizontalLayout.addItem(spacerItem) - self.deletePushButton = QtGui.QPushButton(displayTagDialog) + self.deletePushButton = QtGui.QPushButton(formattingTagDialog) self.deletePushButton.setObjectName(u'deletePushButton') self.horizontalLayout.addWidget(self.deletePushButton) self.listdataGridLayout.addLayout(self.horizontalLayout, 1, 0, 1, 1) - self.editGroupBox = QtGui.QGroupBox(displayTagDialog) + self.editGroupBox = QtGui.QGroupBox(formattingTagDialog) self.editGroupBox.setObjectName(u'editGroupBox') self.dataGridLayout = QtGui.QGridLayout(self.editGroupBox) self.dataGridLayout.setObjectName(u'dataGridLayout') @@ -112,38 +112,38 @@ class Ui_DisplayTagDialog(object): self.savePushButton.setObjectName(u'savePushButton') self.dataGridLayout.addWidget(self.savePushButton, 4, 2, 1, 1) self.listdataGridLayout.addWidget(self.editGroupBox, 2, 0, 1, 1) - self.buttonBox = QtGui.QDialogButtonBox(displayTagDialog) - self.buttonBox.setObjectName('displayTagDialogButtonBox') + self.buttonBox = QtGui.QDialogButtonBox(formattingTagDialog) + self.buttonBox.setObjectName('formattingTagDialogButtonBox') self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Close) self.listdataGridLayout.addWidget(self.buttonBox, 3, 0, 1, 1) - self.retranslateUi(displayTagDialog) - QtCore.QMetaObject.connectSlotsByName(displayTagDialog) + self.retranslateUi(formattingTagDialog) + QtCore.QMetaObject.connectSlotsByName(formattingTagDialog) - def retranslateUi(self, displayTagDialog): - displayTagDialog.setWindowTitle(translate('OpenLP.displayTagDialog', - 'Configure Formatting Tags')) + def retranslateUi(self, formattingTagDialog): + formattingTagDialog.setWindowTitle(translate( + 'OpenLP.FormattingTagDialog', 'Configure Formatting Tags')) self.editGroupBox.setTitle( - translate('OpenLP.DisplayTagDialog', 'Edit Selection')) + translate('OpenLP.FormattingTagDialog', 'Edit Selection')) self.savePushButton.setText( - translate('OpenLP.DisplayTagDialog', 'Save')) + translate('OpenLP.FormattingTagDialog', 'Save')) self.descriptionLabel.setText( - translate('OpenLP.DisplayTagDialog', 'Description')) - self.tagLabel.setText(translate('OpenLP.DisplayTagDialog', 'Tag')) + translate('OpenLP.FormattingTagDialog', 'Description')) + self.tagLabel.setText(translate('OpenLP.FormattingTagDialog', 'Tag')) self.startTagLabel.setText( - translate('OpenLP.DisplayTagDialog', 'Start tag')) + translate('OpenLP.FormattingTagDialog', 'Start tag')) self.endTagLabel.setText( - translate('OpenLP.DisplayTagDialog', 'End tag')) + translate('OpenLP.FormattingTagDialog', 'End tag')) self.deletePushButton.setText(UiStrings().Delete) self.newPushButton.setText(UiStrings().New) self.tagTableWidget.horizontalHeaderItem(0).setText( - translate('OpenLP.DisplayTagDialog', 'Description')) + translate('OpenLP.FormattingTagDialog', 'Description')) self.tagTableWidget.horizontalHeaderItem(1).setText( - translate('OpenLP.DisplayTagDialog', 'Tag Id')) + translate('OpenLP.FormattingTagDialog', 'Tag Id')) self.tagTableWidget.horizontalHeaderItem(2).setText( - translate('OpenLP.DisplayTagDialog', 'Start HTML')) + translate('OpenLP.FormattingTagDialog', 'Start HTML')) self.tagTableWidget.horizontalHeaderItem(3).setText( - translate('OpenLP.DisplayTagDialog', 'End HTML')) + translate('OpenLP.FormattingTagDialog', 'End HTML')) self.tagTableWidget.setColumnWidth(0, 120) self.tagTableWidget.setColumnWidth(1, 80) self.tagTableWidget.setColumnWidth(2, 330) diff --git a/openlp/core/ui/displaytagform.py b/openlp/core/ui/formattingtagform.py similarity index 87% rename from openlp/core/ui/displaytagform.py rename to openlp/core/ui/formattingtagform.py index 9456f1028..7312ffa7b 100644 --- a/openlp/core/ui/displaytagform.py +++ b/openlp/core/ui/formattingtagform.py @@ -25,22 +25,22 @@ # Temple Place, Suite 330, Boston, MA 02111-1307 USA # ############################################################################### """ -The :mod:`DisplayTagTab` provides an Tag Edit facility. The Base set are -protected and included each time loaded. Custom tags can be defined and saved. -The Custom Tag arrays are saved in a pickle so QSettings works on them. Base +The :mod:`DisplayTagTab` provides an Tag Edit facility. The Base set are +protected and included each time loaded. Custom tags can be defined and saved. +The Custom Tag arrays are saved in a pickle so QSettings works on them. Base Tags cannot be changed. """ import cPickle from PyQt4 import QtCore, QtGui -from openlp.core.lib import translate, DisplayTags +from openlp.core.lib import translate, FormattingTags from openlp.core.lib.ui import critical_error_message_box -from openlp.core.ui.displaytagdialog import Ui_DisplayTagDialog +from openlp.core.ui.formattingtagdialog import Ui_FormattingTagDialog -class DisplayTagForm(QtGui.QDialog, Ui_DisplayTagDialog): +class FormattingTagForm(QtGui.QDialog, Ui_FormattingTagDialog): """ - The :class:`DisplayTagTab` manages the settings tab . + The :class:`FormattingTagForm` manages the settings tab . """ def __init__(self, parent): """ @@ -48,7 +48,7 @@ class DisplayTagForm(QtGui.QDialog, Ui_DisplayTagDialog): """ QtGui.QDialog.__init__(self, parent) self.setupUi(self) - self._loadDisplayTags() + self._loadFormattingTags() QtCore.QObject.connect(self.tagTableWidget, QtCore.SIGNAL(u'clicked(QModelIndex)'), self.onRowSelected) QtCore.QObject.connect(self.newPushButton, @@ -65,19 +65,20 @@ class DisplayTagForm(QtGui.QDialog, Ui_DisplayTagDialog): Load Display and set field state. """ # Create initial copy from master - self._loadDisplayTags() + self._loadFormattingTags() self._resetTable() self.selected = -1 return QtGui.QDialog.exec_(self) - def _loadDisplayTags(self): + def _loadFormattingTags(self): """ Load the Tags from store so can be used in the system or used to update the display. If Cancel was selected this is needed to reset the dsiplay to the correct version. """ # Initial Load of the Tags - DisplayTags.reset_html_tags() + FormattingTags.reset_html_tags() + # Formatting Tags where also known as display tags. user_expands = QtCore.QSettings().value(u'displayTags/html_tags', QtCore.QVariant(u'')).toString() # cPickle only accepts str not unicode strings @@ -85,14 +86,14 @@ class DisplayTagForm(QtGui.QDialog, Ui_DisplayTagDialog): if user_expands_string: user_tags = cPickle.loads(user_expands_string) # If we have some user ones added them as well - DisplayTags.add_html_tags(user_tags) + FormattingTags.add_html_tags(user_tags) def onRowSelected(self): """ Table Row selected so display items and set field state. """ row = self.tagTableWidget.currentRow() - html = DisplayTags.get_html_tags()[row] + html = FormattingTags.get_html_tags()[row] self.selected = row self.descriptionLineEdit.setText(html[u'desc']) self.tagLineEdit.setText(self._strip(html[u'start tag'])) @@ -117,7 +118,7 @@ class DisplayTagForm(QtGui.QDialog, Ui_DisplayTagDialog): """ Add a new tag to list only if it is not a duplicate. """ - for html in DisplayTags.get_html_tags(): + for html in FormattingTags.get_html_tags(): if self._strip(html[u'start tag']) == u'n': critical_error_message_box( translate('OpenLP.DisplayTagTab', 'Update Error'), @@ -133,7 +134,7 @@ class DisplayTagForm(QtGui.QDialog, Ui_DisplayTagDialog): u'end html': translate('OpenLP.DisplayTagTab', ''), u'protected': False } - DisplayTags.add_html_tags([tag]) + FormattingTags.add_html_tags([tag]) self._resetTable() # Highlight new row self.tagTableWidget.selectRow(self.tagTableWidget.rowCount() - 1) @@ -145,7 +146,7 @@ class DisplayTagForm(QtGui.QDialog, Ui_DisplayTagDialog): Delete selected custom tag. """ if self.selected != -1: - DisplayTags.remove_html_tag(self.selected) + FormattingTags.remove_html_tag(self.selected) self.selected = -1 self._resetTable() self._saveTable() @@ -154,7 +155,7 @@ class DisplayTagForm(QtGui.QDialog, Ui_DisplayTagDialog): """ Update Custom Tag details if not duplicate and save the data. """ - html_expands = DisplayTags.get_html_tags() + html_expands = FormattingTags.get_html_tags() if self.selected != -1: html = html_expands[self.selected] tag = unicode(self.tagLineEdit.text()) @@ -180,15 +181,12 @@ class DisplayTagForm(QtGui.QDialog, Ui_DisplayTagDialog): Saves all formatting tags except protected ones. """ tags = [] - for tag in DisplayTags.get_html_tags(): + for tag in FormattingTags.get_html_tags(): if not tag[u'protected']: tags.append(tag) - if tags: - QtCore.QSettings().setValue(u'displayTags/html_tags', - QtCore.QVariant(cPickle.dumps(tags))) - else: - QtCore.QSettings().setValue(u'displayTags/html_tags', - QtCore.QVariant(u'')) + # Formatting Tags where also known as display tags. + QtCore.QSettings().setValue(u'displayTags/html_tags', + QtCore.QVariant(cPickle.dumps(tags) if tags else u'')) def _resetTable(self): """ @@ -199,7 +197,7 @@ class DisplayTagForm(QtGui.QDialog, Ui_DisplayTagDialog): self.newPushButton.setEnabled(True) self.savePushButton.setEnabled(False) self.deletePushButton.setEnabled(False) - for linenumber, html in enumerate(DisplayTags.get_html_tags()): + for linenumber, html in enumerate(FormattingTags.get_html_tags()): self.tagTableWidget.setRowCount( self.tagTableWidget.rowCount() + 1) self.tagTableWidget.setItem(linenumber, 0, diff --git a/openlp/core/ui/mainwindow.py b/openlp/core/ui/mainwindow.py index f3a5e2cb9..16691e5a0 100644 --- a/openlp/core/ui/mainwindow.py +++ b/openlp/core/ui/mainwindow.py @@ -38,7 +38,7 @@ from openlp.core.lib.ui import UiStrings, base_action, checkable_action, \ icon_action, shortcut_action from openlp.core.ui import AboutForm, SettingsForm, ServiceManager, \ ThemeManager, SlideController, PluginForm, MediaDockManager, \ - ShortcutListForm, DisplayTagForm + ShortcutListForm, FormattingTagForm from openlp.core.utils import AppLocation, add_actions, LanguageManager, \ get_application_version, delete_file from openlp.core.utils.actions import ActionList, CategoryOrder @@ -269,7 +269,8 @@ class Ui_MainWindow(object): u'settingsShortcutsItem', u':/system/system_configure_shortcuts.png', category=UiStrings().Settings) - self.displayTagItem = icon_action(mainWindow, + # Formatting Tags where also known as display tags. + self.formattingTagItem = icon_action(mainWindow, u'displayTagItem', u':/system/tag_editor.png', category=UiStrings().Settings) self.settingsConfigureItem = icon_action(mainWindow, @@ -315,11 +316,11 @@ class Ui_MainWindow(object): add_actions(self.settingsMenu, (self.settingsPluginListItem, self.settingsLanguageMenu.menuAction(), None, self.settingsConfigureItem, self.settingsShortcutsItem, - self.displayTagItem)) + self.formattingTagItem)) else: add_actions(self.settingsMenu, (self.settingsPluginListItem, self.settingsLanguageMenu.menuAction(), None, - self.displayTagItem, self.settingsShortcutsItem, + self.formattingTagItem, self.settingsShortcutsItem, self.settingsConfigureItem)) add_actions(self.toolsMenu, (self.toolsAddToolItem, None)) add_actions(self.toolsMenu, (self.toolsOpenDataFolder, None)) @@ -403,7 +404,7 @@ class Ui_MainWindow(object): translate('OpenLP.MainWindow', '&Language')) self.settingsShortcutsItem.setText( translate('OpenLP.MainWindow', 'Configure &Shortcuts...')) - self.displayTagItem.setText( + self.formattingTagItem.setText( translate('OpenLP.MainWindow', '&Configure Formatting Tags...')) self.settingsConfigureItem.setText( translate('OpenLP.MainWindow', '&Configure OpenLP...')) @@ -511,7 +512,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): self.serviceNotSaved = False self.aboutForm = AboutForm(self) self.settingsForm = SettingsForm(self, self) - self.displayTagForm = DisplayTagForm(self) + self.formattingTagForm = FormattingTagForm(self) self.shortcutForm = ShortcutListForm(self) self.recentFiles = QtCore.QStringList() # Set up the path with plugins @@ -548,8 +549,8 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): QtCore.SIGNAL(u'triggered()'), self.onToolsOpenDataFolderClicked) QtCore.QObject.connect(self.updateThemeImages, QtCore.SIGNAL(u'triggered()'), self.onUpdateThemeImages) - QtCore.QObject.connect(self.displayTagItem, - QtCore.SIGNAL(u'triggered()'), self.onDisplayTagItemClicked) + QtCore.QObject.connect(self.formattingTagItem, + QtCore.SIGNAL(u'triggered()'), self.onFormattingTagItemClicked) QtCore.QObject.connect(self.settingsConfigureItem, QtCore.SIGNAL(u'triggered()'), self.onSettingsConfigureItemClicked) QtCore.QObject.connect(self.settingsShortcutsItem, @@ -788,11 +789,11 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): """ self.themeManagerContents.updatePreviewImages() - def onDisplayTagItemClicked(self): + def onFormattingTagItemClicked(self): """ Show the Settings dialog """ - self.displayTagForm.exec_() + self.formattingTagForm.exec_() def onSettingsConfigureItemClicked(self): """ From b3896d880bd7f222cd01557d9fd2af7d7bd0b49f Mon Sep 17 00:00:00 2001 From: Andreas Preikschat Date: Sat, 30 Jul 2011 09:40:34 +0200 Subject: [PATCH 138/184] spelling --- openlp/core/ui/formattingtagform.py | 6 +++--- openlp/core/ui/mainwindow.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/openlp/core/ui/formattingtagform.py b/openlp/core/ui/formattingtagform.py index 7312ffa7b..b3fda20ba 100644 --- a/openlp/core/ui/formattingtagform.py +++ b/openlp/core/ui/formattingtagform.py @@ -25,7 +25,7 @@ # Temple Place, Suite 330, Boston, MA 02111-1307 USA # ############################################################################### """ -The :mod:`DisplayTagTab` provides an Tag Edit facility. The Base set are +The :mod:`formattingtagform` provides an Tag Edit facility. The Base set are protected and included each time loaded. Custom tags can be defined and saved. The Custom Tag arrays are saved in a pickle so QSettings works on them. Base Tags cannot be changed. @@ -78,7 +78,7 @@ class FormattingTagForm(QtGui.QDialog, Ui_FormattingTagDialog): """ # Initial Load of the Tags FormattingTags.reset_html_tags() - # Formatting Tags where also known as display tags. + # Formatting Tags were also known as display tags. user_expands = QtCore.QSettings().value(u'displayTags/html_tags', QtCore.QVariant(u'')).toString() # cPickle only accepts str not unicode strings @@ -184,7 +184,7 @@ class FormattingTagForm(QtGui.QDialog, Ui_FormattingTagDialog): for tag in FormattingTags.get_html_tags(): if not tag[u'protected']: tags.append(tag) - # Formatting Tags where also known as display tags. + # Formatting Tags were also known as display tags. QtCore.QSettings().setValue(u'displayTags/html_tags', QtCore.QVariant(cPickle.dumps(tags) if tags else u'')) diff --git a/openlp/core/ui/mainwindow.py b/openlp/core/ui/mainwindow.py index 16691e5a0..8beb21eac 100644 --- a/openlp/core/ui/mainwindow.py +++ b/openlp/core/ui/mainwindow.py @@ -269,7 +269,7 @@ class Ui_MainWindow(object): u'settingsShortcutsItem', u':/system/system_configure_shortcuts.png', category=UiStrings().Settings) - # Formatting Tags where also known as display tags. + # Formatting Tags were also known as display tags. self.formattingTagItem = icon_action(mainWindow, u'displayTagItem', u':/system/tag_editor.png', category=UiStrings().Settings) From 4f195a4721a3253f0cea101f2a26fde0d0a03797 Mon Sep 17 00:00:00 2001 From: Andreas Preikschat Date: Sat, 30 Jul 2011 09:43:19 +0200 Subject: [PATCH 139/184] changed translate context --- openlp/core/ui/formattingtagform.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/openlp/core/ui/formattingtagform.py b/openlp/core/ui/formattingtagform.py index b3fda20ba..2a8625b1a 100644 --- a/openlp/core/ui/formattingtagform.py +++ b/openlp/core/ui/formattingtagform.py @@ -121,17 +121,17 @@ class FormattingTagForm(QtGui.QDialog, Ui_FormattingTagDialog): for html in FormattingTags.get_html_tags(): if self._strip(html[u'start tag']) == u'n': critical_error_message_box( - translate('OpenLP.DisplayTagTab', 'Update Error'), - translate('OpenLP.DisplayTagTab', + translate('OpenLP.FormattingTagForm', 'Update Error'), + translate('OpenLP.FormattingTagForm', 'Tag "n" already defined.')) return # Add new tag to list tag = { - u'desc': translate('OpenLP.DisplayTagTab', 'New Tag'), + u'desc': translate('OpenLP.FormattingTagForm', 'New Tag'), u'start tag': u'{n}', - u'start html': translate('OpenLP.DisplayTagTab', ''), + u'start html': translate('OpenLP.FormattingTagForm', ''), u'end tag': u'{/n}', - u'end html': translate('OpenLP.DisplayTagTab', ''), + u'end html': translate('OpenLP.FormattingTagForm', ''), u'protected': False } FormattingTags.add_html_tags([tag]) @@ -163,8 +163,8 @@ class FormattingTagForm(QtGui.QDialog, Ui_FormattingTagDialog): if self._strip(html1[u'start tag']) == tag and \ linenumber != self.selected: critical_error_message_box( - translate('OpenLP.DisplayTagTab', 'Update Error'), - unicode(translate('OpenLP.DisplayTagTab', + translate('OpenLP.FormattingTagForm', 'Update Error'), + unicode(translate('OpenLP.FormattingTagForm', 'Tag %s already defined.')) % tag) return html[u'desc'] = unicode(self.descriptionLineEdit.text()) From 5e91aa7aee0d7bdc7006dabfa8f0273cd6385102 Mon Sep 17 00:00:00 2001 From: Andreas Preikschat Date: Sat, 30 Jul 2011 10:07:48 +0200 Subject: [PATCH 140/184] fixed long lines --- openlp/core/lib/formattingtags.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/openlp/core/lib/formattingtags.py b/openlp/core/lib/formattingtags.py index 9fd42a605..ae9d5c1cf 100644 --- a/openlp/core/lib/formattingtags.py +++ b/openlp/core/lib/formattingtags.py @@ -93,20 +93,24 @@ class FormattingTags(object): u'desc': translate('OpenLP.FormattingTags', 'Superscript'), u'start tag': u'{su}', u'start html': u'', u'end tag': u'{/su}', u'end html': u'', u'protected': True}) - base_tags.append({u'desc': translate('OpenLP.FormattingTags', 'Subscript'), + base_tags.append({ + u'desc': translate('OpenLP.FormattingTags', 'Subscript'), u'start tag': u'{sb}', u'start html': u'', u'end tag': u'{/sb}', u'end html': u'', u'protected': True}) - base_tags.append({u'desc': translate('OpenLP.FormattingTags', 'Paragraph'), + base_tags.append({ + u'desc': translate('OpenLP.FormattingTags', 'Paragraph'), u'start tag': u'{p}', u'start html': u'

', u'end tag': u'{/p}', u'end html': u'

', u'protected': True}) base_tags.append({u'desc': translate('OpenLP.FormattingTags', 'Bold'), u'start tag': u'{st}', u'start html': u'', u'end tag': u'{/st}', u'end html': u'', u'protected': True}) - base_tags.append({u'desc': translate('OpenLP.FormattingTags', 'Italics'), + base_tags.append({ + u'desc': translate('OpenLP.FormattingTags', 'Italics'), u'start tag': u'{it}', u'start html': u'', u'end tag': u'{/it}', u'end html': u'', u'protected': True}) - base_tags.append({u'desc': translate('OpenLP.FormattingTags', 'Underline'), + base_tags.append({ + u'desc': translate('OpenLP.FormattingTags', 'Underline'), u'start tag': u'{u}', u'start html': u'', u'end tag': u'{/u}', u'end html': u'', u'protected': True}) From c608a0750dad4ca1418988cd6932c8b8a752874a Mon Sep 17 00:00:00 2001 From: Stevan Pettit Date: Mon, 1 Aug 2011 21:58:10 -0400 Subject: [PATCH 141/184] Modified firsttimeform to include existing themes when wizard is re-run --- openlp/core/ui/firsttimeform.py | 36 +++++++++++++++++++++++++++++---- openlp/core/ui/mainwindow.py | 2 +- 2 files changed, 33 insertions(+), 5 deletions(-) diff --git a/openlp/core/ui/firsttimeform.py b/openlp/core/ui/firsttimeform.py index e5d434180..71c18044e 100644 --- a/openlp/core/ui/firsttimeform.py +++ b/openlp/core/ui/firsttimeform.py @@ -157,10 +157,28 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard): item = self.themesListWidget.item(iter) if item.checkState() == QtCore.Qt.Checked: self.themeComboBox.addItem(item.text()) + #Check if this is a re-run of the wizard. If so, add existing themes to list + self.has_run_wizard = QtCore.QSettings().value( + u'general/has run wizard', QtCore.QVariant(False)).toBool() + if self.has_run_wizard: + #If themes already exist, add them to the list + self.theme_list = self.parent().themeManagerContents.getThemes() + for theme in self.theme_list: + index = self.themeComboBox.findText(theme) + if index == -1: + self.themeComboBox.addItem(theme) + default_theme = unicode(QtCore.QSettings().value( + u'themes/global theme', + QtCore.QVariant(u'')).toString()) + #Pre-select the current default theme + index = self.themeComboBox.findText(default_theme) + self.themeComboBox.setCurrentIndex(index) elif pageId == FirstTimePage.Progress: + Receiver.send_message(u'cursor_busy') self._preWizard() self._performWizard() self._postWizard() + Receiver.send_message(u'cursor_normal') def updateScreenListCombo(self): """ @@ -249,11 +267,21 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard): """ if self.max_progress: self.progressBar.setValue(self.progressBar.maximum()) - self.progressLabel.setText(translate('OpenLP.FirstTimeWizard', - 'Download complete. Click the finish button to start OpenLP.')) + if self.has_run_wizard: + self.progressLabel.setText(translate('OpenLP.FirstTimeWizard', + 'Download complete.' + ' Click the finish button to return to OpenLP.')) + else: + self.progressLabel.setText(translate('OpenLP.FirstTimeWizard', + 'Download complete.' + ' Click the finish button to start OpenLP.')) else: - self.progressLabel.setText(translate('OpenLP.FirstTimeWizard', - 'Click the finish button to start OpenLP.')) + if self.has_run_wizard: + self.progressLabel.setText(translate('OpenLP.FirstTimeWizard', + 'Click the finish button to return to OpenLP.')) + else: + self.progressLabel.setText(translate('OpenLP.FirstTimeWizard', + 'Click the finish button to start OpenLP.')) self.finishButton.setVisible(True) self.finishButton.setEnabled(True) self.cancelButton.setVisible(False) diff --git a/openlp/core/ui/mainwindow.py b/openlp/core/ui/mainwindow.py index 69626cae8..7de14594a 100644 --- a/openlp/core/ui/mainwindow.py +++ b/openlp/core/ui/mainwindow.py @@ -748,7 +748,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): return Receiver.send_message(u'cursor_busy') screens = ScreenList.get_instance() - if FirstTimeForm(screens).exec_() == QtGui.QDialog.Accepted: + if FirstTimeForm(screens, self).exec_() == QtGui.QDialog.Accepted: self.firstTime() for plugin in self.pluginManager.plugins: self.activePlugin = plugin From 644706a62a6558a76e072e2dbf4f3e0d91077337 Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Tue, 2 Aug 2011 06:07:09 +0100 Subject: [PATCH 142/184] Fix review comments and cleanups --- openlp/core/lib/listwidgetwithdnd.py | 17 +++++-- openlp/core/lib/mediamanageritem.py | 50 +++++++++++-------- openlp/plugins/images/lib/mediaitem.py | 2 - openlp/plugins/media/lib/mediaitem.py | 2 - openlp/plugins/presentations/lib/mediaitem.py | 2 - 5 files changed, 42 insertions(+), 31 deletions(-) diff --git a/openlp/core/lib/listwidgetwithdnd.py b/openlp/core/lib/listwidgetwithdnd.py index 69bd67fdd..8474821a4 100644 --- a/openlp/core/lib/listwidgetwithdnd.py +++ b/openlp/core/lib/listwidgetwithdnd.py @@ -51,6 +51,9 @@ class ListWidgetWithDnD(QtGui.QListWidget): """ self.setAcceptDrops(True) self.setDragDropMode(QtGui.QAbstractItemView.DragDrop) + QtCore.QObject.connect(Receiver.get_receiver(), + QtCore.SIGNAL(u'%s_dnd' % self.mimeDataText), + self.parent().loadFile) def mouseMoveEvent(self, event): """ @@ -71,7 +74,7 @@ class ListWidgetWithDnD(QtGui.QListWidget): drag.start(QtCore.Qt.CopyAction) def dragEnterEvent(self, event): - if event.mimeData().hasUrls: + if event.mimeData().hasUrls(): event.accept() else: event.ignore() @@ -93,9 +96,15 @@ class ListWidgetWithDnD(QtGui.QListWidget): if event.mimeData().hasUrls(): event.setDropAction(QtCore.Qt.CopyAction) event.accept() + files = [] for url in event.mimeData().urls(): - if os.path.isfile(url.toLocalFile()): - Receiver.send_message(u'%s_dnd' % self.mimeDataText, - url.toLocalFile()) + localFile = unicode(url.toLocalFile()) + if os.path.isfile(localFile): + files.append(localFile) + elif os.path.isdir(localFile): + listing = os.listdir(localFile) + for file in listing: + files.append(os.path.join(localFile,file)) + Receiver.send_message(u'%s_dnd' % self.mimeDataText,files) else: event.ignore() diff --git a/openlp/core/lib/mediamanageritem.py b/openlp/core/lib/mediamanageritem.py index 2b2e8c6e3..7852a0d5c 100644 --- a/openlp/core/lib/mediamanageritem.py +++ b/openlp/core/lib/mediamanageritem.py @@ -341,25 +341,31 @@ class MediaManagerItem(QtGui.QWidget): self.validateAndLoad(files) Receiver.send_message(u'cursor_normal') - def loadFile(self, filename): + def loadFile(self, files): """ - Turn file from Drag and Drop into a array so the Validate code - can runn it. + Turn file from Drag and Drop into an array so the Validate code + can run it. - ``filename`` - The file to be loaded + ``files`` + The list of files to be loaded """ - filename = unicode(filename) - type = filename.split(u'.')[-1] - if type.lower() not in self.onNewFileMasks: - critical_error_message_box( - translate('OpenLP.MediaManagerItem', - 'Invalid File Type'), - unicode(translate('OpenLP.MediaManagerItem', - 'Invalid File %s.\nSuffix not supported')) - % filename) - else: - self.validateAndLoad([filename]) + newFiles = [] + errorShown = False + for file in files: + type = file.split(u'.')[-1] + if type.lower() not in self.onNewFileMasks: + if not errorShown: + critical_error_message_box( + translate('OpenLP.MediaManagerItem', + 'Invalid File Type'), + unicode(translate('OpenLP.MediaManagerItem', + 'Invalid File %s.\nSuffix not supported')) + % file) + errorShown = True + else: + newFiles.append(file) + if file: + self.validateAndLoad(newFiles) def validateAndLoad(self, files): """ @@ -373,14 +379,11 @@ class MediaManagerItem(QtGui.QWidget): for count in range(0, self.listView.count()): names.append(self.listView.item(count).text()) newFiles = [] + duplicatesFound = False for file in files: filename = os.path.split(unicode(file))[1] if filename in names: - critical_error_message_box( - UiStrings().Duplicate, - unicode(translate('OpenLP.MediaManagerItem', - 'Duplicate filename %s.\nThis filename is already in ' - 'the list')) % filename) + duplicatesFound = True else: newFiles.append(file) self.loadList(newFiles) @@ -388,6 +391,11 @@ class MediaManagerItem(QtGui.QWidget): SettingsManager.set_last_dir(self.settingsSection, lastDir) SettingsManager.set_list(self.settingsSection, self.settingsSection, self.getFileList()) + if duplicatesFound: + critical_error_message_box( + UiStrings().Duplicate, + unicode(translate('OpenLP.MediaManagerItem', + 'Duplicate files found on import and ignored.'))) def contextMenu(self, point): item = self.listView.itemAt(point) diff --git a/openlp/plugins/images/lib/mediaitem.py b/openlp/plugins/images/lib/mediaitem.py index 09811ead7..acd420880 100644 --- a/openlp/plugins/images/lib/mediaitem.py +++ b/openlp/plugins/images/lib/mediaitem.py @@ -54,8 +54,6 @@ class ImageMediaItem(MediaManagerItem): QtCore.SIGNAL(u'live_theme_changed'), self.liveThemeChanged) # Allow DnD from the desktop self.listView.activateDnD() - QtCore.QObject.connect(Receiver.get_receiver(), - QtCore.SIGNAL(u'images_dnd'), self.loadFile) def retranslateUi(self): self.onNewPrompt = translate('ImagePlugin.MediaItem', diff --git a/openlp/plugins/media/lib/mediaitem.py b/openlp/plugins/media/lib/mediaitem.py index 54682dbf6..e3c36bd77 100644 --- a/openlp/plugins/media/lib/mediaitem.py +++ b/openlp/plugins/media/lib/mediaitem.py @@ -63,8 +63,6 @@ class MediaMediaItem(MediaManagerItem): self.createPhonon) # Allow DnD from the desktop self.listView.activateDnD() - QtCore.QObject.connect(Receiver.get_receiver(), - QtCore.SIGNAL(u'media_dnd'), self.loadFile) def retranslateUi(self): self.onNewPrompt = translate('MediaPlugin.MediaItem', 'Select Media') diff --git a/openlp/plugins/presentations/lib/mediaitem.py b/openlp/plugins/presentations/lib/mediaitem.py index abd597c6c..85721c65d 100644 --- a/openlp/plugins/presentations/lib/mediaitem.py +++ b/openlp/plugins/presentations/lib/mediaitem.py @@ -60,8 +60,6 @@ class PresentationMediaItem(MediaManagerItem): QtCore.SIGNAL(u'mediaitem_presentation_rebuild'), self.rebuild) # Allow DnD from the desktop self.listView.activateDnD() - QtCore.QObject.connect(Receiver.get_receiver(), - QtCore.SIGNAL(u'presentations_dnd'), self.loadFile) def retranslateUi(self): """ From af8a89dfd4f1e2f87b1cea18c4514912211bec3e Mon Sep 17 00:00:00 2001 From: Stevan Pettit Date: Tue, 2 Aug 2011 08:51:41 -0400 Subject: [PATCH 143/184] fixed come comments --- openlp/core/ui/firsttimeform.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/openlp/core/ui/firsttimeform.py b/openlp/core/ui/firsttimeform.py index 71c18044e..f5a2563e5 100644 --- a/openlp/core/ui/firsttimeform.py +++ b/openlp/core/ui/firsttimeform.py @@ -157,11 +157,11 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard): item = self.themesListWidget.item(iter) if item.checkState() == QtCore.Qt.Checked: self.themeComboBox.addItem(item.text()) - #Check if this is a re-run of the wizard. If so, add existing themes to list + # Check if this is a re-run of the wizard. If so, add existing themes to list self.has_run_wizard = QtCore.QSettings().value( u'general/has run wizard', QtCore.QVariant(False)).toBool() if self.has_run_wizard: - #If themes already exist, add them to the list + # If themes already exist, add them to the list self.theme_list = self.parent().themeManagerContents.getThemes() for theme in self.theme_list: index = self.themeComboBox.findText(theme) @@ -170,7 +170,7 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard): default_theme = unicode(QtCore.QSettings().value( u'themes/global theme', QtCore.QVariant(u'')).toString()) - #Pre-select the current default theme + # Pre-select the current default theme index = self.themeComboBox.findText(default_theme) self.themeComboBox.setCurrentIndex(index) elif pageId == FirstTimePage.Progress: From 0b4616542934b24a8a8860aebeee688716e8964f Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Tue, 2 Aug 2011 19:17:07 +0100 Subject: [PATCH 144/184] Last set of fixes --- openlp/core/lib/mediamanageritem.py | 11 ++++---- openlp/core/ui/servicemanager.py | 31 +++++++++++++++------ openlp/plugins/songusage/songusageplugin.py | 2 +- 3 files changed, 29 insertions(+), 15 deletions(-) diff --git a/openlp/core/lib/mediamanageritem.py b/openlp/core/lib/mediamanageritem.py index 7852a0d5c..a721fabf6 100644 --- a/openlp/core/lib/mediamanageritem.py +++ b/openlp/core/lib/mediamanageritem.py @@ -386,11 +386,12 @@ class MediaManagerItem(QtGui.QWidget): duplicatesFound = True else: newFiles.append(file) - self.loadList(newFiles) - lastDir = os.path.split(unicode(files[0]))[0] - SettingsManager.set_last_dir(self.settingsSection, lastDir) - SettingsManager.set_list(self.settingsSection, - self.settingsSection, self.getFileList()) + if newFiles: + self.loadList(newFiles) + lastDir = os.path.split(unicode(files[0]))[0] + SettingsManager.set_last_dir(self.settingsSection, lastDir) + SettingsManager.set_list(self.settingsSection, + self.settingsSection, self.getFileList()) if duplicatesFound: critical_error_message_box( UiStrings().Duplicate, diff --git a/openlp/core/ui/servicemanager.py b/openlp/core/ui/servicemanager.py index 6d86097f2..0755a0143 100644 --- a/openlp/core/ui/servicemanager.py +++ b/openlp/core/ui/servicemanager.py @@ -408,20 +408,33 @@ class ServiceManager(QtGui.QWidget): return False self.newFile() - def onLoadServiceClicked(self): + def onLoadServiceClicked(self, loadFile=None): + """ + Loads the service file and saves the existing one it there is one + unchanged + + ``loadFile`` + The service file to the loaded. Will be None is from menu so + selection will be required. + """ if self.isModified(): result = self.saveModifiedService() if result == QtGui.QMessageBox.Cancel: return False elif result == QtGui.QMessageBox.Save: self.saveFile() - fileName = unicode(QtGui.QFileDialog.getOpenFileName(self.mainwindow, - translate('OpenLP.ServiceManager', 'Open File'), - SettingsManager.get_last_dir( - self.mainwindow.serviceSettingsSection), - translate('OpenLP.ServiceManager', 'OpenLP Service Files (*.osz)'))) - if not fileName: - return False + if not loadFile: + fileName = unicode(QtGui.QFileDialog.getOpenFileName( + self.mainwindow, + translate('OpenLP.ServiceManager', 'Open File'), + SettingsManager.get_last_dir( + self.mainwindow.serviceSettingsSection), + translate('OpenLP.ServiceManager', + 'OpenLP Service Files (*.osz)'))) + if not fileName: + return False + else: + fileName = loadFile SettingsManager.set_last_dir(self.mainwindow.serviceSettingsSection, split_filename(fileName)[0]) self.loadFile(fileName) @@ -1245,7 +1258,7 @@ class ServiceManager(QtGui.QWidget): for url in event.mimeData().urls(): filename = unicode(url.toLocalFile()) if filename.endswith(u'.osz'): - self.loadFile(filename) + self.onLoadServiceClicked(filename) elif event.mimeData().hasText(): plugin = unicode(event.mimeData().text()) item = self.serviceManagerList.itemAt(event.pos()) diff --git a/openlp/plugins/songusage/songusageplugin.py b/openlp/plugins/songusage/songusageplugin.py index a657d700d..4ca23aeb0 100644 --- a/openlp/plugins/songusage/songusageplugin.py +++ b/openlp/plugins/songusage/songusageplugin.py @@ -91,8 +91,8 @@ class SongUsagePlugin(Plugin): self.toolsMenu.addAction(self.songUsageMenu.menuAction()) self.songUsageMenu.addAction(self.songUsageStatus) self.songUsageMenu.addSeparator() - self.songUsageMenu.addAction(self.songUsageDelete) self.songUsageMenu.addAction(self.songUsageReport) + self.songUsageMenu.addAction(self.songUsageDelete) self.songUsageActiveButton = QtGui.QToolButton( self.formparent.statusBar) self.songUsageActiveButton.setCheckable(True) From af7ff7c6be8e222d23b7b51abbcc272c85eb01a7 Mon Sep 17 00:00:00 2001 From: Stevan Pettit Date: Wed, 3 Aug 2011 09:19:43 -0400 Subject: [PATCH 145/184] changed some comments, removed a variable using functioin inline --- openlp/core/ui/firsttimeform.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/openlp/core/ui/firsttimeform.py b/openlp/core/ui/firsttimeform.py index f5a2563e5..4beebfde6 100644 --- a/openlp/core/ui/firsttimeform.py +++ b/openlp/core/ui/firsttimeform.py @@ -157,20 +157,19 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard): item = self.themesListWidget.item(iter) if item.checkState() == QtCore.Qt.Checked: self.themeComboBox.addItem(item.text()) - # Check if this is a re-run of the wizard. If so, add existing themes to list + # Check if this is a re-run of the wizard. self.has_run_wizard = QtCore.QSettings().value( u'general/has run wizard', QtCore.QVariant(False)).toBool() if self.has_run_wizard: - # If themes already exist, add them to the list - self.theme_list = self.parent().themeManagerContents.getThemes() - for theme in self.theme_list: + # Add any existing themes to list. + for theme in self.parent().themeManagerContents.getThemes(): index = self.themeComboBox.findText(theme) if index == -1: self.themeComboBox.addItem(theme) default_theme = unicode(QtCore.QSettings().value( u'themes/global theme', QtCore.QVariant(u'')).toString()) - # Pre-select the current default theme + # Pre-select the current default theme. index = self.themeComboBox.findText(default_theme) self.themeComboBox.setCurrentIndex(index) elif pageId == FirstTimePage.Progress: From 5ff39a7d83cd9c67295dd435bf234a72f77ef340 Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Wed, 3 Aug 2011 16:52:29 +0100 Subject: [PATCH 146/184] Fix missing() --- openlp/core/lib/listwidgetwithdnd.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openlp/core/lib/listwidgetwithdnd.py b/openlp/core/lib/listwidgetwithdnd.py index 8474821a4..69fb23092 100644 --- a/openlp/core/lib/listwidgetwithdnd.py +++ b/openlp/core/lib/listwidgetwithdnd.py @@ -80,7 +80,7 @@ class ListWidgetWithDnD(QtGui.QListWidget): event.ignore() def dragMoveEvent(self, event): - if event.mimeData().hasUrls: + if event.mimeData().hasUrls(): event.setDropAction(QtCore.Qt.CopyAction) event.accept() else: From 7f440527f84ad96320521691ea31378f536b4dfd Mon Sep 17 00:00:00 2001 From: Stevan Pettit Date: Wed, 3 Aug 2011 14:49:47 -0400 Subject: [PATCH 147/184] modified servicemanager to check for missing files during service save --- openlp/core/ui/servicemanager.py | 61 ++++++++++++++++++++++---------- 1 file changed, 42 insertions(+), 19 deletions(-) diff --git a/openlp/core/ui/servicemanager.py b/openlp/core/ui/servicemanager.py index 351e5bbc6..721d50d6e 100644 --- a/openlp/core/ui/servicemanager.py +++ b/openlp/core/ui/servicemanager.py @@ -465,10 +465,13 @@ class ServiceManager(QtGui.QWidget): service = [] write_list = [] total_size = 0 + abort_save = False Receiver.send_message(u'cursor_busy') # Number of items + 1 to zip it self.mainwindow.displayProgressBar(len(self.serviceItems) + 1) for item in self.serviceItems: + if abort_save: + continue self.mainwindow.incrementProgressBar() service.append({u'serviceitem': item[u'service_item'].get_service_repr()}) @@ -482,25 +485,45 @@ class ServiceManager(QtGui.QWidget): # Only write a file once if path_from in write_list: continue - file_size = os.path.getsize(path_from) - size_limit = 52428800 # 50MiB - #if file_size > size_limit: - # # File exeeds size_limit bytes, ask user - # message = unicode(translate('OpenLP.ServiceManager', - # 'Do you want to include \n%.1f MB file "%s"\n' - # 'into the service file?\nThis may take some time.\n\n' - # 'Please note that you need to\ntake care of that file' - # ' yourself,\nif you leave it out.')) % \ - # (file_size/1048576, os.path.split(path_from)[1]) - # ans = QtGui.QMessageBox.question(self.mainwindow, - # translate('OpenLP.ServiceManager', 'Including Large ' - # 'File'), message, QtGui.QMessageBox.StandardButtons( - # QtGui.QMessageBox.Ok|QtGui.QMessageBox.Cancel), - # QtGui.QMessageBox.Ok) - # if ans == QtGui.QMessageBox.Cancel: - # continue - write_list.append(path_from) - total_size += file_size + if not os.path.isfile(path_from): + Receiver.send_message(u'cursor_normal') + title = unicode(translate('OpenLP.ServiceManager', + 'Service File Missing')) + message = unicode(translate('OpenLP.ServiceManager', + 'File missing from service\n\n %s \n\n' + 'Continue saving?' % path_from )) + ans = QtGui.QMessageBox.critical(self, title, message, + QtGui.QMessageBox.StandardButtons( + QtGui.QMessageBox.Yes | QtGui.QMessageBox.No)) + if ans == QtGui.QMessageBox.No: + abort_save = True + continue + Receiver.send_message(u'cursor_busy') + else: + file_size = os.path.getsize(path_from) + size_limit = 52428800 # 50MiB + #if file_size > size_limit: + # # File exeeds size_limit bytes, ask user + # message = unicode(translate('OpenLP.ServiceManager', + # 'Do you want to include \n%.1f MB file "%s"\n' + # 'into the service file?\nThis may take some time.\n\n' + # 'Please note that you need to\ntake care of that file' + # ' yourself,\nif you leave it out.')) % \ + # (file_size/1048576, os.path.split(path_from)[1]) + # ans = QtGui.QMessageBox.question(self.mainwindow, + # translate('OpenLP.ServiceManager', 'Including Large ' + # 'File'), message, QtGui.QMessageBox.StandardButtons( + # QtGui.QMessageBox.Ok|QtGui.QMessageBox.Cancel), + # QtGui.QMessageBox.Ok) + # if ans == QtGui.QMessageBox.Cancel: + # continue + write_list.append(path_from) + total_size += file_size + if abort_save: + self._fileName = u'' + self.mainwindow.finishedProgressBar() + Receiver.send_message(u'cursor_normal') + return False log.debug(u'ServiceManager.saveFile - ZIP contents size is %i bytes' % total_size) service_content = cPickle.dumps(service) From b4e776b92c7d96acc69fe0815fe6f0afdde4dc02 Mon Sep 17 00:00:00 2001 From: Stevan Pettit Date: Thu, 4 Aug 2011 09:43:05 -0400 Subject: [PATCH 148/184] removed un-needed code --- openlp/core/ui/servicemanager.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/openlp/core/ui/servicemanager.py b/openlp/core/ui/servicemanager.py index 721d50d6e..8b5d93c5e 100644 --- a/openlp/core/ui/servicemanager.py +++ b/openlp/core/ui/servicemanager.py @@ -485,7 +485,7 @@ class ServiceManager(QtGui.QWidget): # Only write a file once if path_from in write_list: continue - if not os.path.isfile(path_from): + if not os.path.exists(path_from): Receiver.send_message(u'cursor_normal') title = unicode(translate('OpenLP.ServiceManager', 'Service File Missing')) @@ -520,7 +520,6 @@ class ServiceManager(QtGui.QWidget): write_list.append(path_from) total_size += file_size if abort_save: - self._fileName = u'' self.mainwindow.finishedProgressBar() Receiver.send_message(u'cursor_normal') return False From 8876a12deb08f86cce1447957b892115b39ed645 Mon Sep 17 00:00:00 2001 From: Andreas Preikschat Date: Fri, 5 Aug 2011 09:41:20 +0200 Subject: [PATCH 149/184] updated docstring --- openlp/core/lib/renderer.py | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/openlp/core/lib/renderer.py b/openlp/core/lib/renderer.py index ce7f84778..b41e89c26 100644 --- a/openlp/core/lib/renderer.py +++ b/openlp/core/lib/renderer.py @@ -243,19 +243,17 @@ class Renderer(object): new_pages.append(page) return new_pages - def _calculate_default(self, screen): + def _calculate_default(self, size): """ Calculate the default dimentions of the screen. - ``screen`` - The screen to calculate the default of. + ``size`` + The screen's size to calculate the default of (``QtCore.QRect``). """ - log.debug(u'_calculate default %s', screen) - self.width = screen.width() - self.height = screen.height() + self.width = size.width() + self.height = size.height() self.screen_ratio = float(self.height) / float(self.width) - log.debug(u'calculate default %d, %d, %f', - self.width, self.height, self.screen_ratio) + log.debug(u'_calculate default %s, %f' % (size, self.screen_ratio)) # 90% is start of footer self.footer_start = int(self.height * 0.90) @@ -316,8 +314,8 @@ class Renderer(object): // work as expected. return document.all.main.offsetHeight; } - +
""" % \ (build_lyrics_format_css(self.theme_data, self.page_width, self.page_height), build_lyrics_outline_css(self.theme_data)) From f4eb21eb05bdd29dfad053731f243ae40a4669ee Mon Sep 17 00:00:00 2001 From: Andreas Preikschat Date: Fri, 5 Aug 2011 10:10:53 +0200 Subject: [PATCH 150/184] more docstrings, clean ups --- openlp/core/lib/renderer.py | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/openlp/core/lib/renderer.py b/openlp/core/lib/renderer.py index b41e89c26..911891693 100644 --- a/openlp/core/lib/renderer.py +++ b/openlp/core/lib/renderer.py @@ -222,7 +222,7 @@ class Renderer(object): line_end = u' ' # Bibles if item.is_capable(ItemCapabilities.AllowsWordSplit): - pages = self._paginate_slide_words(text, line_end) + pages = self._paginate_slide_words(text.split(u'\n'), line_end) else: # Clean up line endings. lines = self._lines_split(text) @@ -310,9 +310,10 @@ class Renderer(object): function show_text(newtext) { var main = document.getElementById('main'); main.innerHTML = newtext; - // We have to return something, otherwise the renderer does not - // work as expected. - return document.all.main.offsetHeight; + // We need to be sure that the page is loaded, that is why we + // return the element's height (even though we do not use the + // returned value). + return main.offsetHeight; } @@ -325,6 +326,8 @@ class Renderer(object): """ Figure out how much text can appear on a slide, using the current theme settings. + **Note:** The smallest possible "unit" of text for a slide is one line. + If the line is too long it will be cut off when displayed. ``lines`` The text to be fitted on the slide split into lines. @@ -349,24 +352,25 @@ class Renderer(object): log.debug(u'_paginate_slide - End') return formatted - def _paginate_slide_words(self, text, line_end): + def _paginate_slide_words(self, lines, line_end): """ Figure out how much text can appear on a slide, using the current - theme settings. This version is to handle text which needs to be split - into words to get it to fit. + theme settings. + **Note:** The smallest possible "unit" of text for a slide is one word. + If one line is too long it will be processed word by word. This is + sometimes need for **bible** verses. - ``text`` - The words to be fitted on the slide split into lines. + ``lines`` + The text to be fitted on the slide split into lines. ``line_end`` The text added after each line. Either ``u' '`` or ``u'
``. - This is needed for bibles. + This is needed for **bibles**. """ log.debug(u'_paginate_slide_words - Start') formatted = [] previous_html = u'' previous_raw = u'' - lines = text.split(u'\n') for line in lines: line = line.strip() html_line = expand_tags(line) @@ -481,7 +485,7 @@ class Renderer(object): def _text_fits_on_slide(self, text): """ - Checks if the given ``text`` fits on a slide. If it does, ``True`` is + Checks if the given ``text`` fits on a slide. If it does ``True`` is returned, otherwise ``False``. ``text`` From d8008df9029f610f3be1f8b6c648f208ab45150c Mon Sep 17 00:00:00 2001 From: Andreas Preikschat Date: Fri, 5 Aug 2011 10:43:32 +0200 Subject: [PATCH 151/184] do not pass instance variable as argument --- openlp/core/lib/renderer.py | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/openlp/core/lib/renderer.py b/openlp/core/lib/renderer.py index 911891693..3174e4df8 100644 --- a/openlp/core/lib/renderer.py +++ b/openlp/core/lib/renderer.py @@ -83,7 +83,7 @@ class Renderer(object): Updates the render manager's information about the current screen. """ log.debug(u'Update Display') - self._calculate_default(self.screens.current[u'size']) + self._calculate_default() if self.display: self.display.close() self.display = MainDisplay(None, self.imageManager, False) @@ -161,7 +161,7 @@ class Renderer(object): self.theme_data = override_theme else: self.theme_data = self.themeManager.getThemeData(theme) - self._calculate_default(self.screens.current[u'size']) + self._calculate_default() self._build_text_rectangle(self.theme_data) # if No file do not update cache if self.theme_data.background_filename: @@ -183,7 +183,7 @@ class Renderer(object): # save value for use in format_slide self.force_page = force_page # set the default image size for previews - self._calculate_default(self.screens.preview[u'size']) + self._calculate_default() # build a service item to generate preview serviceItem = ServiceItem() serviceItem.theme = theme_data @@ -201,7 +201,7 @@ class Renderer(object): raw_html = serviceItem.get_rendered_frame(0) preview = self.display.text(raw_html) # Reset the real screen size for subsequent render requests - self._calculate_default(self.screens.current[u'size']) + self._calculate_default() return preview self.force_page = False @@ -243,13 +243,11 @@ class Renderer(object): new_pages.append(page) return new_pages - def _calculate_default(self, size): + def _calculate_default(self): """ Calculate the default dimentions of the screen. - - ``size`` - The screen's size to calculate the default of (``QtCore.QRect``). """ + size = self.screens.current[u'size'] self.width = size.width() self.height = size.height() self.screen_ratio = float(self.height) / float(self.width) From 6ce4e7beab8b5fd4ca13db5d4109d88e0d1aaf51 Mon Sep 17 00:00:00 2001 From: Andreas Preikschat Date: Fri, 5 Aug 2011 10:47:31 +0200 Subject: [PATCH 152/184] changed varialbe name --- openlp/core/lib/renderer.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/openlp/core/lib/renderer.py b/openlp/core/lib/renderer.py index 3174e4df8..ac7e95c4c 100644 --- a/openlp/core/lib/renderer.py +++ b/openlp/core/lib/renderer.py @@ -247,11 +247,12 @@ class Renderer(object): """ Calculate the default dimentions of the screen. """ - size = self.screens.current[u'size'] - self.width = size.width() - self.height = size.height() + screen_size = self.screens.current[u'size'] + self.width = screen_size.width() + self.height = screen_size.height() self.screen_ratio = float(self.height) / float(self.width) - log.debug(u'_calculate default %s, %f' % (size, self.screen_ratio)) + log.debug(u'_calculate default %s, %f' % (screen_size, + self.screen_ratio)) # 90% is start of footer self.footer_start = int(self.height * 0.90) From 6c7c27a7c9720539655c32c90cc36c2413f55b85 Mon Sep 17 00:00:00 2001 From: Andreas Preikschat Date: Fri, 5 Aug 2011 13:21:39 +0200 Subject: [PATCH 153/184] fixed bug #816186; fixed comments; fixed list comprehension Fixes: https://launchpad.net/bugs/816186 --- openlp/plugins/songs/forms/songimportform.py | 3 +- openlp/plugins/songs/lib/olp1import.py | 37 +++++++++++++------- 2 files changed, 27 insertions(+), 13 deletions(-) diff --git a/openlp/plugins/songs/forms/songimportform.py b/openlp/plugins/songs/forms/songimportform.py index 4ab60d360..52524b838 100644 --- a/openlp/plugins/songs/forms/songimportform.py +++ b/openlp/plugins/songs/forms/songimportform.py @@ -699,7 +699,8 @@ class SongImportForm(OpenLPWizard): elif source_format == SongFormat.OpenLP1: # Import an openlp.org database importer = self.plugin.importSongs(SongFormat.OpenLP1, - filename=unicode(self.openLP1FilenameEdit.text()) + filename=unicode(self.openLP1FilenameEdit.text()), + plugin=self.plugin ) elif source_format == SongFormat.OpenLyrics: # Import OpenLyrics songs diff --git a/openlp/plugins/songs/lib/olp1import.py b/openlp/plugins/songs/lib/olp1import.py index 423f5ece0..de7264a5b 100644 --- a/openlp/plugins/songs/lib/olp1import.py +++ b/openlp/plugins/songs/lib/olp1import.py @@ -57,6 +57,8 @@ class OpenLP1SongImport(SongImport): The database providing the data to import. """ SongImport.__init__(self, manager, **kwargs) + self.available_themes = \ + kwargs[u'plugin'].formparent.themeManagerContents.getThemes() def do_import(self): """ @@ -70,27 +72,34 @@ class OpenLP1SongImport(SongImport): encoding = self.get_encoding() if not encoding: return - # Connect to the database + # Connect to the database. connection = sqlite.connect(self.import_source, mode=0444, encoding=(encoding, 'replace')) cursor = connection.cursor() - # Determine if we're using a new or an old DB + # Determine if we're using a new or an old DB. cursor.execute(u'SELECT name FROM sqlite_master ' u'WHERE type = \'table\' AND name = \'tracks\'') new_db = len(cursor.fetchall()) > 0 - # "cache" our list of authors + # "cache" our list of authors. cursor.execute(u'-- types int, unicode') cursor.execute(u'SELECT authorid, authorname FROM authors') authors = cursor.fetchall() if new_db: - # "cache" our list of tracks + # "cache" our list of tracks. cursor.execute(u'-- types int, unicode') cursor.execute(u'SELECT trackid, fulltrackname FROM tracks') tracks = cursor.fetchall() - # Import the songs - cursor.execute(u'-- types int, unicode, unicode, unicode') + # "cache" our list of themes. + cursor.execute(u'-- types int, unicode') + cursor.execute(u'SELECT settingsid, settingsname FROM settings') + themes = {} + for theme_id, theme_name in cursor.fetchall(): + if theme_name in self.available_themes: + themes[theme_id] = theme_name + # Import the songs. + cursor.execute(u'-- types int, unicode, unicode, unicode, int') cursor.execute(u'SELECT songid, songtitle, lyrics || \'\' AS lyrics, ' - u'copyrightinfo FROM songs') + u'copyrightinfo, settingsid FROM songs') songs = cursor.fetchall() self.import_wizard.progressBar.setMaximum(len(songs)) for song in songs: @@ -101,8 +110,12 @@ class OpenLP1SongImport(SongImport): self.title = song[1] lyrics = song[2].replace(u'\r\n', u'\n') self.add_copyright(song[3]) + if themes.has_key(song[4]): + self.theme_name = themes[song[4]] verses = lyrics.split(u'\n\n') - [self.add_verse(verse.strip()) for verse in verses if verse.strip()] + for verse in verses: + if verse.strip(): + self.add_verse(verse.strip()) cursor.execute(u'-- types int') cursor.execute(u'SELECT authorid FROM songauthors ' u'WHERE songid = %s' % song_id) @@ -137,12 +150,12 @@ class OpenLP1SongImport(SongImport): """ Detect character encoding of an openlp.org 1.x song database. """ - # Connect to the database + # Connect to the database. connection = sqlite.connect(self.import_source, mode=0444) cursor = connection.cursor() detector = UniversalDetector() - # detect charset by authors + # Detect charset by authors. cursor.execute(u'SELECT authorname FROM authors') authors = cursor.fetchall() for author in authors: @@ -150,7 +163,7 @@ class OpenLP1SongImport(SongImport): if detector.done: detector.close() return detector.result[u'encoding'] - # detect charset by songs + # Detect charset by songs. cursor.execute(u'SELECT songtitle, copyrightinfo, ' u'lyrics || \'\' AS lyrics FROM songs') songs = cursor.fetchall() @@ -160,7 +173,7 @@ class OpenLP1SongImport(SongImport): if detector.done: detector.close() return detector.result[u'encoding'] - # detect charset by songs + # Detect charset by songs. cursor.execute(u'SELECT name FROM sqlite_master ' u'WHERE type = \'table\' AND name = \'tracks\'') if len(cursor.fetchall()) > 0: From a66f7f3365a1fa59f07441469ff8e258b4485242 Mon Sep 17 00:00:00 2001 From: Stevan Pettit Date: Fri, 5 Aug 2011 17:53:56 -0400 Subject: [PATCH 154/184] removed un-needed commented code. fixed dialog "no" answer --- openlp/core/ui/servicemanager.py | 31 ++++--------------------------- 1 file changed, 4 insertions(+), 27 deletions(-) diff --git a/openlp/core/ui/servicemanager.py b/openlp/core/ui/servicemanager.py index 8b5d93c5e..6d4ae6ec0 100644 --- a/openlp/core/ui/servicemanager.py +++ b/openlp/core/ui/servicemanager.py @@ -465,13 +465,10 @@ class ServiceManager(QtGui.QWidget): service = [] write_list = [] total_size = 0 - abort_save = False Receiver.send_message(u'cursor_busy') # Number of items + 1 to zip it self.mainwindow.displayProgressBar(len(self.serviceItems) + 1) for item in self.serviceItems: - if abort_save: - continue self.mainwindow.incrementProgressBar() service.append({u'serviceitem': item[u'service_item'].get_service_repr()}) @@ -492,37 +489,17 @@ class ServiceManager(QtGui.QWidget): message = unicode(translate('OpenLP.ServiceManager', 'File missing from service\n\n %s \n\n' 'Continue saving?' % path_from )) - ans = QtGui.QMessageBox.critical(self, title, message, + answer = QtGui.QMessageBox.critical(self, title, message, QtGui.QMessageBox.StandardButtons( QtGui.QMessageBox.Yes | QtGui.QMessageBox.No)) - if ans == QtGui.QMessageBox.No: - abort_save = True - continue + if answer == QtGui.QMessageBox.No: + self.mainwindow.finishedProgressBar() + return False Receiver.send_message(u'cursor_busy') else: file_size = os.path.getsize(path_from) - size_limit = 52428800 # 50MiB - #if file_size > size_limit: - # # File exeeds size_limit bytes, ask user - # message = unicode(translate('OpenLP.ServiceManager', - # 'Do you want to include \n%.1f MB file "%s"\n' - # 'into the service file?\nThis may take some time.\n\n' - # 'Please note that you need to\ntake care of that file' - # ' yourself,\nif you leave it out.')) % \ - # (file_size/1048576, os.path.split(path_from)[1]) - # ans = QtGui.QMessageBox.question(self.mainwindow, - # translate('OpenLP.ServiceManager', 'Including Large ' - # 'File'), message, QtGui.QMessageBox.StandardButtons( - # QtGui.QMessageBox.Ok|QtGui.QMessageBox.Cancel), - # QtGui.QMessageBox.Ok) - # if ans == QtGui.QMessageBox.Cancel: - # continue write_list.append(path_from) total_size += file_size - if abort_save: - self.mainwindow.finishedProgressBar() - Receiver.send_message(u'cursor_normal') - return False log.debug(u'ServiceManager.saveFile - ZIP contents size is %i bytes' % total_size) service_content = cPickle.dumps(service) From 271e5341f88989c55eb27abf5a881ed2fe278ac0 Mon Sep 17 00:00:00 2001 From: Stevan Pettit Date: Fri, 5 Aug 2011 18:09:51 -0400 Subject: [PATCH 155/184] modified code to delete/move item selected, not first match in list --- openlp/core/ui/serviceitemeditform.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openlp/core/ui/serviceitemeditform.py b/openlp/core/ui/serviceitemeditform.py index f19638e43..974133c3d 100644 --- a/openlp/core/ui/serviceitemeditform.py +++ b/openlp/core/ui/serviceitemeditform.py @@ -79,7 +79,7 @@ class ServiceItemEditForm(QtGui.QDialog, Ui_ServiceItemEditDialog): if not item: return row = self.listWidget.row(item) - self.itemList.remove(self.itemList[row]) + self.itemList.pop(row) self.loadData() if row == self.listWidget.count(): self.listWidget.setCurrentRow(row - 1) @@ -109,7 +109,7 @@ class ServiceItemEditForm(QtGui.QDialog, Ui_ServiceItemEditDialog): return row = self.listWidget.row(item) temp = self.itemList[row] - self.itemList.remove(self.itemList[row]) + self.itemList.pop(row) if direction == u'up': row -= 1 else: From c27d50bddafaecca41133a59bdaf5953f99cde92 Mon Sep 17 00:00:00 2001 From: Andreas Preikschat Date: Mon, 8 Aug 2011 08:30:25 +0200 Subject: [PATCH 156/184] fixed link to 'Contributing' site --- openlp/core/ui/aboutform.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/openlp/core/ui/aboutform.py b/openlp/core/ui/aboutform.py index 2909503f6..4e031656c 100644 --- a/openlp/core/ui/aboutform.py +++ b/openlp/core/ui/aboutform.py @@ -61,6 +61,5 @@ class AboutForm(QtGui.QDialog, Ui_AboutDialog): Launch a web browser and go to the contribute page on the site. """ import webbrowser - url = u'http://www.openlp.org/en/documentation/introduction/' \ - + u'contributing.html' + url = u'http://openlp.org/en/documentation/introduction/contributing' webbrowser.open_new(url) From 2c6d14cfc8fbd68a2b942d255c5d283584e7aeaf Mon Sep 17 00:00:00 2001 From: Chris Blake Date: Mon, 8 Aug 2011 12:59:56 -0400 Subject: [PATCH 157/184] fixed bug #817674 'Export Song - Song list appears to be random order ' Fixes: https://launchpad.net/bugs/817674 --- openlp/plugins/songs/forms/songexportform.py | 1 + 1 file changed, 1 insertion(+) diff --git a/openlp/plugins/songs/forms/songexportform.py b/openlp/plugins/songs/forms/songexportform.py index 3432c8846..1e86c74a1 100644 --- a/openlp/plugins/songs/forms/songexportform.py +++ b/openlp/plugins/songs/forms/songexportform.py @@ -249,6 +249,7 @@ class SongExportForm(OpenLPWizard): # Load the list of songs. Receiver.send_message(u'cursor_busy') songs = self.plugin.manager.get_all_objects(Song) + songs.sort(key=lambda custom: custom.title.lower()) for song in songs: authors = u', '.join([author.display_name for author in song.authors]) From e75631d7f579e2f4990f89626a310703801c238a Mon Sep 17 00:00:00 2001 From: Chris Blake Date: Mon, 8 Aug 2011 13:30:45 -0400 Subject: [PATCH 158/184] fixed bug #817674 'Export Song - Song list appears to be random order ' Fixes: https://launchpad.net/bugs/817674 --- openlp/plugins/songs/forms/songexportform.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openlp/plugins/songs/forms/songexportform.py b/openlp/plugins/songs/forms/songexportform.py index 1e86c74a1..a654db486 100644 --- a/openlp/plugins/songs/forms/songexportform.py +++ b/openlp/plugins/songs/forms/songexportform.py @@ -249,7 +249,7 @@ class SongExportForm(OpenLPWizard): # Load the list of songs. Receiver.send_message(u'cursor_busy') songs = self.plugin.manager.get_all_objects(Song) - songs.sort(key=lambda custom: custom.title.lower()) + songs.sort(key=lambda song: song.title.lower()) for song in songs: authors = u', '.join([author.display_name for author in song.authors]) From 95f75ce26664d501c60a89263aceca8467f08be3 Mon Sep 17 00:00:00 2001 From: Chris Blake Date: Mon, 8 Aug 2011 15:15:45 -0400 Subject: [PATCH 159/184] fixed bug #817674 'Export Song - Song list appears to be random order ' Fixes: https://launchpad.net/bugs/817674 --- openlp/plugins/songs/forms/songexportform.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openlp/plugins/songs/forms/songexportform.py b/openlp/plugins/songs/forms/songexportform.py index a654db486..90c3b0275 100644 --- a/openlp/plugins/songs/forms/songexportform.py +++ b/openlp/plugins/songs/forms/songexportform.py @@ -28,6 +28,7 @@ The :mod:`songexportform` module provides the wizard for exporting songs to the OpenLyrics format. """ +import locale import logging from PyQt4 import QtCore, QtGui @@ -249,7 +250,7 @@ class SongExportForm(OpenLPWizard): # Load the list of songs. Receiver.send_message(u'cursor_busy') songs = self.plugin.manager.get_all_objects(Song) - songs.sort(key=lambda song: song.title.lower()) + songs.sort(cmp=locale.strcoll, key=lambda song: song.title.lower()) for song in songs: authors = u', '.join([author.display_name for author in song.authors]) From c0978d8e2235b88ae950fad20416890e2b0b4766 Mon Sep 17 00:00:00 2001 From: Stevan Pettit Date: Wed, 10 Aug 2011 17:29:44 -0400 Subject: [PATCH 160/184] Added code to skip-all missing files during service save --- openlp/core/ui/servicemanager.py | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/openlp/core/ui/servicemanager.py b/openlp/core/ui/servicemanager.py index 6d4ae6ec0..bd4035d54 100644 --- a/openlp/core/ui/servicemanager.py +++ b/openlp/core/ui/servicemanager.py @@ -474,6 +474,7 @@ class ServiceManager(QtGui.QWidget): item[u'service_item'].get_service_repr()}) if not item[u'service_item'].uses_file(): continue + skipMissing = False for frame in item[u'service_item'].get_frames(): if item[u'service_item'].is_image(): path_from = frame[u'path'] @@ -483,19 +484,24 @@ class ServiceManager(QtGui.QWidget): if path_from in write_list: continue if not os.path.exists(path_from): - Receiver.send_message(u'cursor_normal') - title = unicode(translate('OpenLP.ServiceManager', - 'Service File Missing')) - message = unicode(translate('OpenLP.ServiceManager', - 'File missing from service\n\n %s \n\n' - 'Continue saving?' % path_from )) - answer = QtGui.QMessageBox.critical(self, title, message, - QtGui.QMessageBox.StandardButtons( - QtGui.QMessageBox.Yes | QtGui.QMessageBox.No)) - if answer == QtGui.QMessageBox.No: - self.mainwindow.finishedProgressBar() - return False - Receiver.send_message(u'cursor_busy') + if not skipMissing: + Receiver.send_message(u'cursor_normal') + title = unicode(translate('OpenLP.ServiceManager', + 'Service File Missing')) + message = unicode(translate('OpenLP.ServiceManager', + 'File missing from service\n\n %s \n\n' + 'Continue saving?' % path_from )) + answer = QtGui.QMessageBox.critical(self, title, + message, + QtGui.QMessageBox.StandardButtons( + QtGui.QMessageBox.Yes | QtGui.QMessageBox.No | + QtGui.QMessageBox.YesToAll)) + if answer == QtGui.QMessageBox.No: + self.mainwindow.finishedProgressBar() + return False + if answer == QtGui.QMessageBox.YesToAll: + skipMissing = True + Receiver.send_message(u'cursor_busy') else: file_size = os.path.getsize(path_from) write_list.append(path_from) From ba02eb6a98a096d2895330107b465611264c934a Mon Sep 17 00:00:00 2001 From: Andreas Preikschat Date: Thu, 11 Aug 2011 11:01:25 +0200 Subject: [PATCH 161/184] moved recent files to a menu (bug #818794) Fixes: https://launchpad.net/bugs/818794 --- openlp/core/ui/mainwindow.py | 57 +++++++++++++++++++++--------------- 1 file changed, 34 insertions(+), 23 deletions(-) diff --git a/openlp/core/ui/mainwindow.py b/openlp/core/ui/mainwindow.py index c7ff6c52a..510a94dfd 100644 --- a/openlp/core/ui/mainwindow.py +++ b/openlp/core/ui/mainwindow.py @@ -109,6 +109,8 @@ class Ui_MainWindow(object): self.menuBar.setObjectName(u'menuBar') self.fileMenu = QtGui.QMenu(self.menuBar) self.fileMenu.setObjectName(u'fileMenu') + self.recentFilesMenu = QtGui.QMenu(self.fileMenu) + self.recentFilesMenu.setObjectName(u'recentFilesMenu') self.fileImportMenu = QtGui.QMenu(self.fileMenu) self.fileImportMenu.setObjectName(u'fileImportMenu') self.fileExportMenu = QtGui.QMenu(self.fileMenu) @@ -302,10 +304,11 @@ class Ui_MainWindow(object): (self.importThemeItem, self.importLanguageItem)) add_actions(self.fileExportMenu, (self.exportThemeItem, self.exportLanguageItem)) - self.fileMenuActions = (self.fileNewItem, self.fileOpenItem, + add_actions(self.fileMenu, (self.fileNewItem, self.fileOpenItem, self.fileSaveItem, self.fileSaveAsItem, None, - self.printServiceOrderItem, None, self.fileImportMenu.menuAction(), - self.fileExportMenu.menuAction(), self.fileExitItem) + self.recentFilesMenu.menuAction(), None, self.printServiceOrderItem, + None, self.fileImportMenu.menuAction(), + self.fileExportMenu.menuAction(), self.fileExitItem)) add_actions(self.viewModeMenu, (self.modeDefaultItem, self.modeSetupItem, self.modeLiveItem)) add_actions(self.viewMenu, (self.viewModeMenu.menuAction(), @@ -346,7 +349,7 @@ class Ui_MainWindow(object): self.mediaToolBox.setCurrentIndex(0) # Connect up some signals and slots QtCore.QObject.connect(self.fileMenu, - QtCore.SIGNAL(u'aboutToShow()'), self.updateFileMenu) + QtCore.SIGNAL(u'aboutToShow()'), self.updateRecentFilesMenu) QtCore.QMetaObject.connectSlotsByName(mainWindow) # Hide the entry, as it does not have any functionality yet. self.toolsAddToolItem.setVisible(False) @@ -363,6 +366,8 @@ class Ui_MainWindow(object): self.fileMenu.setTitle(translate('OpenLP.MainWindow', '&File')) self.fileImportMenu.setTitle(translate('OpenLP.MainWindow', '&Import')) self.fileExportMenu.setTitle(translate('OpenLP.MainWindow', '&Export')) + self.recentFilesMenu.setTitle( + translate('OpenLP.MainWindow', '&Recent Files')) self.viewMenu.setTitle(translate('OpenLP.MainWindow', '&View')) self.viewModeMenu.setTitle(translate('OpenLP.MainWindow', 'M&ode')) self.toolsMenu.setTitle(translate('OpenLP.MainWindow', '&Tools')) @@ -534,8 +539,8 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): self.setupUi(self) # Load settings after setupUi so default UI sizes are overwritten self.loadSettings() - # Once settings are loaded update FileMenu with recentFiles - self.updateFileMenu() + # Once settings are loaded update the menu with the recent files. + self.updateRecentFilesMenu() self.pluginForm = PluginForm(self) # Set up signals and slots QtCore.QObject.connect(self.importThemeItem, @@ -1137,30 +1142,36 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): QtCore.QVariant(self.controlSplitter.saveState())) settings.endGroup() - def updateFileMenu(self): + def updateRecentFilesMenu(self): """ - Updates the file menu with the latest list of service files accessed. + Updates the recent file menu with the latest list of service files + accessed. """ recentFileCount = QtCore.QSettings().value( u'advanced/recent file count', QtCore.QVariant(4)).toInt()[0] - self.fileMenu.clear() - add_actions(self.fileMenu, self.fileMenuActions[:-1]) existingRecentFiles = [recentFile for recentFile in self.recentFiles if QtCore.QFile.exists(recentFile)] recentFilesToDisplay = existingRecentFiles[0:recentFileCount] - if recentFilesToDisplay: - self.fileMenu.addSeparator() - for fileId, filename in enumerate(recentFilesToDisplay): - log.debug('Recent file name: %s', filename) - action = base_action(self, u'') - action.setText(u'&%d %s' % - (fileId + 1, QtCore.QFileInfo(filename).fileName())) - action.setData(QtCore.QVariant(filename)) - self.connect(action, QtCore.SIGNAL(u'triggered()'), - self.serviceManagerContents.onRecentServiceClicked) - self.fileMenu.addAction(action) - self.fileMenu.addSeparator() - self.fileMenu.addAction(self.fileMenuActions[-1]) + self.recentFilesMenu.clear() + for fileId, filename in enumerate(recentFilesToDisplay): + log.debug('Recent file name: %s', filename) + action = base_action(self, u'') + action.setText(u'&%d %s' % + (fileId + 1, QtCore.QFileInfo(filename).fileName())) + action.setData(QtCore.QVariant(filename)) + self.connect(action, QtCore.SIGNAL(u'triggered()'), + self.serviceManagerContents.onRecentServiceClicked) + self.recentFilesMenu.addAction(action) + clearRecentFilesAction = base_action(self, u'') + clearRecentFilesAction.setText( + translate('OpenLP.MainWindow', 'Clear List', + 'Clear List of recent files')) + clearRecentFilesAction.setStatusTip( + translate('OpenLP.MainWindow', 'Clear the list of recent files.')) + add_actions(self.recentFilesMenu, (None, clearRecentFilesAction)) + self.connect(clearRecentFilesAction, QtCore.SIGNAL(u'triggered()'), + self.recentFiles.clear) + clearRecentFilesAction.setEnabled(not self.recentFiles.isEmpty()) def addRecentFile(self, filename): """ From 0924bfc246393047601439b722ae47068f124ee5 Mon Sep 17 00:00:00 2001 From: Andreas Preikschat Date: Fri, 12 Aug 2011 15:11:30 +0200 Subject: [PATCH 162/184] fixed bug #804747; clean ups Fixes: https://launchpad.net/bugs/804747 --- openlp/core/lib/eventreceiver.py | 2 +- openlp/core/ui/mainwindow.py | 7 +- .../plugins/bibles/forms/bibleupgradeform.py | 113 +++++++----------- openlp/plugins/bibles/lib/db.py | 57 ++++----- openlp/plugins/bibles/lib/manager.py | 10 +- openlp/plugins/bibles/lib/mediaitem.py | 2 +- 6 files changed, 79 insertions(+), 112 deletions(-) diff --git a/openlp/core/lib/eventreceiver.py b/openlp/core/lib/eventreceiver.py index 7c0115f89..abd57721b 100644 --- a/openlp/core/lib/eventreceiver.py +++ b/openlp/core/lib/eventreceiver.py @@ -247,7 +247,7 @@ class EventReceiver(QtCore.QObject): ``msg`` Defaults to *None*. The message to send with the event. """ - log.debug(u'Event %s passed with payload %s' % (event, msg)) + #log.debug(u'Event %s passed with payload %s' % (event, msg)) self.emit(QtCore.SIGNAL(event), msg) diff --git a/openlp/core/ui/mainwindow.py b/openlp/core/ui/mainwindow.py index c7ff6c52a..cef510a81 100644 --- a/openlp/core/ui/mainwindow.py +++ b/openlp/core/ui/mainwindow.py @@ -28,6 +28,7 @@ import logging import os import sys +import shutil from tempfile import gettempdir from PyQt4 import QtCore, QtGui @@ -721,11 +722,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow): plugin.firstTime() Receiver.send_message(u'openlp_process_events') temp_dir = os.path.join(unicode(gettempdir()), u'openlp') - if not os.path.exists(temp_dir): - return - for filename in os.listdir(temp_dir): - delete_file(os.path.join(temp_dir, filename)) - os.removedirs(temp_dir) + shutil.rmtree(temp_dir, True) def onFirstTimeWizardClicked(self): """ diff --git a/openlp/plugins/bibles/forms/bibleupgradeform.py b/openlp/plugins/bibles/forms/bibleupgradeform.py index 615d4231e..1ce938b3c 100644 --- a/openlp/plugins/bibles/forms/bibleupgradeform.py +++ b/openlp/plugins/bibles/forms/bibleupgradeform.py @@ -29,6 +29,7 @@ The bible import functions for OpenLP import logging import os import shutil +from tempfile import gettempdir from PyQt4 import QtCore, QtGui @@ -124,7 +125,7 @@ class BibleUpgradeForm(OpenLPWizard): self.preWizard() self.performWizard() self.postWizard() - elif self.page(pageId) == self.selectPage and self.maxBibles == 0: + elif self.page(pageId) == self.selectPage and not self.files: self.next() def onBackupBrowseButtonClicked(self): @@ -425,9 +426,13 @@ class BibleUpgradeForm(OpenLPWizard): return False return True elif self.currentPage() == self.selectPage: + temp_dir = os.path.join(gettempdir(), u'openlp') + check_directory_exists(temp_dir) for number, filename in enumerate(self.files): if not self.checkBox[number].checkState() == QtCore.Qt.Checked: continue + # Move bibles to temp dir. + shutil.move(os.path.join(self.path, filename[0]), temp_dir) version_name = unicode(self.versionNameEdit[number].text()) if not version_name: critical_error_message_box(UiStrings().EmptyField, @@ -435,37 +440,6 @@ class BibleUpgradeForm(OpenLPWizard): 'You need to specify a version name for your Bible.')) self.versionNameEdit[number].setFocus() return False - elif self.manager.exists(version_name): - critical_error_message_box( - translate('BiblesPlugin.UpgradeWizardForm', - 'Bible Exists'), - translate('BiblesPlugin.UpgradeWizardForm', - 'This Bible already exists. Please upgrade ' - 'a different Bible, delete the existing one or ' - 'uncheck.')) - self.versionNameEdit[number].setFocus() - return False - elif os.path.exists(os.path.join(self.path, clean_filename( - version_name))) and version_name == filename[1]: - newfilename = u'old_database_%s' % filename[0] - if not os.path.exists(os.path.join(self.path, - newfilename)): - os.rename(os.path.join(self.path, filename[0]), - os.path.join(self.path, newfilename)) - self.files[number] = [newfilename, filename[1]] - continue - else: - critical_error_message_box( - translate('BiblesPlugin.UpgradeWizardForm', - 'Bible Exists'), - translate('BiblesPlugin.UpgradeWizardForm', - 'This Bible already exists. Please upgrade ' - 'a different Bible, delete the existing one or ' - 'uncheck.')) - self.verticalWidget[number].show() - self.formWidget[number].show() - self.versionNameEdit[number].setFocus() - return False elif os.path.exists(os.path.join(self.path, clean_filename(version_name))): critical_error_message_box( @@ -495,7 +469,6 @@ class BibleUpgradeForm(OpenLPWizard): self.files = self.manager.old_bible_databases self.addScrollArea() self.retranslateUi() - self.maxBibles = len(self.files) for number, filename in enumerate(self.files): self.checkBox[number].setCheckState(QtCore.Qt.Checked) oldname = filename[1] @@ -516,9 +489,8 @@ class BibleUpgradeForm(OpenLPWizard): Prepare the UI for the upgrade. """ OpenLPWizard.preWizard(self) - self.progressLabel.setText(translate( - 'BiblesPlugin.UpgradeWizardForm', - 'Starting upgrade...')) + self.progressLabel.setText( + translate('BiblesPlugin.UpgradeWizardForm', 'Starting upgrade...')) Receiver.send_message(u'openlp_process_events') def performWizard(self): @@ -527,46 +499,47 @@ class BibleUpgradeForm(OpenLPWizard): """ self.include_webbible = False proxy_server = None - if self.maxBibles == 0: + if not self.files: self.progressLabel.setText( translate('BiblesPlugin.UpgradeWizardForm', 'There are no ' 'Bibles that need to be upgraded.')) self.progressBar.hide() return - self.maxBibles = 0 + max_bibles = 0 for number, file in enumerate(self.files): if self.checkBox[number].checkState() == QtCore.Qt.Checked: - self.maxBibles += 1 - number = 0 - for biblenumber, filename in enumerate(self.files): + max_bibles += 1 + temp_dir = os.path.join(gettempdir(), u'openlp') + for number, filename in enumerate(self.files): if self.stop_import_flag: bible_failed = True break bible_failed = False - self.success[biblenumber] = False - if not self.checkBox[biblenumber].checkState() == QtCore.Qt.Checked: + self.success[number] = False + if not self.checkBox[number].checkState() == QtCore.Qt.Checked: continue self.progressBar.reset() - oldbible = OldBibleDB(self.mediaItem, path=self.path, + oldbible = OldBibleDB(self.mediaItem, path=temp_dir, file=filename[0]) name = filename[1] if name is None: + print u'no Name!!!' + # FIXME: ? delete_file(os.path.join(self.path, filename[0])) self.incrementProgressBar(unicode(translate( 'BiblesPlugin.UpgradeWizardForm', 'Upgrading Bible %s of %s: "%s"\nFailed')) % - (number + 1, self.maxBibles, name), + (number + 1, max_bibles, name), self.progressBar.maximum() - self.progressBar.value()) - number += 1 continue self.progressLabel.setText(unicode(translate( 'BiblesPlugin.UpgradeWizardForm', 'Upgrading Bible %s of %s: "%s"\nUpgrading ...')) % - (number + 1, self.maxBibles, name)) + (number + 1, max_bibles, name)) if os.path.exists(os.path.join(self.path, filename[0])): - name = unicode(self.versionNameEdit[biblenumber].text()) + name = unicode(self.versionNameEdit[number].text()) self.newbibles[number] = BibleDB(self.mediaItem, path=self.path, - name=name) + name=name, file=filename[0]) self.newbibles[number].register(self.plugin.upgrade_wizard) metadata = oldbible.get_metadata() webbible = False @@ -595,7 +568,7 @@ class BibleUpgradeForm(OpenLPWizard): u'name: "%s" failed' % ( meta_data[u'download source'], meta_data[u'download name'])) - delete_database(self.path, clean_filename(name)) + delete_database(temp_dir, clean_filename(name)) del self.newbibles[number] critical_error_message_box( translate('BiblesPlugin.UpgradeWizardForm', @@ -606,9 +579,8 @@ class BibleUpgradeForm(OpenLPWizard): self.incrementProgressBar(unicode(translate( 'BiblesPlugin.UpgradeWizardForm', 'Upgrading Bible %s of %s: "%s"\nFailed')) % - (number + 1, self.maxBibles, name), + (number + 1, max_bibles, name), self.progressBar.maximum() - self.progressBar.value()) - number += 1 continue bible = BiblesResourcesDB.get_webbible( meta_data[u'download name'], @@ -621,14 +593,13 @@ class BibleUpgradeForm(OpenLPWizard): language_id = self.newbibles[number].get_language(name) if not language_id: log.warn(u'Upgrading from "%s" failed' % filename[0]) - delete_database(self.path, clean_filename(name)) + delete_database(temp_dir, clean_filename(name)) del self.newbibles[number] self.incrementProgressBar(unicode(translate( 'BiblesPlugin.UpgradeWizardForm', 'Upgrading Bible %s of %s: "%s"\nFailed')) % - (number + 1, self.maxBibles, name), + (number + 1, max_bibles, name), self.progressBar.maximum() - self.progressBar.value()) - number += 1 continue self.progressBar.setMaximum(len(books)) for book in books: @@ -639,7 +610,7 @@ class BibleUpgradeForm(OpenLPWizard): 'BiblesPlugin.UpgradeWizardForm', 'Upgrading Bible %s of %s: "%s"\n' 'Upgrading %s ...')) % - (number + 1, self.maxBibles, name, book)) + (number + 1, max_bibles, name, book)) book_ref_id = self.newbibles[number].\ get_book_ref_id_by_name(book, len(books), language_id) if not book_ref_id: @@ -647,7 +618,7 @@ class BibleUpgradeForm(OpenLPWizard): u'name: "%s" aborted by user' % ( meta_data[u'download source'], meta_data[u'download name'])) - delete_database(self.path, clean_filename(name)) + delete_database(temp_dir, clean_filename(name)) del self.newbibles[number] bible_failed = True break @@ -678,14 +649,13 @@ class BibleUpgradeForm(OpenLPWizard): language_id = self.newbibles[number].get_language(name) if not language_id: log.warn(u'Upgrading books from "%s" failed' % name) - delete_database(self.path, clean_filename(name)) + delete_database(temp_dir, clean_filename(name)) del self.newbibles[number] self.incrementProgressBar(unicode(translate( 'BiblesPlugin.UpgradeWizardForm', 'Upgrading Bible %s of %s: "%s"\nFailed')) % - (number + 1, self.maxBibles, name), + (number + 1, max_bibles, name), self.progressBar.maximum() - self.progressBar.value()) - number += 1 continue books = oldbible.get_books() self.progressBar.setMaximum(len(books)) @@ -697,14 +667,14 @@ class BibleUpgradeForm(OpenLPWizard): 'BiblesPlugin.UpgradeWizardForm', 'Upgrading Bible %s of %s: "%s"\n' 'Upgrading %s ...')) % - (number + 1, self.maxBibles, name, book[u'name'])) + (number + 1, max_bibles, name, book[u'name'])) book_ref_id = self.newbibles[number].\ get_book_ref_id_by_name(book[u'name'], len(books), language_id) if not book_ref_id: log.warn(u'Upgrading books from %s " '\ 'failed - aborted by user' % name) - delete_database(self.path, clean_filename(name)) + delete_database(temp_dir, clean_filename(name)) del self.newbibles[number] bible_failed = True break @@ -729,21 +699,21 @@ class BibleUpgradeForm(OpenLPWizard): if not bible_failed: self.newbibles[number].create_meta(u'Version', name) oldbible.close_connection() - delete_file(os.path.join(self.path, filename[0])) + delete_file(os.path.join(temp_dir, filename[0])) self.incrementProgressBar(unicode(translate( 'BiblesPlugin.UpgradeWizardForm', 'Upgrading Bible %s of %s: "%s"\n' 'Complete')) % - (number + 1, self.maxBibles, name)) - self.success[biblenumber] = True + (number + 1, max_bibles, name)) + self.success[number] = True else: self.incrementProgressBar(unicode(translate( 'BiblesPlugin.UpgradeWizardForm', 'Upgrading Bible %s of %s: "%s"\nFailed')) % - (number + 1, self.maxBibles, name), + (number + 1, max_bibles, name), self.progressBar.maximum() - self.progressBar.value()) - delete_database(self.path, clean_filename(name)) - number += 1 + delete_database(temp_dir, clean_filename(name)) + shutil.rmtree(temp_dir, True) def postWizard(self): """ @@ -752,7 +722,7 @@ class BibleUpgradeForm(OpenLPWizard): successful_import = 0 failed_import = 0 for number, filename in enumerate(self.files): - if number in self.success and self.success[number] == True: + if self.success.has_key(number) and self.success[number]: successful_import += 1 elif self.checkBox[number].checkState() == QtCore.Qt.Checked: failed_import += 1 @@ -776,7 +746,6 @@ class BibleUpgradeForm(OpenLPWizard): 'Bible(s): %s successful%s')) % (successful_import, failed_import_text)) else: - self.progressLabel.setText( - translate('BiblesPlugin.UpgradeWizardForm', 'Upgrade ' - 'failed.')) + self.progressLabel.setText(translate( + 'BiblesPlugin.UpgradeWizardForm', 'Upgrade failed.')) OpenLPWizard.postWizard(self) diff --git a/openlp/plugins/bibles/lib/db.py b/openlp/plugins/bibles/lib/db.py index 5273f670c..7be2ca84a 100644 --- a/openlp/plugins/bibles/lib/db.py +++ b/openlp/plugins/bibles/lib/db.py @@ -169,6 +169,7 @@ class BibleDB(QtCore.QObject, Manager): self.wizard = None QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'openlp_stop_wizard'), self.stop_import) + print kwargs, (self.file, self.path) def stop_import(self): """ @@ -210,7 +211,7 @@ class BibleDB(QtCore.QObject, Manager): The book_reference_id from bibles_resources.sqlite of the book. ``testament`` - *Defaults to 1.* The testament_reference_id from + *Defaults to 1.* The testament_reference_id from bibles_resources.sqlite of the testament this book belongs to. """ log.debug(u'BibleDB.create_book("%s", "%s")', name, bk_ref_id) @@ -329,7 +330,7 @@ class BibleDB(QtCore.QObject, Manager): return self.get_object_filtered(Book, Book.book_reference_id.like(id)) def get_book_ref_id_by_name(self, book, maxbooks, language_id=None): - log.debug(u'BibleDB.get_book_ref_id_by_name:("%s", "%s")', book, + log.debug(u'BibleDB.get_book_ref_id_by_name:("%s", "%s")', book, language_id) if BiblesResourcesDB.get_book(book, True): book_temp = BiblesResourcesDB.get_book(book, True) @@ -471,7 +472,7 @@ class BibleDB(QtCore.QObject, Manager): def get_language(self, bible_name=None): """ - If no language is given it calls a dialog window where the user could + If no language is given it calls a dialog window where the user could select the bible language. Return the language id of a bible. @@ -521,9 +522,9 @@ class BiblesResourcesDB(QtCore.QObject, Manager): some resources which are used in the Bibles plugin. A wrapper class around a small SQLite database which contains the download resources, a biblelist from the different download resources, the books, - chapter counts and verse counts for the web download Bibles, a language - reference, the testament reference and some alternative book names. This - class contains a singleton "cursor" so that only one connection to the + chapter counts and verse counts for the web download Bibles, a language + reference, the testament reference and some alternative book names. This + class contains a singleton "cursor" so that only one connection to the SQLite database is ever used. """ cursor = None @@ -582,7 +583,7 @@ class BiblesResourcesDB(QtCore.QObject, Manager): ``name`` The name or abbreviation of the book. - + ``lower`` True if the comparsion should be only lowercase """ @@ -592,7 +593,7 @@ class BiblesResourcesDB(QtCore.QObject, Manager): if lower: books = BiblesResourcesDB.run_sql(u'SELECT id, testament_id, name, ' u'abbreviation, chapters FROM book_reference WHERE ' - u'LOWER(name) = ? OR LOWER(abbreviation) = ?', + u'LOWER(name) = ? OR LOWER(abbreviation) = ?', (name.lower(), name.lower())) else: books = BiblesResourcesDB.run_sql(u'SELECT id, testament_id, name, ' @@ -621,7 +622,7 @@ class BiblesResourcesDB(QtCore.QObject, Manager): if not isinstance(id, int): id = int(id) books = BiblesResourcesDB.run_sql(u'SELECT id, testament_id, name, ' - u'abbreviation, chapters FROM book_reference WHERE id = ?', + u'abbreviation, chapters FROM book_reference WHERE id = ?', (id, )) if books: return { @@ -645,12 +646,12 @@ class BiblesResourcesDB(QtCore.QObject, Manager): ``chapter`` The chapter number. """ - log.debug(u'BiblesResourcesDB.get_chapter("%s", "%s")', book_id, + log.debug(u'BiblesResourcesDB.get_chapter("%s", "%s")', book_id, chapter) if not isinstance(chapter, int): chapter = int(chapter) chapters = BiblesResourcesDB.run_sql(u'SELECT id, book_reference_id, ' - u'chapter, verse_count FROM chapters WHERE book_reference_id = ?', + u'chapter, verse_count FROM chapters WHERE book_reference_id = ?', (book_id,)) if chapters: return { @@ -687,7 +688,7 @@ class BiblesResourcesDB(QtCore.QObject, Manager): ``chapter`` The number of the chapter. """ - log.debug(u'BiblesResourcesDB.get_verse_count("%s", "%s")', book_id, + log.debug(u'BiblesResourcesDB.get_verse_count("%s", "%s")', book_id, chapter) details = BiblesResourcesDB.get_chapter(book_id, chapter) if details: @@ -715,7 +716,7 @@ class BiblesResourcesDB(QtCore.QObject, Manager): } else: return None - + @staticmethod def get_webbibles(source): """ @@ -737,7 +738,7 @@ class BiblesResourcesDB(QtCore.QObject, Manager): u'id': bible[0], u'name': bible[1], u'abbreviation': bible[2], - u'language_id': bible[3], + u'language_id': bible[3], u'download_source_id': bible[4] } for bible in bibles @@ -752,11 +753,11 @@ class BiblesResourcesDB(QtCore.QObject, Manager): ``abbreviation`` The abbreviation of the webbible. - + ``source`` The source of the webbible. """ - log.debug(u'BiblesResourcesDB.get_webbibles("%s", "%s")', abbreviation, + log.debug(u'BiblesResourcesDB.get_webbibles("%s", "%s")', abbreviation, source) if not isinstance(abbreviation, unicode): abbreviation = unicode(abbreviation) @@ -765,14 +766,14 @@ class BiblesResourcesDB(QtCore.QObject, Manager): source = BiblesResourcesDB.get_download_source(source) bible = BiblesResourcesDB.run_sql(u'SELECT id, name, abbreviation, ' u'language_id, download_source_id FROM webbibles WHERE ' - u'download_source_id = ? AND abbreviation = ?', (source[u'id'], + u'download_source_id = ? AND abbreviation = ?', (source[u'id'], abbreviation)) if bible: return { u'id': bible[0][0], u'name': bible[0][1], u'abbreviation': bible[0][2], - u'language_id': bible[0][3], + u'language_id': bible[0][3], u'download_source_id': bible[0][4] } else: @@ -785,11 +786,11 @@ class BiblesResourcesDB(QtCore.QObject, Manager): ``name`` The name to search the id. - + ``language_id`` The language_id for which language should be searched """ - log.debug(u'BiblesResourcesDB.get_alternative_book_name("%s", "%s")', + log.debug(u'BiblesResourcesDB.get_alternative_book_name("%s", "%s")', name, language_id) if language_id: books = BiblesResourcesDB.run_sql(u'SELECT book_reference_id, name ' @@ -806,7 +807,7 @@ class BiblesResourcesDB(QtCore.QObject, Manager): @staticmethod def get_language(name): """ - Return a dict containing the language id, name and code by name or + Return a dict containing the language id, name and code by name or abbreviation. ``name`` @@ -865,7 +866,7 @@ class BiblesResourcesDB(QtCore.QObject, Manager): class AlternativeBookNamesDB(QtCore.QObject, Manager): """ - This class represents a database-bound alternative book names system. + This class represents a database-bound alternative book names system. """ cursor = None conn = None @@ -874,7 +875,7 @@ class AlternativeBookNamesDB(QtCore.QObject, Manager): def get_cursor(): """ Return the cursor object. Instantiate one if it doesn't exist yet. - If necessary loads up the database and creates the tables if the + If necessary loads up the database and creates the tables if the database doesn't exist. """ if AlternativeBookNamesDB.cursor is None: @@ -904,7 +905,7 @@ class AlternativeBookNamesDB(QtCore.QObject, Manager): ``parameters`` Any variable parameters to add to the query - + ``commit`` If a commit statement is necessary this should be True. """ @@ -921,11 +922,11 @@ class AlternativeBookNamesDB(QtCore.QObject, Manager): ``name`` The name to search the id. - + ``language_id`` The language_id for which language should be searched """ - log.debug(u'AlternativeBookNamesDB.get_book_reference_id("%s", "%s")', + log.debug(u'AlternativeBookNamesDB.get_book_reference_id("%s", "%s")', name, language_id) if language_id: books = AlternativeBookNamesDB.run_sql(u'SELECT book_reference_id, ' @@ -962,11 +963,11 @@ class AlternativeBookNamesDB(QtCore.QObject, Manager): class OldBibleDB(QtCore.QObject, Manager): """ - This class conects to the old bible databases to reimport them to the new + This class conects to the old bible databases to reimport them to the new database scheme. """ cursor = None - + def __init__(self, parent, **kwargs): """ The constructor loads up the database and creates and initialises the diff --git a/openlp/plugins/bibles/lib/manager.py b/openlp/plugins/bibles/lib/manager.py index 354332083..fcccd7bcf 100644 --- a/openlp/plugins/bibles/lib/manager.py +++ b/openlp/plugins/bibles/lib/manager.py @@ -153,7 +153,7 @@ class BibleManager(object): if name is None: delete_file(os.path.join(self.path, filename)) continue - # Find old database versions + # Find old database versions. if bible.is_old_database(): self.old_bible_databases.append([filename, name]) bible.session.close() @@ -220,7 +220,7 @@ class BibleManager(object): return [ { u'name': book.name, - u'book_reference_id': book.book_reference_id, + u'book_reference_id': book.book_reference_id, u'chapters': self.db_cache[bible].get_chapter_count(book) } for book in self.db_cache[bible].get_books() @@ -229,10 +229,10 @@ class BibleManager(object): def get_chapter_count(self, bible, book): """ Returns the number of Chapters for a given book. - + ``bible`` Unicode. The Bible to get the list of books from. - + ``book`` The book object to get the chapter count for. """ @@ -295,7 +295,7 @@ class BibleManager(object): if db_book: book_id = db_book.book_reference_id log.debug(u'Book name corrected to "%s"', db_book.name) - new_reflist.append((book_id, item[1], item[2], + new_reflist.append((book_id, item[1], item[2], item[3])) else: log.debug(u'OpenLP failed to find book %s', item[0]) diff --git a/openlp/plugins/bibles/lib/mediaitem.py b/openlp/plugins/bibles/lib/mediaitem.py index 82ee4430c..5a5f77c50 100644 --- a/openlp/plugins/bibles/lib/mediaitem.py +++ b/openlp/plugins/bibles/lib/mediaitem.py @@ -612,7 +612,7 @@ class BibleMediaItem(MediaManagerItem): if restore: old_text = unicode(combo.currentText()) combo.clear() - combo.addItems([unicode(i) for i in range(range_from, range_to + 1)]) + combo.addItems(map(unicode, range(range_from, range_to + 1))) if restore and combo.findText(old_text) != -1: combo.setCurrentIndex(combo.findText(old_text)) From 4831cf0a7c7970a82b46bfd893ef1774b15147c8 Mon Sep 17 00:00:00 2001 From: Andreas Preikschat Date: Fri, 12 Aug 2011 15:16:06 +0200 Subject: [PATCH 163/184] more clean ups --- openlp/plugins/bibles/forms/bibleupgradeform.py | 14 ++------------ openlp/plugins/bibles/lib/db.py | 1 - 2 files changed, 2 insertions(+), 13 deletions(-) diff --git a/openlp/plugins/bibles/forms/bibleupgradeform.py b/openlp/plugins/bibles/forms/bibleupgradeform.py index 1ce938b3c..80b6ad910 100644 --- a/openlp/plugins/bibles/forms/bibleupgradeform.py +++ b/openlp/plugins/bibles/forms/bibleupgradeform.py @@ -35,10 +35,9 @@ from PyQt4 import QtCore, QtGui from openlp.core.lib import Receiver, SettingsManager, translate, \ check_directory_exists -from openlp.core.lib.db import delete_database from openlp.core.lib.ui import UiStrings, critical_error_message_box from openlp.core.ui.wizard import OpenLPWizard, WizardStrings -from openlp.core.utils import AppLocation, delete_file +from openlp.core.utils import AppLocation from openlp.plugins.bibles.lib.db import BibleDB, BibleMeta, OldBibleDB, \ BiblesResourcesDB, clean_filename from openlp.plugins.bibles.lib.http import BSExtract, BGExtract, CWExtract @@ -523,9 +522,6 @@ class BibleUpgradeForm(OpenLPWizard): file=filename[0]) name = filename[1] if name is None: - print u'no Name!!!' - # FIXME: ? - delete_file(os.path.join(self.path, filename[0])) self.incrementProgressBar(unicode(translate( 'BiblesPlugin.UpgradeWizardForm', 'Upgrading Bible %s of %s: "%s"\nFailed')) % @@ -568,7 +564,6 @@ class BibleUpgradeForm(OpenLPWizard): u'name: "%s" failed' % ( meta_data[u'download source'], meta_data[u'download name'])) - delete_database(temp_dir, clean_filename(name)) del self.newbibles[number] critical_error_message_box( translate('BiblesPlugin.UpgradeWizardForm', @@ -593,7 +588,6 @@ class BibleUpgradeForm(OpenLPWizard): language_id = self.newbibles[number].get_language(name) if not language_id: log.warn(u'Upgrading from "%s" failed' % filename[0]) - delete_database(temp_dir, clean_filename(name)) del self.newbibles[number] self.incrementProgressBar(unicode(translate( 'BiblesPlugin.UpgradeWizardForm', @@ -618,7 +612,6 @@ class BibleUpgradeForm(OpenLPWizard): u'name: "%s" aborted by user' % ( meta_data[u'download source'], meta_data[u'download name'])) - delete_database(temp_dir, clean_filename(name)) del self.newbibles[number] bible_failed = True break @@ -649,7 +642,6 @@ class BibleUpgradeForm(OpenLPWizard): language_id = self.newbibles[number].get_language(name) if not language_id: log.warn(u'Upgrading books from "%s" failed' % name) - delete_database(temp_dir, clean_filename(name)) del self.newbibles[number] self.incrementProgressBar(unicode(translate( 'BiblesPlugin.UpgradeWizardForm', @@ -674,7 +666,6 @@ class BibleUpgradeForm(OpenLPWizard): if not book_ref_id: log.warn(u'Upgrading books from %s " '\ 'failed - aborted by user' % name) - delete_database(temp_dir, clean_filename(name)) del self.newbibles[number] bible_failed = True break @@ -699,7 +690,6 @@ class BibleUpgradeForm(OpenLPWizard): if not bible_failed: self.newbibles[number].create_meta(u'Version', name) oldbible.close_connection() - delete_file(os.path.join(temp_dir, filename[0])) self.incrementProgressBar(unicode(translate( 'BiblesPlugin.UpgradeWizardForm', 'Upgrading Bible %s of %s: "%s"\n' @@ -712,7 +702,7 @@ class BibleUpgradeForm(OpenLPWizard): 'Upgrading Bible %s of %s: "%s"\nFailed')) % (number + 1, max_bibles, name), self.progressBar.maximum() - self.progressBar.value()) - delete_database(temp_dir, clean_filename(name)) + # Remove old bibles. shutil.rmtree(temp_dir, True) def postWizard(self): diff --git a/openlp/plugins/bibles/lib/db.py b/openlp/plugins/bibles/lib/db.py index 7be2ca84a..f37b73ab0 100644 --- a/openlp/plugins/bibles/lib/db.py +++ b/openlp/plugins/bibles/lib/db.py @@ -169,7 +169,6 @@ class BibleDB(QtCore.QObject, Manager): self.wizard = None QtCore.QObject.connect(Receiver.get_receiver(), QtCore.SIGNAL(u'openlp_stop_wizard'), self.stop_import) - print kwargs, (self.file, self.path) def stop_import(self): """ From 3f3ab71eeb032d5d5cca33cd62cc8aacb6746e5f Mon Sep 17 00:00:00 2001 From: Andreas Preikschat Date: Fri, 12 Aug 2011 15:38:05 +0200 Subject: [PATCH 164/184] more clean ups --- openlp/core/lib/eventreceiver.py | 2 +- openlp/plugins/bibles/forms/bibleupgradeform.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/openlp/core/lib/eventreceiver.py b/openlp/core/lib/eventreceiver.py index abd57721b..7c0115f89 100644 --- a/openlp/core/lib/eventreceiver.py +++ b/openlp/core/lib/eventreceiver.py @@ -247,7 +247,7 @@ class EventReceiver(QtCore.QObject): ``msg`` Defaults to *None*. The message to send with the event. """ - #log.debug(u'Event %s passed with payload %s' % (event, msg)) + log.debug(u'Event %s passed with payload %s' % (event, msg)) self.emit(QtCore.SIGNAL(event), msg) diff --git a/openlp/plugins/bibles/forms/bibleupgradeform.py b/openlp/plugins/bibles/forms/bibleupgradeform.py index 80b6ad910..a49d1a25a 100644 --- a/openlp/plugins/bibles/forms/bibleupgradeform.py +++ b/openlp/plugins/bibles/forms/bibleupgradeform.py @@ -618,7 +618,7 @@ class BibleUpgradeForm(OpenLPWizard): book_details = BiblesResourcesDB.get_book_by_id(book_ref_id) db_book = self.newbibles[number].create_book(book, book_ref_id, book_details[u'testament_id']) - # Try to import still downloaded verses + # Try to import already downloaded verses. oldbook = oldbible.get_book(book) if oldbook: verses = oldbible.get_verses(oldbook[u'id']) From 11f3a9e13a6733e78a4282585c0c4b4ad25d27e7 Mon Sep 17 00:00:00 2001 From: Andreas Preikschat Date: Fri, 12 Aug 2011 16:54:16 +0200 Subject: [PATCH 165/184] removed code; moved clean_filename method to utils --- openlp/core/utils/__init__.py | 13 +++++++++++- .../plugins/bibles/forms/bibleupgradeform.py | 20 +------------------ openlp/plugins/bibles/lib/db.py | 17 ++-------------- openlp/plugins/songs/lib/openlyricsexport.py | 1 + 4 files changed, 16 insertions(+), 35 deletions(-) diff --git a/openlp/core/utils/__init__.py b/openlp/core/utils/__init__.py index b0a28962c..3612bb002 100644 --- a/openlp/core/utils/__init__.py +++ b/openlp/core/utils/__init__.py @@ -386,6 +386,17 @@ def split_filename(path): else: return os.path.split(path) +def clean_filename(filename): + """ + Removes invalid characters from the given ``filename``. + + ``filename`` + The "dirty" file name to clean. + """ + if not isinstance(filename, unicode): + filename = unicode(filename, u'utf-8') + return re.sub(r'[/\\?*|<>\[\]":<>+%]+', u'_', filename).strip(u'_') + def delete_file(file_path_name): """ Deletes a file from the system. @@ -492,4 +503,4 @@ from actions import ActionList __all__ = [u'AppLocation', u'get_application_version', u'check_latest_version', u'add_actions', u'get_filesystem_encoding', u'LanguageManager', u'ActionList', u'get_web_page', u'file_is_unicode', u'get_uno_command', - u'get_uno_instance', u'delete_file'] + u'get_uno_instance', u'delete_file', u'clean_filename'] diff --git a/openlp/plugins/bibles/forms/bibleupgradeform.py b/openlp/plugins/bibles/forms/bibleupgradeform.py index a49d1a25a..669af68b3 100644 --- a/openlp/plugins/bibles/forms/bibleupgradeform.py +++ b/openlp/plugins/bibles/forms/bibleupgradeform.py @@ -39,7 +39,7 @@ from openlp.core.lib.ui import UiStrings, critical_error_message_box from openlp.core.ui.wizard import OpenLPWizard, WizardStrings from openlp.core.utils import AppLocation from openlp.plugins.bibles.lib.db import BibleDB, BibleMeta, OldBibleDB, \ - BiblesResourcesDB, clean_filename + BiblesResourcesDB from openlp.plugins.bibles.lib.http import BSExtract, BGExtract, CWExtract log = logging.getLogger(__name__) @@ -432,24 +432,6 @@ class BibleUpgradeForm(OpenLPWizard): continue # Move bibles to temp dir. shutil.move(os.path.join(self.path, filename[0]), temp_dir) - version_name = unicode(self.versionNameEdit[number].text()) - if not version_name: - critical_error_message_box(UiStrings().EmptyField, - translate('BiblesPlugin.UpgradeWizardForm', - 'You need to specify a version name for your Bible.')) - self.versionNameEdit[number].setFocus() - return False - elif os.path.exists(os.path.join(self.path, - clean_filename(version_name))): - critical_error_message_box( - translate('BiblesPlugin.UpgradeWizardForm', - 'Bible Exists'), - translate('BiblesPlugin.UpgradeWizardForm', - 'This Bible already exists. Please upgrade ' - 'a different Bible, delete the existing one or ' - 'uncheck.')) - self.versionNameEdit[number].setFocus() - return False return True if self.currentPage() == self.progressPage: return True diff --git a/openlp/plugins/bibles/lib/db.py b/openlp/plugins/bibles/lib/db.py index f37b73ab0..e5962664b 100644 --- a/openlp/plugins/bibles/lib/db.py +++ b/openlp/plugins/bibles/lib/db.py @@ -39,7 +39,7 @@ from sqlalchemy.orm.exc import UnmappedClassError from openlp.core.lib import Receiver, translate from openlp.core.lib.db import BaseModel, init_db, Manager from openlp.core.lib.ui import critical_error_message_box -from openlp.core.utils import AppLocation +from openlp.core.utils import AppLocation, clean_filename log = logging.getLogger(__name__) @@ -63,19 +63,6 @@ class Verse(BaseModel): """ pass -def clean_filename(filename): - """ - Clean up the version name of the Bible and convert it into a valid - file name. - - ``filename`` - The "dirty" file name or version name. - """ - if not isinstance(filename, unicode): - filename = unicode(filename, u'utf-8') - filename = re.sub(r'[^\w]+', u'_', filename).strip(u'_') - return filename + u'.sqlite' - def init_schema(url): """ Setup a bible database connection and initialise the database schema. @@ -158,7 +145,7 @@ class BibleDB(QtCore.QObject, Manager): self.name = kwargs[u'name'] if not isinstance(self.name, unicode): self.name = unicode(self.name, u'utf-8') - self.file = clean_filename(self.name) + self.file = clean_filename(self.name) + u'.sqlite' if u'file' in kwargs: self.file = kwargs[u'file'] Manager.__init__(self, u'bibles', init_schema, self.file) diff --git a/openlp/plugins/songs/lib/openlyricsexport.py b/openlp/plugins/songs/lib/openlyricsexport.py index 6ba1fabe7..de86e1c05 100644 --- a/openlp/plugins/songs/lib/openlyricsexport.py +++ b/openlp/plugins/songs/lib/openlyricsexport.py @@ -35,6 +35,7 @@ import re from lxml import etree from openlp.core.lib import check_directory_exists, Receiver, translate +from openlp.core.utils import clean_filename from openlp.plugins.songs.lib import OpenLyrics log = logging.getLogger(__name__) From 6c96794af183979374aa699fb00ac4c5057920e9 Mon Sep 17 00:00:00 2001 From: Andreas Preikschat Date: Fri, 12 Aug 2011 17:31:16 +0200 Subject: [PATCH 166/184] restore not upgraded bibles; clean ups --- .../plugins/bibles/forms/bibleupgradeform.py | 46 +++++++++++-------- openlp/plugins/songs/lib/openlyricsexport.py | 3 +- 2 files changed, 27 insertions(+), 22 deletions(-) diff --git a/openlp/plugins/bibles/forms/bibleupgradeform.py b/openlp/plugins/bibles/forms/bibleupgradeform.py index 669af68b3..f34236503 100644 --- a/openlp/plugins/bibles/forms/bibleupgradeform.py +++ b/openlp/plugins/bibles/forms/bibleupgradeform.py @@ -37,7 +37,7 @@ from openlp.core.lib import Receiver, SettingsManager, translate, \ check_directory_exists from openlp.core.lib.ui import UiStrings, critical_error_message_box from openlp.core.ui.wizard import OpenLPWizard, WizardStrings -from openlp.core.utils import AppLocation +from openlp.core.utils import AppLocation, delete_file from openlp.plugins.bibles.lib.db import BibleDB, BibleMeta, OldBibleDB, \ BiblesResourcesDB from openlp.plugins.bibles.lib.http import BSExtract, BGExtract, CWExtract @@ -254,23 +254,22 @@ class BibleUpgradeForm(OpenLPWizard): for number, filename in enumerate(self.files): bible = OldBibleDB(self.mediaItem, path=self.path, file=filename[0]) self.checkBox[number] = QtGui.QCheckBox(self.scrollAreaContents) - checkBoxName = u'checkBox[%d]' % number - self.checkBox[number].setObjectName(checkBoxName) + self.checkBox[number].setObjectName(u'checkBox[%d]' % number) self.checkBox[number].setText(bible.get_name()) self.checkBox[number].setCheckState(QtCore.Qt.Checked) self.formLayout.addWidget(self.checkBox[number]) self.verticalWidget[number] = QtGui.QWidget(self.scrollAreaContents) - verticalWidgetName = u'verticalWidget[%d]' % number - self.verticalWidget[number].setObjectName(verticalWidgetName) + self.verticalWidget[number].setObjectName( + u'verticalWidget[%d]' % number) self.horizontalLayout[number] = QtGui.QHBoxLayout( self.verticalWidget[number]) self.horizontalLayout[number].setContentsMargins(25, 0, 0, 0) - horizontalLayoutName = u'horizontalLayout[%d]' % number - self.horizontalLayout[number].setObjectName(horizontalLayoutName) + self.horizontalLayout[number].setObjectName( + u'horizontalLayout[%d]' % number) self.versionInfoPixmap[number] = QtGui.QLabel( self.verticalWidget[number]) - versionInfoPixmapName = u'versionInfoPixmap[%d]' % number - self.versionInfoPixmap[number].setObjectName(versionInfoPixmapName) + self.versionInfoPixmap[number].setObjectName( + u'versionInfoPixmap[%d]' % number) self.versionInfoPixmap[number].setPixmap(QtGui.QPixmap( u':/bibles/bibles_upgrade_alert.png')) self.versionInfoPixmap[number].setAlignment(QtCore.Qt.AlignRight) @@ -278,8 +277,8 @@ class BibleUpgradeForm(OpenLPWizard): self.versionInfoPixmap[number]) self.versionInfoLabel[number] = QtGui.QLabel( self.verticalWidget[number]) - versionInfoLabelName = u'versionInfoLabel[%d]' % number - self.versionInfoLabel[number].setObjectName(versionInfoLabelName) + self.versionInfoLabel[number].setObjectName( + u'versionInfoLabel[%d]' % number) sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Preferred) sizePolicy.setHorizontalStretch(0) @@ -291,14 +290,12 @@ class BibleUpgradeForm(OpenLPWizard): self.versionInfoLabel[number]) self.formLayout.addWidget(self.verticalWidget[number]) self.formWidget[number] = QtGui.QWidget(self.scrollAreaContents) - formWidgetName = u'formWidget[%d]' % number - self.formWidget[number].setObjectName(formWidgetName) + self.formWidget[number].setObjectName(u'formWidget[%d]' % number) self.formLayoutAttention[number] = QtGui.QFormLayout( self.formWidget[number]) self.formLayoutAttention[number].setContentsMargins(25, 0, 0, 5) - formLayoutAttentionName = u'formLayoutAttention[%d]' % number self.formLayoutAttention[number].setObjectName( - formLayoutAttentionName) + u'formLayoutAttention[%d]' % number) self.versionNameLabel[number] = QtGui.QLabel( self.formWidget[number]) self.versionNameLabel[number].setObjectName(u'VersionNameLabel') @@ -431,7 +428,10 @@ class BibleUpgradeForm(OpenLPWizard): if not self.checkBox[number].checkState() == QtCore.Qt.Checked: continue # Move bibles to temp dir. - shutil.move(os.path.join(self.path, filename[0]), temp_dir) + if not os.path.exists(os.path.join(temp_dir, filename[0])): + shutil.move(os.path.join(self.path, filename[0]), temp_dir) + else: + delete_file(os.path.join(self.path, filename[0])) return True if self.currentPage() == self.progressPage: return True @@ -684,20 +684,24 @@ class BibleUpgradeForm(OpenLPWizard): 'Upgrading Bible %s of %s: "%s"\nFailed')) % (number + 1, max_bibles, name), self.progressBar.maximum() - self.progressBar.value()) - # Remove old bibles. - shutil.rmtree(temp_dir, True) def postWizard(self): """ Clean up the UI after the import has finished. """ + temp_dir = os.path.join(gettempdir(), u'openlp') successful_import = 0 failed_import = 0 for number, filename in enumerate(self.files): if self.success.has_key(number) and self.success[number]: successful_import += 1 - elif self.checkBox[number].checkState() == QtCore.Qt.Checked: - failed_import += 1 + else: + # Delete upgraded (but not complete, corrupted, ...) bible. + delete_file(os.path.join(self.path, filename[0])) + # Copy not upgraded bible back. + shutil.move(os.path.join(temp_dir, filename[0]), self.path) + if self.checkBox[number].checkState() == QtCore.Qt.Checked: + failed_import += 1 if failed_import > 0: failed_import_text = unicode(translate( 'BiblesPlugin.UpgradeWizardForm', @@ -720,4 +724,6 @@ class BibleUpgradeForm(OpenLPWizard): else: self.progressLabel.setText(translate( 'BiblesPlugin.UpgradeWizardForm', 'Upgrade failed.')) + # Remove old bibles. + shutil.rmtree(temp_dir, True) OpenLPWizard.postWizard(self) diff --git a/openlp/plugins/songs/lib/openlyricsexport.py b/openlp/plugins/songs/lib/openlyricsexport.py index de86e1c05..ec5677ea4 100644 --- a/openlp/plugins/songs/lib/openlyricsexport.py +++ b/openlp/plugins/songs/lib/openlyricsexport.py @@ -73,8 +73,7 @@ class OpenLyricsExport(object): tree = etree.ElementTree(etree.fromstring(xml)) filename = u'%s (%s)' % (song.title, u', '.join([author.display_name for author in song.authors])) - filename = re.sub( - r'[/\\?*|<>\[\]":<>+%]+', u'_', filename).strip(u'_') + filename = clean_filename(filename) # Ensure the filename isn't too long for some filesystems filename = u'%s.xml' % filename[0:250 - len(self.save_path)] # Pass a file object, because lxml does not cope with some special From b72b53889372b8f5c96cbbc08a20a7e3b4bc913b Mon Sep 17 00:00:00 2001 From: Andreas Preikschat Date: Sat, 13 Aug 2011 12:14:20 +0200 Subject: [PATCH 167/184] removed variable; hopefully fixed windows crahes --- .../plugins/bibles/forms/bibleupgradeform.py | 40 ++++++++++--------- 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/openlp/plugins/bibles/forms/bibleupgradeform.py b/openlp/plugins/bibles/forms/bibleupgradeform.py index f34236503..e0ebc46fc 100644 --- a/openlp/plugins/bibles/forms/bibleupgradeform.py +++ b/openlp/plugins/bibles/forms/bibleupgradeform.py @@ -491,16 +491,19 @@ class BibleUpgradeForm(OpenLPWizard): if self.checkBox[number].checkState() == QtCore.Qt.Checked: max_bibles += 1 temp_dir = os.path.join(gettempdir(), u'openlp') + oldBible = None for number, filename in enumerate(self.files): + # Close the previous bible's connection. + if oldBible is not None: + oldBible.close_connection() if self.stop_import_flag: - bible_failed = True + self.success[number] = False break - bible_failed = False - self.success[number] = False + self.success[number] = True if not self.checkBox[number].checkState() == QtCore.Qt.Checked: continue self.progressBar.reset() - oldbible = OldBibleDB(self.mediaItem, path=temp_dir, + oldBible = OldBibleDB(self.mediaItem, path=temp_dir, file=filename[0]) name = filename[1] if name is None: @@ -519,7 +522,7 @@ class BibleUpgradeForm(OpenLPWizard): self.newbibles[number] = BibleDB(self.mediaItem, path=self.path, name=name, file=filename[0]) self.newbibles[number].register(self.plugin.upgrade_wizard) - metadata = oldbible.get_metadata() + metadata = oldBible.get_metadata() webbible = False meta_data = {} for meta in metadata: @@ -580,7 +583,7 @@ class BibleUpgradeForm(OpenLPWizard): self.progressBar.setMaximum(len(books)) for book in books: if self.stop_import_flag: - bible_failed = True + self.success[number] = False break self.incrementProgressBar(unicode(translate( 'BiblesPlugin.UpgradeWizardForm', @@ -595,22 +598,22 @@ class BibleUpgradeForm(OpenLPWizard): meta_data[u'download source'], meta_data[u'download name'])) del self.newbibles[number] - bible_failed = True + self.success[number] = False break book_details = BiblesResourcesDB.get_book_by_id(book_ref_id) db_book = self.newbibles[number].create_book(book, book_ref_id, book_details[u'testament_id']) # Try to import already downloaded verses. - oldbook = oldbible.get_book(book) + oldbook = oldBible.get_book(book) if oldbook: - verses = oldbible.get_verses(oldbook[u'id']) + verses = oldBible.get_verses(oldbook[u'id']) if not verses: log.warn(u'No verses found to import for book ' u'"%s"', book) continue for verse in verses: if self.stop_import_flag: - bible_failed = True + self.success[number] = False break self.newbibles[number].create_verse(db_book.id, int(verse[u'chapter']), @@ -631,11 +634,11 @@ class BibleUpgradeForm(OpenLPWizard): (number + 1, max_bibles, name), self.progressBar.maximum() - self.progressBar.value()) continue - books = oldbible.get_books() + books = oldBible.get_books() self.progressBar.setMaximum(len(books)) for book in books: if self.stop_import_flag: - bible_failed = True + self.success[number] = False break self.incrementProgressBar(unicode(translate( 'BiblesPlugin.UpgradeWizardForm', @@ -649,12 +652,12 @@ class BibleUpgradeForm(OpenLPWizard): log.warn(u'Upgrading books from %s " '\ 'failed - aborted by user' % name) del self.newbibles[number] - bible_failed = True + self.success[number] = False break book_details = BiblesResourcesDB.get_book_by_id(book_ref_id) db_book = self.newbibles[number].create_book(book[u'name'], book_ref_id, book_details[u'testament_id']) - verses = oldbible.get_verses(book[u'id']) + verses = oldBible.get_verses(book[u'id']) if not verses: log.warn(u'No verses found to import for book ' u'"%s"', book[u'name']) @@ -662,28 +665,29 @@ class BibleUpgradeForm(OpenLPWizard): continue for verse in verses: if self.stop_import_flag: - bible_failed = True + self.success[number] = False break self.newbibles[number].create_verse(db_book.id, int(verse[u'chapter']), int(verse[u'verse']), unicode(verse[u'text'])) Receiver.send_message(u'openlp_process_events') self.newbibles[number].session.commit() - if not bible_failed: + if self.success[number]: self.newbibles[number].create_meta(u'Version', name) - oldbible.close_connection() self.incrementProgressBar(unicode(translate( 'BiblesPlugin.UpgradeWizardForm', 'Upgrading Bible %s of %s: "%s"\n' 'Complete')) % (number + 1, max_bibles, name)) - self.success[number] = True else: self.incrementProgressBar(unicode(translate( 'BiblesPlugin.UpgradeWizardForm', 'Upgrading Bible %s of %s: "%s"\nFailed')) % (number + 1, max_bibles, name), self.progressBar.maximum() - self.progressBar.value()) + # Close the last bible's connection. + if oldBible is not None: + oldBible.close_connection() def postWizard(self): """ From 259b57badde3ea7571a8b63f8c483ae9add7c7d2 Mon Sep 17 00:00:00 2001 From: Andreas Preikschat Date: Sat, 13 Aug 2011 12:41:21 +0200 Subject: [PATCH 168/184] added try/except --- openlp/plugins/bibles/forms/bibleupgradeform.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/openlp/plugins/bibles/forms/bibleupgradeform.py b/openlp/plugins/bibles/forms/bibleupgradeform.py index e0ebc46fc..d78124c6c 100644 --- a/openlp/plugins/bibles/forms/bibleupgradeform.py +++ b/openlp/plugins/bibles/forms/bibleupgradeform.py @@ -703,7 +703,12 @@ class BibleUpgradeForm(OpenLPWizard): # Delete upgraded (but not complete, corrupted, ...) bible. delete_file(os.path.join(self.path, filename[0])) # Copy not upgraded bible back. - shutil.move(os.path.join(temp_dir, filename[0]), self.path) + try: + shutil.move(os.path.join(temp_dir, filename[0]), self.path) + except shutil.Error: + # We can ignore any error, because the temp directory is + # will be deleted later. + pass if self.checkBox[number].checkState() == QtCore.Qt.Checked: failed_import += 1 if failed_import > 0: @@ -728,6 +733,6 @@ class BibleUpgradeForm(OpenLPWizard): else: self.progressLabel.setText(translate( 'BiblesPlugin.UpgradeWizardForm', 'Upgrade failed.')) - # Remove old bibles. + # Remove temp directory. shutil.rmtree(temp_dir, True) OpenLPWizard.postWizard(self) From 8a926b01e1da1a27894edfcafa649662381d38e5 Mon Sep 17 00:00:00 2001 From: Andreas Preikschat Date: Sat, 13 Aug 2011 12:49:53 +0200 Subject: [PATCH 169/184] Auto-completer does not work immediately after importing/upgrading a bible (bug #825181) Fixes: https://launchpad.net/bugs/825181 --- openlp/plugins/bibles/lib/mediaitem.py | 1 + 1 file changed, 1 insertion(+) diff --git a/openlp/plugins/bibles/lib/mediaitem.py b/openlp/plugins/bibles/lib/mediaitem.py index 82ee4430c..e47375298 100644 --- a/openlp/plugins/bibles/lib/mediaitem.py +++ b/openlp/plugins/bibles/lib/mediaitem.py @@ -395,6 +395,7 @@ class BibleMediaItem(MediaManagerItem): log.debug(u'Reloading Bibles') self.plugin.manager.reload_bibles() self.loadBibles() + self.updateAutoCompleter() def initialiseAdvancedBible(self, bible): """ From 3f489ddbaf4fb93600582789fdac572fefed1555 Mon Sep 17 00:00:00 2001 From: Andreas Preikschat Date: Sun, 14 Aug 2011 12:56:05 +0200 Subject: [PATCH 170/184] fixed song meta data to include application name --- openlp/plugins/songs/lib/xml.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/openlp/plugins/songs/lib/xml.py b/openlp/plugins/songs/lib/xml.py index 3635fd7e7..193a823d5 100644 --- a/openlp/plugins/songs/lib/xml.py +++ b/openlp/plugins/songs/lib/xml.py @@ -246,8 +246,9 @@ class OpenLyrics(object): # Append the necessary meta data to the song. song_xml.set(u'xmlns', u'http://openlyrics.info/namespace/2009/song') song_xml.set(u'version', OpenLyrics.IMPLEMENTED_VERSION) - song_xml.set(u'createdIn', get_application_version()[u'version']) - song_xml.set(u'modifiedIn', get_application_version()[u'version']) + application_name = u'OpenLP ' + get_application_version()[u'version'] + song_xml.set(u'createdIn', application_name) + song_xml.set(u'modifiedIn', application_name) song_xml.set(u'modifiedDate', datetime.datetime.now().strftime(u'%Y-%m-%dT%H:%M:%S')) properties = etree.SubElement(song_xml, u'properties') From 17e397ffa8dc2269f8217c3fab753ae698dc895f Mon Sep 17 00:00:00 2001 From: Andreas Preikschat Date: Sun, 14 Aug 2011 15:05:39 +0200 Subject: [PATCH 171/184] added spellchecker to service notes dialog (bug #825979); escape texts in various places (bug #825983) Fixes: https://launchpad.net/bugs/825983, https://launchpad.net/bugs/825979 --- openlp/core/lib/spelltextedit.py | 20 +++++++++++--------- openlp/core/ui/printservicedialog.py | 2 +- openlp/core/ui/printserviceform.py | 21 ++++++++++++--------- openlp/core/ui/servicemanager.py | 6 +++++- openlp/core/ui/servicenoteform.py | 4 ++-- 5 files changed, 31 insertions(+), 22 deletions(-) diff --git a/openlp/core/lib/spelltextedit.py b/openlp/core/lib/spelltextedit.py index b0bb61e92..e9b5e64f7 100644 --- a/openlp/core/lib/spelltextedit.py +++ b/openlp/core/lib/spelltextedit.py @@ -48,9 +48,10 @@ class SpellTextEdit(QtGui.QPlainTextEdit): """ Spell checking widget based on QPlanTextEdit. """ - def __init__(self, *args): + def __init__(self, parent=None, formatting_tags_allowed=True): global ENCHANT_AVAILABLE - QtGui.QPlainTextEdit.__init__(self, *args) + QtGui.QPlainTextEdit.__init__(self, parent) + self.formattingTagsAllowed = formatting_tags_allowed # Default dictionary based on the current locale. if ENCHANT_AVAILABLE: try: @@ -110,16 +111,17 @@ class SpellTextEdit(QtGui.QPlainTextEdit): spell_menu.addAction(action) # Only add the spelling suggests to the menu if there are # suggestions. - if len(spell_menu.actions()): + if spell_menu.actions(): popupMenu.insertMenu(popupMenu.actions()[0], spell_menu) tagMenu = QtGui.QMenu(translate('OpenLP.SpellTextEdit', 'Formatting Tags')) - for html in FormattingTags.get_html_tags(): - action = SpellAction(html[u'desc'], tagMenu) - action.correct.connect(self.htmlTag) - tagMenu.addAction(action) - popupMenu.insertSeparator(popupMenu.actions()[0]) - popupMenu.insertMenu(popupMenu.actions()[0], tagMenu) + if self.formattingTagsAllowed: + for html in FormattingTags.get_html_tags(): + action = SpellAction(html[u'desc'], tagMenu) + action.correct.connect(self.htmlTag) + tagMenu.addAction(action) + popupMenu.insertSeparator(popupMenu.actions()[0]) + popupMenu.insertMenu(popupMenu.actions()[0], tagMenu) popupMenu.exec_(event.globalPos()) def setLanguage(self, action): diff --git a/openlp/core/ui/printservicedialog.py b/openlp/core/ui/printservicedialog.py index b0065df99..8287ef02a 100644 --- a/openlp/core/ui/printservicedialog.py +++ b/openlp/core/ui/printservicedialog.py @@ -108,7 +108,7 @@ class Ui_PrintServiceDialog(object): self.footerLabel = QtGui.QLabel(self.optionsWidget) self.footerLabel.setObjectName(u'footerLabel') self.optionsLayout.addWidget(self.footerLabel) - self.footerTextEdit = SpellTextEdit(self.optionsWidget) + self.footerTextEdit = SpellTextEdit(self.optionsWidget, False) self.footerTextEdit.setObjectName(u'footerTextEdit') self.optionsLayout.addWidget(self.footerTextEdit) self.optionsGroupBox = QtGui.QGroupBox() diff --git a/openlp/core/ui/printserviceform.py b/openlp/core/ui/printserviceform.py index f50237619..55fc6eb3c 100644 --- a/openlp/core/ui/printserviceform.py +++ b/openlp/core/ui/printserviceform.py @@ -24,6 +24,7 @@ # with this program; if not, write to the Free Software Foundation, Inc., 59 # # Temple Place, Suite 330, Boston, MA 02111-1307 USA # ############################################################################### +import cgi import datetime import os @@ -183,7 +184,7 @@ class PrintServiceForm(QtGui.QDialog, Ui_PrintServiceDialog): self._addElement(u'style', custom_css, html_data.head, attribute=(u'type', u'text/css')) self._addElement(u'body', parent=html_data) - self._addElement(u'h1', unicode(self.titleLineEdit.text()), + self._addElement(u'h1', cgi.escape(unicode(self.titleLineEdit.text())), html_data.body, classId=u'serviceTitle') for index, item in enumerate(self.serviceManager.serviceItems): self._addPreviewItem(html_data.body, item[u'service_item'], index) @@ -193,8 +194,9 @@ class PrintServiceForm(QtGui.QDialog, Ui_PrintServiceDialog): classId=u'customNotes') self._addElement(u'span', translate('OpenLP.ServiceManager', 'Custom Service Notes: '), div, classId=u'customNotesTitle') - self._addElement(u'span', self.footerTextEdit.toPlainText(), div, - classId=u'customNotesText') + self._addElement(u'span', + cgi.escape(self.footerTextEdit.toPlainText()), + div, classId=u'customNotesText') self.document.setHtml(html.tostring(html_data)) self.previewWidget.updatePreview() @@ -204,8 +206,8 @@ class PrintServiceForm(QtGui.QDialog, Ui_PrintServiceDialog): item_title = self._addElement(u'h2', parent=div, classId=u'itemTitle') self._addElement(u'img', parent=item_title, attribute=(u'src', item.icon)) - self._addElement(u'span', u' ' + item.get_display_title(), - item_title) + self._addElement(u'span', + u' ' + cgi.escape(item.get_display_title()), item_title) if self.slideTextCheckBox.isChecked(): # Add the text of the service item. if item.is_text(): @@ -230,8 +232,9 @@ class PrintServiceForm(QtGui.QDialog, Ui_PrintServiceDialog): foot_text = item.foot_text foot_text = foot_text.partition(u'
')[2] if foot_text: - foot = self._addElement(u'div', foot_text, parent=div, - classId=u'itemFooter') + foot_text = cgi.escape(foot_text.replace(u'
', u'\n')) + self._addElement(u'div', foot_text.replace(u'\n', u'
'), + parent=div, classId=u'itemFooter') # Add service items' notes. if self.notesCheckBox.isChecked(): if item.notes: @@ -239,8 +242,8 @@ class PrintServiceForm(QtGui.QDialog, Ui_PrintServiceDialog): self._addElement(u'span', translate('OpenLP.ServiceManager', 'Notes: '), p, classId=u'itemNotesTitle') - notes = self._addElement(u'span', - item.notes.replace(u'\n', u'
'), p, + self._addElement(u'span', + cgi.escape(unicode(item.notes)).replace(u'\n', u'
'), p, classId=u'itemNotesText') # Add play length of media files. if item.is_media() and self.metaDataCheckBox.isChecked(): diff --git a/openlp/core/ui/servicemanager.py b/openlp/core/ui/servicemanager.py index 0ef45af12..3ab2e9239 100644 --- a/openlp/core/ui/servicemanager.py +++ b/openlp/core/ui/servicemanager.py @@ -24,6 +24,7 @@ # with this program; if not, write to the Free Software Foundation, Inc., 59 # # Temple Place, Suite 330, Boston, MA 02111-1307 USA # ############################################################################### +import cgi import cPickle import logging import os @@ -719,6 +720,9 @@ class ServiceManager(QtGui.QWidget): self.setModified() def onStartTimeForm(self): + """ + Opens a dialog to type in service item notes. + """ item = self.findServiceItem()[0] self.startTimeForm.item = self.serviceItems[item] if self.startTimeForm.exec_(): @@ -957,7 +961,7 @@ class ServiceManager(QtGui.QWidget): if serviceitem.notes: tips.append(u'%s: %s' % (unicode(translate('OpenLP.ServiceManager', 'Notes')), - unicode(serviceitem.notes))) + cgi.escape(unicode(serviceitem.notes)))) if item[u'service_item'] \ .is_capable(ItemCapabilities.AllowsVariableStartTime): tips.append(item[u'service_item'].get_media_time()) diff --git a/openlp/core/ui/servicenoteform.py b/openlp/core/ui/servicenoteform.py index 3bc55e242..ddfcb3381 100644 --- a/openlp/core/ui/servicenoteform.py +++ b/openlp/core/ui/servicenoteform.py @@ -27,7 +27,7 @@ from PyQt4 import QtCore, QtGui -from openlp.core.lib import translate +from openlp.core.lib import translate, SpellTextEdit from openlp.core.lib.ui import create_accept_reject_button_box class ServiceNoteForm(QtGui.QDialog): @@ -52,7 +52,7 @@ class ServiceNoteForm(QtGui.QDialog): self.dialogLayout.setContentsMargins(8, 8, 8, 8) self.dialogLayout.setSpacing(8) self.dialogLayout.setObjectName(u'verticalLayout') - self.textEdit = QtGui.QTextEdit(self) + self.textEdit = SpellTextEdit(self, False) self.textEdit.setObjectName(u'textEdit') self.dialogLayout.addWidget(self.textEdit) self.dialogLayout.addWidget(create_accept_reject_button_box(self)) From 41b3bde91933c780be06f9b0e79bf000b2a6b9ba Mon Sep 17 00:00:00 2001 From: Andreas Preikschat Date: Sun, 14 Aug 2011 15:11:41 +0200 Subject: [PATCH 172/184] changed underscore varialbe to camelCase --- openlp/core/lib/spelltextedit.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openlp/core/lib/spelltextedit.py b/openlp/core/lib/spelltextedit.py index e9b5e64f7..25e4e24ae 100644 --- a/openlp/core/lib/spelltextedit.py +++ b/openlp/core/lib/spelltextedit.py @@ -48,10 +48,10 @@ class SpellTextEdit(QtGui.QPlainTextEdit): """ Spell checking widget based on QPlanTextEdit. """ - def __init__(self, parent=None, formatting_tags_allowed=True): + def __init__(self, parent=None, formattingTagsAllowed=True): global ENCHANT_AVAILABLE QtGui.QPlainTextEdit.__init__(self, parent) - self.formattingTagsAllowed = formatting_tags_allowed + self.formattingTagsAllowed = formattingTagsAllowed # Default dictionary based on the current locale. if ENCHANT_AVAILABLE: try: From 924482ac517f08a994de63c6f697d9fee0208660 Mon Sep 17 00:00:00 2001 From: Andreas Preikschat Date: Sun, 14 Aug 2011 15:49:03 +0200 Subject: [PATCH 173/184] prevent closing an already closed database --- openlp/plugins/bibles/forms/bibleupgradeform.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/openlp/plugins/bibles/forms/bibleupgradeform.py b/openlp/plugins/bibles/forms/bibleupgradeform.py index d78124c6c..b5bc6ed3d 100644 --- a/openlp/plugins/bibles/forms/bibleupgradeform.py +++ b/openlp/plugins/bibles/forms/bibleupgradeform.py @@ -496,6 +496,9 @@ class BibleUpgradeForm(OpenLPWizard): # Close the previous bible's connection. if oldBible is not None: oldBible.close_connection() + # Set to None to make obvious that we have already closed the + # database. + oldBible = None if self.stop_import_flag: self.success[number] = False break From 928467847e62f890f3d0739ef0b1e9b7a2277ad6 Mon Sep 17 00:00:00 2001 From: Andreas Preikschat Date: Sun, 14 Aug 2011 16:35:36 +0200 Subject: [PATCH 174/184] do not call postWizard twice --- openlp/plugins/bibles/forms/bibleupgradeform.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/openlp/plugins/bibles/forms/bibleupgradeform.py b/openlp/plugins/bibles/forms/bibleupgradeform.py index b5bc6ed3d..ca5a16866 100644 --- a/openlp/plugins/bibles/forms/bibleupgradeform.py +++ b/openlp/plugins/bibles/forms/bibleupgradeform.py @@ -113,8 +113,6 @@ class BibleUpgradeForm(OpenLPWizard): self.stop_import_flag = True if not self.currentPage() == self.progressPage: self.done(QtGui.QDialog.Rejected) - else: - self.postWizard() def onCurrentIdChanged(self, pageId): """ From c70ac5e656ea6115e046378789f5427bc1d3db6b Mon Sep 17 00:00:00 2001 From: Andreas Preikschat Date: Mon, 15 Aug 2011 08:31:36 +0200 Subject: [PATCH 175/184] create temp directory name in constructor --- .../plugins/bibles/forms/bibleupgradeform.py | 22 +++++++------------ 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/openlp/plugins/bibles/forms/bibleupgradeform.py b/openlp/plugins/bibles/forms/bibleupgradeform.py index ca5a16866..9f5d62d0f 100644 --- a/openlp/plugins/bibles/forms/bibleupgradeform.py +++ b/openlp/plugins/bibles/forms/bibleupgradeform.py @@ -70,6 +70,7 @@ class BibleUpgradeForm(OpenLPWizard): self.suffix = u'.sqlite' self.settingsSection = u'bibles' self.path = AppLocation.get_section_data_path(self.settingsSection) + self.temp_dir = os.path.join(gettempdir(), u'openlp') self.files = self.manager.old_bible_databases self.success = {} self.newbibles = {} @@ -420,14 +421,14 @@ class BibleUpgradeForm(OpenLPWizard): return False return True elif self.currentPage() == self.selectPage: - temp_dir = os.path.join(gettempdir(), u'openlp') - check_directory_exists(temp_dir) + check_directory_exists(self.temp_dir) for number, filename in enumerate(self.files): if not self.checkBox[number].checkState() == QtCore.Qt.Checked: continue # Move bibles to temp dir. - if not os.path.exists(os.path.join(temp_dir, filename[0])): - shutil.move(os.path.join(self.path, filename[0]), temp_dir) + if not os.path.exists(os.path.join(self.temp_dir, filename[0])): + shutil.move( + os.path.join(self.path, filename[0]), self.temp_dir) else: delete_file(os.path.join(self.path, filename[0])) return True @@ -488,7 +489,6 @@ class BibleUpgradeForm(OpenLPWizard): for number, file in enumerate(self.files): if self.checkBox[number].checkState() == QtCore.Qt.Checked: max_bibles += 1 - temp_dir = os.path.join(gettempdir(), u'openlp') oldBible = None for number, filename in enumerate(self.files): # Close the previous bible's connection. @@ -504,7 +504,7 @@ class BibleUpgradeForm(OpenLPWizard): if not self.checkBox[number].checkState() == QtCore.Qt.Checked: continue self.progressBar.reset() - oldBible = OldBibleDB(self.mediaItem, path=temp_dir, + oldBible = OldBibleDB(self.mediaItem, path=self.temp_dir, file=filename[0]) name = filename[1] if name is None: @@ -694,7 +694,6 @@ class BibleUpgradeForm(OpenLPWizard): """ Clean up the UI after the import has finished. """ - temp_dir = os.path.join(gettempdir(), u'openlp') successful_import = 0 failed_import = 0 for number, filename in enumerate(self.files): @@ -704,12 +703,7 @@ class BibleUpgradeForm(OpenLPWizard): # Delete upgraded (but not complete, corrupted, ...) bible. delete_file(os.path.join(self.path, filename[0])) # Copy not upgraded bible back. - try: - shutil.move(os.path.join(temp_dir, filename[0]), self.path) - except shutil.Error: - # We can ignore any error, because the temp directory is - # will be deleted later. - pass + shutil.move(os.path.join(self.temp_dir, filename[0]), self.path) if self.checkBox[number].checkState() == QtCore.Qt.Checked: failed_import += 1 if failed_import > 0: @@ -735,5 +729,5 @@ class BibleUpgradeForm(OpenLPWizard): self.progressLabel.setText(translate( 'BiblesPlugin.UpgradeWizardForm', 'Upgrade failed.')) # Remove temp directory. - shutil.rmtree(temp_dir, True) + shutil.rmtree(self.temp_dir, True) OpenLPWizard.postWizard(self) From da1db9994dfa9ec28d0773efaefb074c0d5ada53 Mon Sep 17 00:00:00 2001 From: Andreas Preikschat Date: Mon, 15 Aug 2011 09:35:37 +0200 Subject: [PATCH 176/184] removed not needed code --- .../plugins/bibles/forms/bibleupgradeform.py | 108 ------------------ 1 file changed, 108 deletions(-) diff --git a/openlp/plugins/bibles/forms/bibleupgradeform.py b/openlp/plugins/bibles/forms/bibleupgradeform.py index 9f5d62d0f..af046c938 100644 --- a/openlp/plugins/bibles/forms/bibleupgradeform.py +++ b/openlp/plugins/bibles/forms/bibleupgradeform.py @@ -92,20 +92,6 @@ class BibleUpgradeForm(OpenLPWizard): log.debug(u'Stopping import') self.stop_import_flag = True - def onCheckBoxIndexChanged(self, index): - """ - Show/Hide warnings if CheckBox state has changed - """ - for number, filename in enumerate(self.files): - if not self.checkBox[number].checkState() == QtCore.Qt.Checked: - self.verticalWidget[number].hide() - self.formWidget[number].hide() - else: - version_name = unicode(self.versionNameEdit[number].text()) - if self.manager.exists(version_name): - self.verticalWidget[number].show() - self.formWidget[number].show() - def reject(self): """ Stop the wizard on cancel button, close button or ESC key. @@ -242,14 +228,6 @@ class BibleUpgradeForm(OpenLPWizard): Add the content to the scrollArea. """ self.checkBox = {} - self.versionNameEdit = {} - self.versionNameLabel = {} - self.versionInfoLabel = {} - self.versionInfoPixmap = {} - self.verticalWidget = {} - self.horizontalLayout = {} - self.formWidget = {} - self.formLayoutAttention = {} for number, filename in enumerate(self.files): bible = OldBibleDB(self.mediaItem, path=self.path, file=filename[0]) self.checkBox[number] = QtGui.QCheckBox(self.scrollAreaContents) @@ -257,60 +235,6 @@ class BibleUpgradeForm(OpenLPWizard): self.checkBox[number].setText(bible.get_name()) self.checkBox[number].setCheckState(QtCore.Qt.Checked) self.formLayout.addWidget(self.checkBox[number]) - self.verticalWidget[number] = QtGui.QWidget(self.scrollAreaContents) - self.verticalWidget[number].setObjectName( - u'verticalWidget[%d]' % number) - self.horizontalLayout[number] = QtGui.QHBoxLayout( - self.verticalWidget[number]) - self.horizontalLayout[number].setContentsMargins(25, 0, 0, 0) - self.horizontalLayout[number].setObjectName( - u'horizontalLayout[%d]' % number) - self.versionInfoPixmap[number] = QtGui.QLabel( - self.verticalWidget[number]) - self.versionInfoPixmap[number].setObjectName( - u'versionInfoPixmap[%d]' % number) - self.versionInfoPixmap[number].setPixmap(QtGui.QPixmap( - u':/bibles/bibles_upgrade_alert.png')) - self.versionInfoPixmap[number].setAlignment(QtCore.Qt.AlignRight) - self.horizontalLayout[number].addWidget( - self.versionInfoPixmap[number]) - self.versionInfoLabel[number] = QtGui.QLabel( - self.verticalWidget[number]) - self.versionInfoLabel[number].setObjectName( - u'versionInfoLabel[%d]' % number) - sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding, - QtGui.QSizePolicy.Preferred) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth( - self.versionInfoLabel[number].sizePolicy().hasHeightForWidth()) - self.versionInfoLabel[number].setSizePolicy(sizePolicy) - self.horizontalLayout[number].addWidget( - self.versionInfoLabel[number]) - self.formLayout.addWidget(self.verticalWidget[number]) - self.formWidget[number] = QtGui.QWidget(self.scrollAreaContents) - self.formWidget[number].setObjectName(u'formWidget[%d]' % number) - self.formLayoutAttention[number] = QtGui.QFormLayout( - self.formWidget[number]) - self.formLayoutAttention[number].setContentsMargins(25, 0, 0, 5) - self.formLayoutAttention[number].setObjectName( - u'formLayoutAttention[%d]' % number) - self.versionNameLabel[number] = QtGui.QLabel( - self.formWidget[number]) - self.versionNameLabel[number].setObjectName(u'VersionNameLabel') - self.formLayoutAttention[number].setWidget(0, - QtGui.QFormLayout.LabelRole, self.versionNameLabel[number]) - self.versionNameEdit[number] = QtGui.QLineEdit( - self.formWidget[number]) - self.versionNameEdit[number].setObjectName(u'VersionNameEdit') - self.formLayoutAttention[number].setWidget(0, - QtGui.QFormLayout.FieldRole, self.versionNameEdit[number]) - self.versionNameEdit[number].setText(bible.get_name()) - self.formLayout.addWidget(self.formWidget[number]) - # Set up the Signal for the checkbox. - QtCore.QObject.connect(self.checkBox[number], - QtCore.SIGNAL(u'stateChanged(int)'), - self.onCheckBoxIndexChanged) self.spacerItem = QtGui.QSpacerItem(20, 5, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding) self.formLayout.addItem(self.spacerItem) @@ -323,23 +247,6 @@ class BibleUpgradeForm(OpenLPWizard): for number, filename in enumerate(self.files): self.formLayout.removeWidget(self.checkBox[number]) self.checkBox[number].setParent(None) - self.horizontalLayout[number].removeWidget( - self.versionInfoPixmap[number]) - self.versionInfoPixmap[number].setParent(None) - self.horizontalLayout[number].removeWidget( - self.versionInfoLabel[number]) - self.versionInfoLabel[number].setParent(None) - self.formLayout.removeWidget(self.verticalWidget[number]) - self.verticalWidget[number].setParent(None) - self.formLayoutAttention[number].removeWidget( - self.versionNameLabel[number]) - self.versionNameLabel[number].setParent(None) - self.formLayoutAttention[number].removeWidget( - self.versionNameEdit[number]) - self.formLayoutAttention[number].deleteLater() - self.versionNameEdit[number].setParent(None) - self.formLayout.removeWidget(self.formWidget[number]) - self.formWidget[number].setParent(None) self.formLayout.removeItem(self.spacerItem) def retranslateUi(self): @@ -381,12 +288,6 @@ class BibleUpgradeForm(OpenLPWizard): self.selectPage.setSubTitle( translate('BiblesPlugin.UpgradeWizardForm', 'Please select the Bibles to upgrade')) - for number, bible in enumerate(self.files): - self.versionNameLabel[number].setText( - translate('BiblesPlugin.UpgradeWizardForm', 'Version name:')) - self.versionInfoLabel[number].setText( - translate('BiblesPlugin.UpgradeWizardForm', 'This ' - 'Bible still exists. Please change the name or uncheck it.')) self.progressPage.setTitle(translate('BiblesPlugin.UpgradeWizardForm', 'Upgrading')) self.progressPage.setSubTitle( @@ -451,13 +352,6 @@ class BibleUpgradeForm(OpenLPWizard): self.retranslateUi() for number, filename in enumerate(self.files): self.checkBox[number].setCheckState(QtCore.Qt.Checked) - oldname = filename[1] - if self.manager.exists(oldname): - self.verticalWidget[number].show() - self.formWidget[number].show() - else: - self.verticalWidget[number].hide() - self.formWidget[number].hide() self.progressBar.show() self.restart() self.finishButton.setVisible(False) @@ -518,8 +412,6 @@ class BibleUpgradeForm(OpenLPWizard): 'BiblesPlugin.UpgradeWizardForm', 'Upgrading Bible %s of %s: "%s"\nUpgrading ...')) % (number + 1, max_bibles, name)) - if os.path.exists(os.path.join(self.path, filename[0])): - name = unicode(self.versionNameEdit[number].text()) self.newbibles[number] = BibleDB(self.mediaItem, path=self.path, name=name, file=filename[0]) self.newbibles[number].register(self.plugin.upgrade_wizard) From 5607f025f68ce803ef20213bbac0308694c0aba3 Mon Sep 17 00:00:00 2001 From: Andreas Preikschat Date: Mon, 15 Aug 2011 10:53:51 +0200 Subject: [PATCH 177/184] fixed bug #826483 Fixes: https://launchpad.net/bugs/826483 --- .../bibles/resources/bibles_resources.sqlite | Bin 104448 -> 104448 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/openlp/plugins/bibles/resources/bibles_resources.sqlite b/openlp/plugins/bibles/resources/bibles_resources.sqlite index 3235c95629f3d00cde01ef172cf7727e3edd4670..c0fa931d1bb88b6e6c0224feff9cbc5aa61c7312 100644 GIT binary patch delta 34 qcmZqJz}B#VZGtr8 Date: Mon, 15 Aug 2011 10:55:36 +0200 Subject: [PATCH 178/184] fix failure dectection --- .../plugins/bibles/forms/bibleupgradeform.py | 29 +++++++++++-------- openlp/plugins/bibles/forms/languageform.py | 11 ++++--- 2 files changed, 22 insertions(+), 18 deletions(-) diff --git a/openlp/plugins/bibles/forms/bibleupgradeform.py b/openlp/plugins/bibles/forms/bibleupgradeform.py index af046c938..67ef1aba4 100644 --- a/openlp/plugins/bibles/forms/bibleupgradeform.py +++ b/openlp/plugins/bibles/forms/bibleupgradeform.py @@ -394,8 +394,8 @@ class BibleUpgradeForm(OpenLPWizard): if self.stop_import_flag: self.success[number] = False break - self.success[number] = True if not self.checkBox[number].checkState() == QtCore.Qt.Checked: + self.success[number] = False continue self.progressBar.reset() oldBible = OldBibleDB(self.mediaItem, path=self.temp_dir, @@ -407,6 +407,7 @@ class BibleUpgradeForm(OpenLPWizard): 'Upgrading Bible %s of %s: "%s"\nFailed')) % (number + 1, max_bibles, name), self.progressBar.maximum() - self.progressBar.value()) + self.success[number] = False continue self.progressLabel.setText(unicode(translate( 'BiblesPlugin.UpgradeWizardForm', @@ -454,6 +455,7 @@ class BibleUpgradeForm(OpenLPWizard): 'Upgrading Bible %s of %s: "%s"\nFailed')) % (number + 1, max_bibles, name), self.progressBar.maximum() - self.progressBar.value()) + self.success[number] = False continue bible = BiblesResourcesDB.get_webbible( meta_data[u'download name'], @@ -472,6 +474,7 @@ class BibleUpgradeForm(OpenLPWizard): 'Upgrading Bible %s of %s: "%s"\nFailed')) % (number + 1, max_bibles, name), self.progressBar.maximum() - self.progressBar.value()) + self.success[number] = False continue self.progressBar.setMaximum(len(books)) for book in books: @@ -526,6 +529,7 @@ class BibleUpgradeForm(OpenLPWizard): 'Upgrading Bible %s of %s: "%s"\nFailed')) % (number + 1, max_bibles, name), self.progressBar.maximum() - self.progressBar.value()) + self.success[number] = False continue books = oldBible.get_books() self.progressBar.setMaximum(len(books)) @@ -565,20 +569,22 @@ class BibleUpgradeForm(OpenLPWizard): int(verse[u'verse']), unicode(verse[u'text'])) Receiver.send_message(u'openlp_process_events') self.newbibles[number].session.commit() - if self.success[number]: + if self.success.has_key(number) and not self.success[number]: + print u'11111' + self.incrementProgressBar(unicode(translate( + 'BiblesPlugin.UpgradeWizardForm', + 'Upgrading Bible %s of %s: "%s"\nFailed')) % + (number + 1, max_bibles, name), + self.progressBar.maximum() - self.progressBar.value()) + else: + self.success[number] = True self.newbibles[number].create_meta(u'Version', name) self.incrementProgressBar(unicode(translate( 'BiblesPlugin.UpgradeWizardForm', 'Upgrading Bible %s of %s: "%s"\n' 'Complete')) % (number + 1, max_bibles, name)) - else: - self.incrementProgressBar(unicode(translate( - 'BiblesPlugin.UpgradeWizardForm', - 'Upgrading Bible %s of %s: "%s"\nFailed')) % - (number + 1, max_bibles, name), - self.progressBar.maximum() - self.progressBar.value()) - # Close the last bible's connection. + # Close the last bible's connection if possible. if oldBible is not None: oldBible.close_connection() @@ -591,13 +597,12 @@ class BibleUpgradeForm(OpenLPWizard): for number, filename in enumerate(self.files): if self.success.has_key(number) and self.success[number]: successful_import += 1 - else: + elif self.checkBox[number].checkState() == QtCore.Qt.Checked: + failed_import += 1 # Delete upgraded (but not complete, corrupted, ...) bible. delete_file(os.path.join(self.path, filename[0])) # Copy not upgraded bible back. shutil.move(os.path.join(self.temp_dir, filename[0]), self.path) - if self.checkBox[number].checkState() == QtCore.Qt.Checked: - failed_import += 1 if failed_import > 0: failed_import_text = unicode(translate( 'BiblesPlugin.UpgradeWizardForm', diff --git a/openlp/plugins/bibles/forms/languageform.py b/openlp/plugins/bibles/forms/languageform.py index 477c7ee1e..c5069815b 100644 --- a/openlp/plugins/bibles/forms/languageform.py +++ b/openlp/plugins/bibles/forms/languageform.py @@ -44,8 +44,8 @@ class LanguageForm(QDialog, Ui_LanguageDialog): Class to manage a dialog which ask the user for a language. """ log.info(u'LanguageForm loaded') - - def __init__(self, parent = None): + + def __init__(self, parent=None): """ Constructor """ @@ -57,12 +57,11 @@ class LanguageForm(QDialog, Ui_LanguageDialog): if bible_name: self.bibleLabel.setText(unicode(bible_name)) items = BiblesResourcesDB.get_languages() - for item in items: - self.languageComboBox.addItem(item[u'name']) + self.languageComboBox.addItems([item[u'name'] for item in items]) return QDialog.exec_(self) - + def accept(self): - if self.languageComboBox.currentText() == u'': + if not self.languageComboBox.currentText(): critical_error_message_box( message=translate('BiblesPlugin.LanguageForm', 'You need to choose a language.')) From cdec32f706fb321a4b026fabd6f9681da4a46177 Mon Sep 17 00:00:00 2001 From: Andreas Preikschat Date: Mon, 15 Aug 2011 11:05:28 +0200 Subject: [PATCH 179/184] remove print --- openlp/plugins/bibles/forms/bibleupgradeform.py | 1 - 1 file changed, 1 deletion(-) diff --git a/openlp/plugins/bibles/forms/bibleupgradeform.py b/openlp/plugins/bibles/forms/bibleupgradeform.py index 67ef1aba4..373aa64a3 100644 --- a/openlp/plugins/bibles/forms/bibleupgradeform.py +++ b/openlp/plugins/bibles/forms/bibleupgradeform.py @@ -570,7 +570,6 @@ class BibleUpgradeForm(OpenLPWizard): Receiver.send_message(u'openlp_process_events') self.newbibles[number].session.commit() if self.success.has_key(number) and not self.success[number]: - print u'11111' self.incrementProgressBar(unicode(translate( 'BiblesPlugin.UpgradeWizardForm', 'Upgrading Bible %s of %s: "%s"\nFailed')) % From ca5c8d9a0b5359d619ca589119c1ba0a52c8ffb6 Mon Sep 17 00:00:00 2001 From: Raoul Snyman Date: Tue, 16 Aug 2011 23:19:57 +0200 Subject: [PATCH 180/184] Fixed bug #802146: Couldn't import some SongShowPlus files. Rearranged the file menu as well to be in a more logical order, and to look a little nicer. Fixes: https://launchpad.net/bugs/802146 --- openlp/core/ui/mainwindow.py | 8 ++++---- openlp/plugins/songs/lib/songshowplusimport.py | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/openlp/core/ui/mainwindow.py b/openlp/core/ui/mainwindow.py index 510a94dfd..d9c8111bb 100644 --- a/openlp/core/ui/mainwindow.py +++ b/openlp/core/ui/mainwindow.py @@ -305,10 +305,10 @@ class Ui_MainWindow(object): add_actions(self.fileExportMenu, (self.exportThemeItem, self.exportLanguageItem)) add_actions(self.fileMenu, (self.fileNewItem, self.fileOpenItem, - self.fileSaveItem, self.fileSaveAsItem, None, - self.recentFilesMenu.menuAction(), None, self.printServiceOrderItem, - None, self.fileImportMenu.menuAction(), - self.fileExportMenu.menuAction(), self.fileExitItem)) + self.fileSaveItem, self.fileSaveAsItem, + self.recentFilesMenu.menuAction(), None, + self.fileImportMenu.menuAction(), self.fileExportMenu.menuAction(), + None, self.printServiceOrderItem, self.fileExitItem)) add_actions(self.viewModeMenu, (self.modeDefaultItem, self.modeSetupItem, self.modeLiveItem)) add_actions(self.viewMenu, (self.viewModeMenu.menuAction(), diff --git a/openlp/plugins/songs/lib/songshowplusimport.py b/openlp/plugins/songs/lib/songshowplusimport.py index 7f7527c6d..c50df8752 100644 --- a/openlp/plugins/songs/lib/songshowplusimport.py +++ b/openlp/plugins/songs/lib/songshowplusimport.py @@ -102,7 +102,6 @@ class SongShowPlusImport(SongImport): if not isinstance(self.import_source, list): return self.import_wizard.progressBar.setMaximum(len(self.import_source)) - for file in self.import_source: self.sspVerseOrderList = [] otherCount = 0 @@ -111,7 +110,6 @@ class SongShowPlusImport(SongImport): self.import_wizard.incrementProgressBar( WizardStrings.ImportingType % file_name, 0) songData = open(file, 'rb') - while True: blockKey, = struct.unpack("I", songData.read(4)) # The file ends with 4 NUL's @@ -126,8 +124,9 @@ class SongShowPlusImport(SongImport): songData.read(2)) verseName = songData.read(verseNameLength) lengthDescriptorSize, = struct.unpack("B", songData.read(1)) + log.debug(lengthDescriptorSize) # Detect if/how long the length descriptor is - if lengthDescriptorSize == 12: + if lengthDescriptorSize == 12 or lengthDescriptorSize == 20: lengthDescriptor, = struct.unpack("I", songData.read(4)) elif lengthDescriptorSize == 2: lengthDescriptor = 1 @@ -135,6 +134,7 @@ class SongShowPlusImport(SongImport): lengthDescriptor = 0 else: lengthDescriptor, = struct.unpack("B", songData.read(1)) + log.debug(lengthDescriptorSize) data = songData.read(lengthDescriptor) if blockKey == TITLE: self.title = unicode(data, u'cp1252') From 29b67efed63fcacf74958e56b5369d5c988ed38b Mon Sep 17 00:00:00 2001 From: Andreas Preikschat Date: Wed, 17 Aug 2011 12:47:01 +0200 Subject: [PATCH 181/184] close connection to database when the upgrade failed, to prevent errors on windows --- openlp/plugins/bibles/forms/bibleupgradeform.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/openlp/plugins/bibles/forms/bibleupgradeform.py b/openlp/plugins/bibles/forms/bibleupgradeform.py index 373aa64a3..3286c6f88 100644 --- a/openlp/plugins/bibles/forms/bibleupgradeform.py +++ b/openlp/plugins/bibles/forms/bibleupgradeform.py @@ -443,6 +443,7 @@ class BibleUpgradeForm(OpenLPWizard): u'name: "%s" failed' % ( meta_data[u'download source'], meta_data[u'download name'])) + self.newbibles[number].session.close() del self.newbibles[number] critical_error_message_box( translate('BiblesPlugin.UpgradeWizardForm', @@ -468,6 +469,7 @@ class BibleUpgradeForm(OpenLPWizard): language_id = self.newbibles[number].get_language(name) if not language_id: log.warn(u'Upgrading from "%s" failed' % filename[0]) + self.newbibles[number].session.close() del self.newbibles[number] self.incrementProgressBar(unicode(translate( 'BiblesPlugin.UpgradeWizardForm', @@ -493,6 +495,7 @@ class BibleUpgradeForm(OpenLPWizard): u'name: "%s" aborted by user' % ( meta_data[u'download source'], meta_data[u'download name'])) + self.newbibles[number].session.close() del self.newbibles[number] self.success[number] = False break @@ -523,6 +526,7 @@ class BibleUpgradeForm(OpenLPWizard): language_id = self.newbibles[number].get_language(name) if not language_id: log.warn(u'Upgrading books from "%s" failed' % name) + self.newbibles[number].session.close() del self.newbibles[number] self.incrementProgressBar(unicode(translate( 'BiblesPlugin.UpgradeWizardForm', @@ -548,6 +552,7 @@ class BibleUpgradeForm(OpenLPWizard): if not book_ref_id: log.warn(u'Upgrading books from %s " '\ 'failed - aborted by user' % name) + self.newbibles[number].session.close() del self.newbibles[number] self.success[number] = False break @@ -583,6 +588,8 @@ class BibleUpgradeForm(OpenLPWizard): 'Upgrading Bible %s of %s: "%s"\n' 'Complete')) % (number + 1, max_bibles, name)) + if self.newbibles.has_key(number): + self.newbibles[number].session.close() # Close the last bible's connection if possible. if oldBible is not None: oldBible.close_connection() From 7159559eaaec2f445820c38b3200ccff3481cbc1 Mon Sep 17 00:00:00 2001 From: Andreas Preikschat Date: Wed, 17 Aug 2011 13:08:32 +0200 Subject: [PATCH 182/184] removed not needed code (this case should never occur and if it does, the manager instance should delete the file) --- openlp/plugins/bibles/forms/bibleupgradeform.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/openlp/plugins/bibles/forms/bibleupgradeform.py b/openlp/plugins/bibles/forms/bibleupgradeform.py index 3286c6f88..322e3219a 100644 --- a/openlp/plugins/bibles/forms/bibleupgradeform.py +++ b/openlp/plugins/bibles/forms/bibleupgradeform.py @@ -401,14 +401,6 @@ class BibleUpgradeForm(OpenLPWizard): oldBible = OldBibleDB(self.mediaItem, path=self.temp_dir, file=filename[0]) name = filename[1] - if name is None: - self.incrementProgressBar(unicode(translate( - 'BiblesPlugin.UpgradeWizardForm', - 'Upgrading Bible %s of %s: "%s"\nFailed')) % - (number + 1, max_bibles, name), - self.progressBar.maximum() - self.progressBar.value()) - self.success[number] = False - continue self.progressLabel.setText(unicode(translate( 'BiblesPlugin.UpgradeWizardForm', 'Upgrading Bible %s of %s: "%s"\nUpgrading ...')) % From d7ae55f733178904e71ce14c32ffc5ae3261cc20 Mon Sep 17 00:00:00 2001 From: Andreas Preikschat Date: Wed, 17 Aug 2011 14:08:33 +0200 Subject: [PATCH 183/184] improved deletion of corrupted files on windows (bug #824129) Fixes: https://launchpad.net/bugs/824129 --- openlp/plugins/bibles/lib/manager.py | 1 + 1 file changed, 1 insertion(+) diff --git a/openlp/plugins/bibles/lib/manager.py b/openlp/plugins/bibles/lib/manager.py index fcccd7bcf..934aa2d90 100644 --- a/openlp/plugins/bibles/lib/manager.py +++ b/openlp/plugins/bibles/lib/manager.py @@ -151,6 +151,7 @@ class BibleManager(object): name = bible.get_name() # Remove corrupted files. if name is None: + bible.session.close() delete_file(os.path.join(self.path, filename)) continue # Find old database versions. From 9baa1374b6ff62bebd2d06408cab75392fbc9271 Mon Sep 17 00:00:00 2001 From: Andreas Preikschat Date: Wed, 17 Aug 2011 18:16:43 +0200 Subject: [PATCH 184/184] changed instance varaibles to camelCase --- openlp/plugins/alerts/lib/alertstab.py | 132 ++++++++++++------------- 1 file changed, 66 insertions(+), 66 deletions(-) diff --git a/openlp/plugins/alerts/lib/alertstab.py b/openlp/plugins/alerts/lib/alertstab.py index 0a1eb3e75..15577fd0e 100644 --- a/openlp/plugins/alerts/lib/alertstab.py +++ b/openlp/plugins/alerts/lib/alertstab.py @@ -44,85 +44,85 @@ class AlertsTab(SettingsTab): self.fontGroupBox.setObjectName(u'fontGroupBox') self.fontLayout = QtGui.QFormLayout(self.fontGroupBox) self.fontLayout.setObjectName(u'fontLayout') - self.FontLabel = QtGui.QLabel(self.fontGroupBox) - self.FontLabel.setObjectName(u'FontLabel') - self.FontComboBox = QtGui.QFontComboBox(self.fontGroupBox) - self.FontComboBox.setObjectName(u'FontComboBox') - self.fontLayout.addRow(self.FontLabel, self.FontComboBox) - self.FontColorLabel = QtGui.QLabel(self.fontGroupBox) - self.FontColorLabel.setObjectName(u'FontColorLabel') - self.ColorLayout = QtGui.QHBoxLayout() - self.ColorLayout.setObjectName(u'ColorLayout') - self.FontColorButton = QtGui.QPushButton(self.fontGroupBox) - self.FontColorButton.setObjectName(u'FontColorButton') - self.ColorLayout.addWidget(self.FontColorButton) - self.ColorLayout.addSpacing(20) - self.BackgroundColorLabel = QtGui.QLabel(self.fontGroupBox) - self.BackgroundColorLabel.setObjectName(u'BackgroundColorLabel') - self.ColorLayout.addWidget(self.BackgroundColorLabel) - self.BackgroundColorButton = QtGui.QPushButton(self.fontGroupBox) - self.BackgroundColorButton.setObjectName(u'BackgroundColorButton') - self.ColorLayout.addWidget(self.BackgroundColorButton) - self.fontLayout.addRow(self.FontColorLabel, self.ColorLayout) - self.FontSizeLabel = QtGui.QLabel(self.fontGroupBox) - self.FontSizeLabel.setObjectName(u'FontSizeLabel') - self.FontSizeSpinBox = QtGui.QSpinBox(self.fontGroupBox) - self.FontSizeSpinBox.setObjectName(u'FontSizeSpinBox') - self.fontLayout.addRow(self.FontSizeLabel, self.FontSizeSpinBox) - self.TimeoutLabel = QtGui.QLabel(self.fontGroupBox) - self.TimeoutLabel.setObjectName(u'TimeoutLabel') - self.TimeoutSpinBox = QtGui.QSpinBox(self.fontGroupBox) - self.TimeoutSpinBox.setMaximum(180) - self.TimeoutSpinBox.setObjectName(u'TimeoutSpinBox') - self.fontLayout.addRow(self.TimeoutLabel, self.TimeoutSpinBox) + self.fontLabel = QtGui.QLabel(self.fontGroupBox) + self.fontLabel.setObjectName(u'fontLabel') + self.fontComboBox = QtGui.QFontComboBox(self.fontGroupBox) + self.fontComboBox.setObjectName(u'fontComboBox') + self.fontLayout.addRow(self.fontLabel, self.fontComboBox) + self.fontColorLabel = QtGui.QLabel(self.fontGroupBox) + self.fontColorLabel.setObjectName(u'fontColorLabel') + self.colorLayout = QtGui.QHBoxLayout() + self.colorLayout.setObjectName(u'colorLayout') + self.fontColorButton = QtGui.QPushButton(self.fontGroupBox) + self.fontColorButton.setObjectName(u'fontColorButton') + self.colorLayout.addWidget(self.fontColorButton) + self.colorLayout.addSpacing(20) + self.backgroundColorLabel = QtGui.QLabel(self.fontGroupBox) + self.backgroundColorLabel.setObjectName(u'backgroundColorLabel') + self.colorLayout.addWidget(self.backgroundColorLabel) + self.backgroundColorButton = QtGui.QPushButton(self.fontGroupBox) + self.backgroundColorButton.setObjectName(u'backgroundColorButton') + self.colorLayout.addWidget(self.backgroundColorButton) + self.fontLayout.addRow(self.fontColorLabel, self.colorLayout) + self.fontSizeLabel = QtGui.QLabel(self.fontGroupBox) + self.fontSizeLabel.setObjectName(u'fontSizeLabel') + self.fontSizeSpinBox = QtGui.QSpinBox(self.fontGroupBox) + self.fontSizeSpinBox.setObjectName(u'fontSizeSpinBox') + self.fontLayout.addRow(self.fontSizeLabel, self.fontSizeSpinBox) + self.timeoutLabel = QtGui.QLabel(self.fontGroupBox) + self.timeoutLabel.setObjectName(u'timeoutLabel') + self.timeoutSpinBox = QtGui.QSpinBox(self.fontGroupBox) + self.timeoutSpinBox.setMaximum(180) + self.timeoutSpinBox.setObjectName(u'timeoutSpinBox') + self.fontLayout.addRow(self.timeoutLabel, self.timeoutSpinBox) create_valign_combo(self, self.fontGroupBox, self.fontLayout) self.leftLayout.addWidget(self.fontGroupBox) self.leftLayout.addStretch() - self.PreviewGroupBox = QtGui.QGroupBox(self.rightColumn) - self.PreviewGroupBox.setObjectName(u'PreviewGroupBox') - self.PreviewLayout = QtGui.QVBoxLayout(self.PreviewGroupBox) - self.PreviewLayout.setObjectName(u'PreviewLayout') - self.FontPreview = QtGui.QLineEdit(self.PreviewGroupBox) - self.FontPreview.setObjectName(u'FontPreview') - self.PreviewLayout.addWidget(self.FontPreview) - self.rightLayout.addWidget(self.PreviewGroupBox) + self.previewGroupBox = QtGui.QGroupBox(self.rightColumn) + self.previewGroupBox.setObjectName(u'previewGroupBox') + self.previewLayout = QtGui.QVBoxLayout(self.previewGroupBox) + self.previewLayout.setObjectName(u'previewLayout') + self.fontPreview = QtGui.QLineEdit(self.previewGroupBox) + self.fontPreview.setObjectName(u'fontPreview') + self.previewLayout.addWidget(self.fontPreview) + self.rightLayout.addWidget(self.previewGroupBox) self.rightLayout.addStretch() # Signals and slots - QtCore.QObject.connect(self.BackgroundColorButton, + QtCore.QObject.connect(self.backgroundColorButton, QtCore.SIGNAL(u'pressed()'), self.onBackgroundColorButtonClicked) - QtCore.QObject.connect(self.FontColorButton, + QtCore.QObject.connect(self.fontColorButton, QtCore.SIGNAL(u'pressed()'), self.onFontColorButtonClicked) - QtCore.QObject.connect(self.FontComboBox, + QtCore.QObject.connect(self.fontComboBox, QtCore.SIGNAL(u'activated(int)'), self.onFontComboBoxClicked) - QtCore.QObject.connect(self.TimeoutSpinBox, + QtCore.QObject.connect(self.timeoutSpinBox, QtCore.SIGNAL(u'valueChanged(int)'), self.onTimeoutSpinBoxChanged) - QtCore.QObject.connect(self.FontSizeSpinBox, + QtCore.QObject.connect(self.fontSizeSpinBox, QtCore.SIGNAL(u'valueChanged(int)'), self.onFontSizeSpinBoxChanged) def retranslateUi(self): self.fontGroupBox.setTitle( translate('AlertsPlugin.AlertsTab', 'Font')) - self.FontLabel.setText( + self.fontLabel.setText( translate('AlertsPlugin.AlertsTab', 'Font name:')) - self.FontColorLabel.setText( + self.fontColorLabel.setText( translate('AlertsPlugin.AlertsTab', 'Font color:')) - self.BackgroundColorLabel.setText( + self.backgroundColorLabel.setText( translate('AlertsPlugin.AlertsTab', 'Background color:')) - self.FontSizeLabel.setText( + self.fontSizeLabel.setText( translate('AlertsPlugin.AlertsTab', 'Font size:')) - self.FontSizeSpinBox.setSuffix(UiStrings().FontSizePtUnit) - self.TimeoutLabel.setText( + self.fontSizeSpinBox.setSuffix(UiStrings().FontSizePtUnit) + self.timeoutLabel.setText( translate('AlertsPlugin.AlertsTab', 'Alert timeout:')) - self.TimeoutSpinBox.setSuffix(UiStrings().Seconds) - self.PreviewGroupBox.setTitle(UiStrings().Preview) - self.FontPreview.setText(UiStrings().OLPV2) + self.timeoutSpinBox.setSuffix(UiStrings().Seconds) + self.previewGroupBox.setTitle(UiStrings().Preview) + self.fontPreview.setText(UiStrings().OLPV2) def onBackgroundColorButtonClicked(self): new_color = QtGui.QColorDialog.getColor( QtGui.QColor(self.bg_color), self) if new_color.isValid(): self.bg_color = new_color.name() - self.BackgroundColorButton.setStyleSheet( + self.backgroundColorButton.setStyleSheet( u'background-color: %s' % self.bg_color) self.updateDisplay() @@ -134,15 +134,15 @@ class AlertsTab(SettingsTab): QtGui.QColor(self.font_color), self) if new_color.isValid(): self.font_color = new_color.name() - self.FontColorButton.setStyleSheet( + self.fontColorButton.setStyleSheet( u'background-color: %s' % self.font_color) self.updateDisplay() def onTimeoutSpinBoxChanged(self): - self.timeout = self.TimeoutSpinBox.value() + self.timeout = self.timeoutSpinBox.value() def onFontSizeSpinBoxChanged(self): - self.font_size = self.FontSizeSpinBox.value() + self.font_size = self.fontSizeSpinBox.value() self.updateDisplay() def load(self): @@ -160,16 +160,16 @@ class AlertsTab(SettingsTab): self.location = settings.value( u'location', QtCore.QVariant(1)).toInt()[0] settings.endGroup() - self.FontSizeSpinBox.setValue(self.font_size) - self.TimeoutSpinBox.setValue(self.timeout) - self.FontColorButton.setStyleSheet( + self.fontSizeSpinBox.setValue(self.font_size) + self.timeoutSpinBox.setValue(self.timeout) + self.fontColorButton.setStyleSheet( u'background-color: %s' % self.font_color) - self.BackgroundColorButton.setStyleSheet( + self.backgroundColorButton.setStyleSheet( u'background-color: %s' % self.bg_color) self.verticalComboBox.setCurrentIndex(self.location) font = QtGui.QFont() font.setFamily(self.font_face) - self.FontComboBox.setCurrentFont(font) + self.fontComboBox.setCurrentFont(font) self.updateDisplay() def save(self): @@ -178,7 +178,7 @@ class AlertsTab(SettingsTab): settings.setValue(u'background color', QtCore.QVariant(self.bg_color)) settings.setValue(u'font color', QtCore.QVariant(self.font_color)) settings.setValue(u'font size', QtCore.QVariant(self.font_size)) - self.font_face = self.FontComboBox.currentFont().family() + self.font_face = self.fontComboBox.currentFont().family() settings.setValue(u'font face', QtCore.QVariant(self.font_face)) settings.setValue(u'timeout', QtCore.QVariant(self.timeout)) self.location = self.verticalComboBox.currentIndex() @@ -187,10 +187,10 @@ class AlertsTab(SettingsTab): def updateDisplay(self): font = QtGui.QFont() - font.setFamily(self.FontComboBox.currentFont().family()) + font.setFamily(self.fontComboBox.currentFont().family()) font.setBold(True) font.setPointSize(self.font_size) - self.FontPreview.setFont(font) - self.FontPreview.setStyleSheet(u'background-color: %s; color: %s' % + self.fontPreview.setFont(font) + self.fontPreview.setStyleSheet(u'background-color: %s; color: %s' % (self.bg_color, self.font_color))