From 2ad441e88332f6d71bc980cabbfef62d15fd36ad Mon Sep 17 00:00:00 2001 From: Jonathan Corwin Date: Thu, 16 Sep 2010 22:19:51 +0100 Subject: [PATCH 1/6] Speedups --- openlp/core/lib/__init__.py | 2 ++ openlp/core/lib/htmlbuilder.py | 6 ++-- openlp/core/lib/renderer.py | 51 ++++++++++++++++++-------------- openlp/core/lib/rendermanager.py | 1 - openlp/core/lib/serviceitem.py | 6 ++-- openlp/core/ui/maindisplay.py | 2 ++ 6 files changed, 37 insertions(+), 31 deletions(-) diff --git a/openlp/core/lib/__init__.py b/openlp/core/lib/__init__.py index b325f0c6c..ade4bc019 100644 --- a/openlp/core/lib/__init__.py +++ b/openlp/core/lib/__init__.py @@ -220,6 +220,7 @@ def image_to_byte(image): ``image`` The image to converted. """ + log.debug(u'image_to_byte') byte_array = QtCore.QByteArray() # use buffer to store pixmap into byteArray buffie = QtCore.QBuffer(byte_array) @@ -249,6 +250,7 @@ def resize_image(image, width, height, background=QtCore.Qt.black): The background colour defaults to black. """ + log.debug(u'resize_image') preview = QtGui.QImage(image) if not preview.isNull(): # Only resize if different size diff --git a/openlp/core/lib/htmlbuilder.py b/openlp/core/lib/htmlbuilder.py index 906ebb987..0e8aca432 100644 --- a/openlp/core/lib/htmlbuilder.py +++ b/openlp/core/lib/htmlbuilder.py @@ -27,8 +27,6 @@ import logging from PyQt4 import QtWebKit -from openlp.core.lib import image_to_byte - log = logging.getLogger(__name__) HTMLSRC = u""" @@ -301,8 +299,8 @@ def build_html(item, screen, alert, islive): height = screen[u'size'].height() theme = item.themedata webkitvers = webkit_version() - if item.bg_frame: - image = u'data:image/png;base64,%s' % image_to_byte(item.bg_frame) + if item.bg_image_bytes: + image = u'data:image/png;base64,%s' % item.bg_image_bytes else: image = u'' html = HTMLSRC % (build_background_css(item, width, height), diff --git a/openlp/core/lib/renderer.py b/openlp/core/lib/renderer.py index 0cb92ad39..b10b4636f 100644 --- a/openlp/core/lib/renderer.py +++ b/openlp/core/lib/renderer.py @@ -32,7 +32,8 @@ import logging from PyQt4 import QtGui, QtCore, QtWebKit from openlp.core.lib import resize_image, expand_tags, \ - build_lyrics_format_css, build_lyrics_outline_css + build_lyrics_format_css, build_lyrics_outline_css, image_to_byte + log = logging.getLogger(__name__) @@ -54,6 +55,9 @@ class Renderer(object): self.frame = None self.bg_frame = None self.bg_image = None + self.bg_image_bytes = None + self.web = QtWebKit.QWebView() + self.web.setVisible(False) def set_theme(self, theme): """ @@ -66,15 +70,12 @@ class Renderer(object): self._theme = theme self.bg_frame = None self.bg_image = None + self.bg_image_bytes = None self._bg_image_filename = None self.theme_name = theme.theme_name if theme.background_type == u'image': if theme.background_filename: self._bg_image_filename = unicode(theme.background_filename) - if self.frame: - self.bg_image = resize_image(self._bg_image_filename, - self.frame.width(), - self.frame.height()) def set_text_rectangle(self, rect_main, rect_footer): """ @@ -88,7 +89,21 @@ class Renderer(object): """ log.debug(u'set_text_rectangle %s , %s' % (rect_main, rect_footer)) self._rect = rect_main - self._rect_footer = rect_footer + self._rect_footer = rect_footer + self.page_width = self._rect.width() + self.page_height = self._rect.height() + if self._theme.display_shadow: + self.page_width -= int(self._theme.display_shadow_size) + self.page_height -= int(self._theme.display_shadow_size) + self.web.resize(self.page_width, self.page_height) + self.web_frame = self.web.page().mainFrame() + # Adjust width and height to account for shadow. outline done in css + self.page_shell = u'' \ + u'
' % \ + (build_lyrics_format_css(self._theme, self.page_width, + self.page_height), build_lyrics_outline_css(self._theme)) def set_frame_dest(self, frame_width, frame_height): """ @@ -110,15 +125,18 @@ class Renderer(object): self.frame.width(), self.frame.height()) if self._theme.background_type == u'image': self.bg_frame = QtGui.QImage(self.frame.width(), - self.frame.height(), QtGui.QImage.Format_ARGB32_Premultiplied) + self.frame.height(), + QtGui.QImage.Format_ARGB32_Premultiplied) painter = QtGui.QPainter() painter.begin(self.bg_frame) painter.fillRect(self.frame.rect(), QtCore.Qt.black) if self.bg_image: painter.drawImage(0, 0, self.bg_image) painter.end() + self.bg_image_bytes = image_to_byte(self.bg_frame) else: self.bg_frame = None + self.bg_image_bytes = None def format_slide(self, words, line_break): """ @@ -139,29 +157,16 @@ class Renderer(object): lines = verse.split(u'\n') for line in lines: text.append(line) - web = QtWebKit.QWebView() - web.resize(self._rect.width(), self._rect.height()) - web.setVisible(False) - frame = web.page().mainFrame() - # Adjust width and height to account for shadow. outline done in css - width = self._rect.width() - int(self._theme.display_shadow_size) - height = self._rect.height() - int(self._theme.display_shadow_size) - shell = u'' \ - u'
' % \ - (build_lyrics_format_css(self._theme, width, height), - build_lyrics_outline_css(self._theme)) formatted = [] html_text = u'' styled_text = u'' - js_height = 'document.getElementById("main").scrollHeight' for line in text: styled_line = expand_tags(line) + line_end styled_text += styled_line - html = shell + styled_text + u'
' - web.setHtml(html) + html = self.page_shell + styled_text + u'
' + self.web.setHtml(html) # Text too long so go to next page - text_height = int(frame.evaluateJavaScript(js_height).toString()) - if text_height > height: + if self.web_frame.contentsSize().height() > self.page_height: formatted.append(html_text) html_text = u'' styled_text = styled_line diff --git a/openlp/core/lib/rendermanager.py b/openlp/core/lib/rendermanager.py index a6e494b01..e98ab4f01 100644 --- a/openlp/core/lib/rendermanager.py +++ b/openlp/core/lib/rendermanager.py @@ -223,7 +223,6 @@ class RenderManager(object): The words to go on the slides. """ log.debug(u'format slide') - self.build_text_rectangle(self.themedata) return self.renderer.format_slide(words, line_break) def calculate_default(self, screen): diff --git a/openlp/core/lib/serviceitem.py b/openlp/core/lib/serviceitem.py index b0d453af5..e7ec9c2af 100644 --- a/openlp/core/lib/serviceitem.py +++ b/openlp/core/lib/serviceitem.py @@ -97,7 +97,7 @@ class ServiceItem(object): self.themedata = None self.main = None self.footer = None - self.bg_frame = None + self.bg_image_bytes = None def _new_item(self): """ @@ -145,7 +145,7 @@ class ServiceItem(object): """ log.debug(u'Render called') self._display_frames = [] - self.bg_frame = None + self.bg_image_bytes = None line_break = True if self.is_capable(ItemCapabilities.NoLineBreaks): line_break = False @@ -156,7 +156,7 @@ class ServiceItem(object): theme = self.theme self.main, self.footer = \ self.render_manager.set_override_theme(theme, useOverride) - self.bg_frame = self.render_manager.renderer.bg_frame + self.bg_image_bytes = self.render_manager.renderer.bg_image_bytes self.themedata = self.render_manager.renderer._theme for slide in self._raw_frames: before = time.time() diff --git a/openlp/core/ui/maindisplay.py b/openlp/core/ui/maindisplay.py index a2b9dd81a..646bdebd5 100644 --- a/openlp/core/ui/maindisplay.py +++ b/openlp/core/ui/maindisplay.py @@ -341,7 +341,9 @@ class MainDisplay(DisplayWidget): self.serviceItem = serviceItem html = build_html(self.serviceItem, self.screen, self.parent.alertTab, self.isLive) + log.debug(u'buildHtml - pre setHtml') self.webView.setHtml(html) + log.debug(u'buildHtml - post setHtml') if serviceItem.foot_text and serviceItem.foot_text: self.footer(serviceItem.foot_text) # if was hidden keep it hidden From 2837c36553562787165161526418fe3a30fd7c24 Mon Sep 17 00:00:00 2001 From: Jonathan Corwin Date: Fri, 17 Sep 2010 21:32:00 +0100 Subject: [PATCH 2/6] tweaks --- openlp/core/lib/renderer.py | 4 ++-- openlp/core/ui/maindisplay.py | 5 +++-- openlp/core/ui/slidecontroller.py | 12 ++++++------ 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/openlp/core/lib/renderer.py b/openlp/core/lib/renderer.py index b10b4636f..194172a9e 100644 --- a/openlp/core/lib/renderer.py +++ b/openlp/core/lib/renderer.py @@ -56,8 +56,6 @@ class Renderer(object): self.bg_frame = None self.bg_image = None self.bg_image_bytes = None - self.web = QtWebKit.QWebView() - self.web.setVisible(False) def set_theme(self, theme): """ @@ -95,6 +93,8 @@ class Renderer(object): if self._theme.display_shadow: self.page_width -= int(self._theme.display_shadow_size) self.page_height -= int(self._theme.display_shadow_size) + self.web = QtWebKit.QWebView() + self.web.setVisible(False) self.web.resize(self.page_width, self.page_height) self.web_frame = self.web.page().mainFrame() # Adjust width and height to account for shadow. outline done in css diff --git a/openlp/core/ui/maindisplay.py b/openlp/core/ui/maindisplay.py index 646bdebd5..fe8438895 100644 --- a/openlp/core/ui/maindisplay.py +++ b/openlp/core/ui/maindisplay.py @@ -306,6 +306,7 @@ class MainDisplay(DisplayWidget): # We must have a service item to preview if not hasattr(self, u'serviceItem'): return + Receiver.send_message(u'openlp_process_events') if self.isLive: # Wait for the fade to finish before geting the preview. # Important otherwise preview will have incorrect text if at all ! @@ -318,6 +319,8 @@ class MainDisplay(DisplayWidget): # Important otherwise first preview will miss the background ! while not self.loaded: Receiver.send_message(u'openlp_process_events') + if self.isLive: + self.setVisible(True) preview = QtGui.QImage(self.screen[u'size'].width(), self.screen[u'size'].height(), QtGui.QImage.Format_ARGB32_Premultiplied) @@ -326,8 +329,6 @@ class MainDisplay(DisplayWidget): self.frame.render(painter) painter.end() # Make display show up if in single screen mode - if self.isLive: - self.setVisible(True) return preview def buildHtml(self, serviceItem): diff --git a/openlp/core/ui/slidecontroller.py b/openlp/core/ui/slidecontroller.py index 9f9b4d433..dcaa726df 100644 --- a/openlp/core/ui/slidecontroller.py +++ b/openlp/core/ui/slidecontroller.py @@ -636,9 +636,9 @@ class SlideController(QtGui.QWidget): """ if not self.serviceItem: return - Receiver.send_message(u'%s_first' % self.serviceItem.name.lower(), - [self.serviceItem, self.isLive]) if self.serviceItem.is_command(): + Receiver.send_message(u'%s_first' % self.serviceItem.name.lower(), + [self.serviceItem, self.isLive]) self.updatePreview() else: self.PreviewListWidget.selectRow(0) @@ -651,9 +651,9 @@ class SlideController(QtGui.QWidget): index = int(message[0]) if not self.serviceItem: return - Receiver.send_message(u'%s_slide' % self.serviceItem.name.lower(), - [self.serviceItem, self.isLive, index]) if self.serviceItem.is_command(): + Receiver.send_message(u'%s_slide' % self.serviceItem.name.lower(), + [self.serviceItem, self.isLive, index]) self.updatePreview() else: self.PreviewListWidget.selectRow(index) @@ -768,9 +768,9 @@ class SlideController(QtGui.QWidget): row = self.PreviewListWidget.currentRow() self.selectedRow = 0 if row > -1 and row < self.PreviewListWidget.rowCount(): - Receiver.send_message(u'%s_slide' % self.serviceItem.name.lower(), - [self.serviceItem, self.isLive, row]) if self.serviceItem.is_command() and self.isLive: + Receiver.send_message(u'%s_slide' % self.serviceItem.name.lower(), + [self.serviceItem, self.isLive, row]) self.updatePreview() else: frame, raw_html = self.serviceItem.get_rendered_frame(row) From ad51cb80409605c05014a9f2345ac539974b85b8 Mon Sep 17 00:00:00 2001 From: Jonathan Corwin Date: Sun, 19 Sep 2010 21:59:00 +0100 Subject: [PATCH 3/6] Remove top/left border on maindisplay. QGraphicsWebView only appeared in Qt4.6 --- openlp/core/lib/htmlbuilder.py | 6 +++--- openlp/core/ui/maindisplay.py | 19 +++++++++++++------ 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/openlp/core/lib/htmlbuilder.py b/openlp/core/lib/htmlbuilder.py index 0e8aca432..ef8fb286a 100644 --- a/openlp/core/lib/htmlbuilder.py +++ b/openlp/core/lib/htmlbuilder.py @@ -272,7 +272,7 @@ body { - + %s @@ -300,9 +300,9 @@ def build_html(item, screen, alert, islive): theme = item.themedata webkitvers = webkit_version() if item.bg_image_bytes: - image = u'data:image/png;base64,%s' % item.bg_image_bytes + image = u'src="data:image/png;base64,%s"' % item.bg_image_bytes else: - image = u'' + image = u'style="display:none;"' html = HTMLSRC % (build_background_css(item, width, height), width, height, build_alert_css(alert, width), diff --git a/openlp/core/ui/maindisplay.py b/openlp/core/ui/maindisplay.py index fe8438895..7e4a31b83 100644 --- a/openlp/core/ui/maindisplay.py +++ b/openlp/core/ui/maindisplay.py @@ -99,6 +99,7 @@ class MainDisplay(DisplayWidget): self.alertTab = None self.hide_mode = None self.setWindowTitle(u'OpenLP Display') + self.setStyleSheet(u'border: 0px; margin: 0px; padding: 0px;') self.setWindowFlags(QtCore.Qt.FramelessWindowHint | QtCore.Qt.WindowStaysOnTopHint) if self.isLive: @@ -116,12 +117,18 @@ class MainDisplay(DisplayWidget): self.screen = self.screens.current self.setVisible(False) self.setGeometry(self.screen[u'size']) - self.scene = QtGui.QGraphicsScene() - self.setScene(self.scene) - self.webView = QtWebKit.QGraphicsWebView() - self.scene.addItem(self.webView) - self.webView.resize(self.screen[u'size'].width(), - self.screen[u'size'].height()) + try: + self.webView = QtWebKit.QGraphicsWebView() + self.scene = QtGui.QGraphicsScene(self) + self.setScene(self.scene) + self.scene.addItem(self.webView) + self.webView.setGeometry(QtCore.QRectF(0, 0, + self.screen[u'size'].width(), self.screen[u'size'].height())) + except AttributeError: + # QGraphicsWebView a recent addition, so fall back to QWebView + self.webView = QtWebKit.QWebView(self) + self.webView.setGeometry(0, 0, + self.screen[u'size'].width(), self.screen[u'size'].height()) self.page = self.webView.page() self.frame = self.page.mainFrame() QtCore.QObject.connect(self.webView, From d4a1b7f796008a5c32b8ce3d2a399f87c070785f Mon Sep 17 00:00:00 2001 From: "Jeffrey S. Smith" Date: Mon, 20 Sep 2010 13:22:57 -0500 Subject: [PATCH 4/6] Added a song importer for EasyWorship --- openlp/plugins/songs/forms/songimportform.py | 26 ++ .../plugins/songs/forms/songimportwizard.py | 33 ++- openlp/plugins/songs/lib/ewimport.py | 249 ++++++++++++++++++ openlp/plugins/songs/lib/importer.py | 9 +- 4 files changed, 314 insertions(+), 3 deletions(-) create mode 100644 openlp/plugins/songs/lib/ewimport.py diff --git a/openlp/plugins/songs/forms/songimportform.py b/openlp/plugins/songs/forms/songimportform.py index 29cc42ec5..7680a8e96 100644 --- a/openlp/plugins/songs/forms/songimportform.py +++ b/openlp/plugins/songs/forms/songimportform.py @@ -109,6 +109,9 @@ class ImportWizardForm(QtGui.QWizard, Ui_SongImportWizard): QtCore.QObject.connect(self.genericRemoveButton, QtCore.SIGNAL(u'clicked()'), self.onGenericRemoveButtonClicked) + QtCore.QObject.connect(self.ewBrowseButton, + QtCore.SIGNAL(u'clicked()'), + self.onEWBrowseButtonClicked) QtCore.QObject.connect(self.cancelButton, QtCore.SIGNAL(u'clicked(bool)'), self.onCancelButtonClicked) @@ -214,6 +217,16 @@ class ImportWizardForm(QtGui.QWizard, Ui_SongImportWizard): 'presentation file to import from.')) self.genericAddButton.setFocus() return False + elif source_format == SongFormat.EasyWorship: + if self.ewFilenameEdit.text().isEmpty(): + QtGui.QMessageBox.critical(self, + translate('SongsPlugin.ImportWizardForm', + 'No EasyWorship Song Database Selected'), + translate('SongsPlugin.ImportWizardForm', + 'You need to select an EasyWorship song database ' + 'file to import from.')) + self.ewBrowseButton.setFocus() + return False return True elif self.currentId() == 2: # Progress page @@ -322,6 +335,13 @@ class ImportWizardForm(QtGui.QWizard, Ui_SongImportWizard): def onGenericRemoveButtonClicked(self): self.removeSelectedItems(self.genericFileListWidget) + def onEWBrowseButtonClicked(self): + self.getFileName( + translate('SongsPlugin.ImportWizardForm', + 'Select EasyWorship Database File'), + self.ewFilenameEdit + ) + def onCancelButtonClicked(self, checked): """ Stop the import on pressing the cancel button. @@ -350,6 +370,7 @@ class ImportWizardForm(QtGui.QWizard, Ui_SongImportWizard): self.ccliFileListWidget.clear() self.songsOfFellowshipFileListWidget.clear() self.genericFileListWidget.clear() + self.ewFilenameEdit.setText(u'') #self.csvFilenameEdit.setText(u'') def incrementProgressBar(self, status_text, increment=1): @@ -420,6 +441,11 @@ class ImportWizardForm(QtGui.QWizard, Ui_SongImportWizard): importer = self.plugin.importSongs(SongFormat.Generic, filenames=self.getListOfFiles(self.genericFileListWidget) ) + elif source_format == SongFormat.EasyWorship: + # Import an OpenLP 2.0 database + importer = self.plugin.importSongs(SongFormat.EasyWorship, + filename=unicode(self.ewFilenameEdit.text()) + ) success = importer.do_import() if success: # reload songs diff --git a/openlp/plugins/songs/forms/songimportwizard.py b/openlp/plugins/songs/forms/songimportwizard.py index 37ee10612..0fb36cfe7 100644 --- a/openlp/plugins/songs/forms/songimportwizard.py +++ b/openlp/plugins/songs/forms/songimportwizard.py @@ -96,6 +96,7 @@ class Ui_SongImportWizard(object): self.formatComboBox.addItem(u'') self.formatComboBox.addItem(u'') self.formatComboBox.addItem(u'') + self.formatComboBox.addItem(u'') # self.formatComboBox.addItem(u'') self.formatLayout.addWidget(self.formatComboBox) self.formatSpacer = QtGui.QSpacerItem(40, 20, @@ -413,6 +414,30 @@ class Ui_SongImportWizard(object): self.genericImportLayout.addLayout(self.genericButtonLayout) self.genericLayout.addWidget(self.genericImportWidget) self.formatStackedWidget.addWidget(self.genericPage) + # EasyWorship + self.ewPage = QtGui.QWidget() + self.ewPage.setObjectName(u'ewPage') + self.ewLayout = QtGui.QFormLayout(self.ewPage) + self.ewLayout.setMargin(0) + self.ewLayout.setSpacing(8) + self.ewLayout.setObjectName(u'ewLayout') + self.ewFilenameLabel = QtGui.QLabel(self.ewPage) + self.ewFilenameLabel.setObjectName(u'ewFilenameLabel') + self.ewLayout.setWidget(0, QtGui.QFormLayout.LabelRole, + self.ewFilenameLabel) + self.ewFileLayout = QtGui.QHBoxLayout() + self.ewFileLayout.setSpacing(8) + self.ewFileLayout.setObjectName(u'ewFileLayout') + self.ewFilenameEdit = QtGui.QLineEdit(self.ewPage) + self.ewFilenameEdit.setObjectName(u'ewFilenameEdit') + self.ewFileLayout.addWidget(self.ewFilenameEdit) + self.ewBrowseButton = QtGui.QToolButton(self.ewPage) + self.ewBrowseButton.setIcon(openIcon) + self.ewBrowseButton.setObjectName(u'ewBrowseButton') + self.ewFileLayout.addWidget(self.ewBrowseButton) + self.ewLayout.setLayout(0, QtGui.QFormLayout.FieldRole, + self.ewFileLayout) + self.formatStackedWidget.addWidget(self.ewPage) # Commented out for future use. # self.csvPage = QtGui.QWidget() # self.csvPage.setObjectName(u'CSVPage') @@ -497,7 +522,9 @@ class Ui_SongImportWizard(object): self.formatComboBox.setItemText(7, translate('SongsPlugin.ImportWizardForm', 'Generic Document/Presentation')) -# self.formatComboBox.setItemText(8, + self.formatComboBox.setItemText(8, + translate('SongsPlugin.ImportWizardForm', 'EasyWorship')) +# self.formatComboBox.setItemText(9, # translate('SongsPlugin.ImportWizardForm', 'CSV')) self.openLP2FilenameLabel.setText( translate('SongsPlugin.ImportWizardForm', 'Filename:')) @@ -549,6 +576,10 @@ class Ui_SongImportWizard(object): translate('SongsPlugin.ImportWizardForm', 'The generic document/' 'presentation importer has been disabled because OpenLP cannot ' 'find OpenOffice.org on your computer.')) + self.ewFilenameLabel.setText( + translate('SongsPlugin.ImportWizardForm', 'Filename:')) + self.ewBrowseButton.setText( + translate('SongsPlugin.ImportWizardForm', 'Browse...')) # self.csvFilenameLabel.setText( # translate('SongsPlugin.ImportWizardForm', 'Filename:')) # self.csvBrowseButton.setText( diff --git a/openlp/plugins/songs/lib/ewimport.py b/openlp/plugins/songs/lib/ewimport.py new file mode 100644 index 000000000..e521536b9 --- /dev/null +++ b/openlp/plugins/songs/lib/ewimport.py @@ -0,0 +1,249 @@ +# -*- coding: utf-8 -*- +# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4 + +""" +The :mod:`ewimport` module provides the functionality for importing +EasyWorship song databases into the current installation database. +""" + +import sys +import os +import struct + +from songimport import SongImport + +def strip_rtf(blob): + depth = 0 + control = False + clear_text = [] + control_word = [] + for c in blob: + if control: + # for delimiters, set control to False + if c == '{': + depth += 1 + control = False + elif c == '}': + depth -= 1 + control = False + elif c == '\\': + 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: + control_word_str = ''.join(control_word) + if control_word_str == 'par': + clear_text.append(u'\n') + # Really should take RTF character set into account + # but for now assume ANSI (Windows-1252) and call it good + if control_word_str[0] == '\'': + s = chr(int(control_word_str[1:3], 16)) + clear_text.append(s.decode(u'windows-1252')) + del control_word[:] + + if c == '\\': + 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): + self.import_source = kwargs[u'filename'] + SongImport.__init__(self, manager) + + 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 False + if not os.path.isfile(import_source_mb): + return False + db_size = os.path.getsize(self.import_source) + if db_size < 0x800: + return False + 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, next_block, num_fields \ + = struct.unpack(' 4: + db_file.close() + self.memo_file.close() + return False + + # There does not appear to be a _reliable_ way of getting the number + # of songs/records, so let's use file blocks for measuring progress. + total_blocks = (db_size - header_size) / (block_size * 1024) + self.import_wizard.importProgressBar.setMaximum(total_blocks) + + # Read the field description information + db_file.seek(120) + field_info = db_file.read(num_fields * 2) + db_file.seek(4 + (num_fields * 4) + 261, os.SEEK_CUR) + field_names = db_file.read(header_size - db_file.tell()).split('\0', + num_fields) + field_names.pop() + field_descs = [] + for i,field_name in enumerate(field_names): + field_type, field_size = struct.unpack_from('BB', field_info, i * 2) + field_descs.append(FieldDescEntry(field_name, field_type, + field_size)) + self.set_record_struct(field_descs) + + # Pick out the field description indexes we will need + success = True + try: + fi_title = self.find_field(u'Title') + fi_author = self.find_field(u'Author') + fi_copy = self.find_field(u'Copyright') + fi_admin = self.find_field(u'Administrator') + fi_words = self.find_field(u'Words') + fi_ccli = self.find_field(u'Song Number') + except IndexError: + # This is the wrong table + success = False + + while next_block != 0 and success: + db_file.seek(header_size + ((next_block - 1) * 1024 * block_size)) + next_block, rec_count = 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] + + # Check for 'blank' entries + if isinstance(field, str): + if len(field.rstrip('\0')) == 0: + return u'' + elif field == 0: + return 0 + + if field_desc.type == 1: # string + return field.rstrip('\0').decode(u'windows-1252') + 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: + sub_block, 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 * 256) + + (sub_block_start * 16)) + else: + return u''; + + return self.memo_file.read(blob_size) + else: + return 0 diff --git a/openlp/plugins/songs/lib/importer.py b/openlp/plugins/songs/lib/importer.py index 2d00c6523..d8028db24 100644 --- a/openlp/plugins/songs/lib/importer.py +++ b/openlp/plugins/songs/lib/importer.py @@ -28,6 +28,7 @@ from opensongimport import OpenSongImport from olpimport import OpenLPSongImport from wowimport import WowImport from cclifileimport import CCLIFileImport +from ewimport import EasyWorshipSongImport # Imports that might fail try: from olp1import import OpenLP1SongImport @@ -61,7 +62,8 @@ class SongFormat(object): CCLI = 5 SongsOfFellowship = 6 Generic = 7 - CSV = 8 + #CSV = 8 + EasyWorship = 8 @staticmethod def get_class(format): @@ -85,6 +87,8 @@ class SongFormat(object): return OooImport elif format == SongFormat.CCLI: return CCLIFileImport + elif format == SongFormat.EasyWorship: + return EasyWorshipSongImport # else: return None @@ -101,7 +105,8 @@ class SongFormat(object): SongFormat.WordsOfWorship, SongFormat.CCLI, SongFormat.SongsOfFellowship, - SongFormat.Generic + SongFormat.Generic, + SongFormat.EasyWorship ] @staticmethod From 49e6a4589ce4b3657de0c1b63b076ceb61d29952 Mon Sep 17 00:00:00 2001 From: "Jeffrey S. Smith" Date: Mon, 20 Sep 2010 15:58:55 -0500 Subject: [PATCH 5/6] Get rid of extra blank lines and handle \{ \} \ in RTF --- openlp/plugins/songs/lib/ewimport.py | 100 ++++++++++++++------------- 1 file changed, 53 insertions(+), 47 deletions(-) diff --git a/openlp/plugins/songs/lib/ewimport.py b/openlp/plugins/songs/lib/ewimport.py index e521536b9..16db36b20 100644 --- a/openlp/plugins/songs/lib/ewimport.py +++ b/openlp/plugins/songs/lib/ewimport.py @@ -21,12 +21,15 @@ def strip_rtf(blob): if control: # for delimiters, set control to False if c == '{': - depth += 1 + if len(control_word) > 0: + depth += 1 control = False elif c == '}': - depth -= 1 + if len(control_word) > 0: + depth -= 1 control = False elif c == '\\': + new_control = (len(control_word) > 0) control = False elif c.isspace(): control = False @@ -34,31 +37,32 @@ def strip_rtf(blob): control_word.append(c) if len(control_word) == 3 and control_word[0] == '\'': control = False - if not control: - control_word_str = ''.join(control_word) - if control_word_str == 'par': - clear_text.append(u'\n') - # Really should take RTF character set into account - # but for now assume ANSI (Windows-1252) and call it good - if control_word_str[0] == '\'': - s = chr(int(control_word_str[1:3], 16)) - clear_text.append(s.decode(u'windows-1252')) - del control_word[:] - - if c == '\\': + 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'\n') + elif control_str[0] == '\'': + # Really should take RTF character set into account but + # for now assume ANSI (Windows-1252) and call it good + s = chr(int(control_str[1:3], 16)) + clear_text.append(s.decode(u'windows-1252')) + 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: @@ -92,20 +96,17 @@ class EasyWorshipSongImport(SongImport): return False 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, next_block, num_fields \ - = struct.unpack(' 4: db_file.close() self.memo_file.close() return False - # There does not appear to be a _reliable_ way of getting the number # of songs/records, so let's use file blocks for measuring progress. total_blocks = (db_size - header_size) / (block_size * 1024) self.import_wizard.importProgressBar.setMaximum(total_blocks) - # Read the field description information db_file.seek(120) field_info = db_file.read(num_fields * 2) @@ -119,7 +120,6 @@ class EasyWorshipSongImport(SongImport): field_descs.append(FieldDescEntry(field_name, field_type, field_size)) self.set_record_struct(field_descs) - # Pick out the field description indexes we will need success = True try: @@ -132,18 +132,19 @@ class EasyWorshipSongImport(SongImport): except IndexError: # This is the wrong table success = False - - while next_block != 0 and success: - db_file.seek(header_size + ((next_block - 1) * 1024 * block_size)) - next_block, rec_count = struct.unpack(''] for field_desc in field_descs: - if field_desc.type == 1: # string + if field_desc.type == 1: + # string fsl.append('%ds' % field_desc.size) - elif field_desc.type == 3: # 16-bit int + elif field_desc.type == 3: + # 16-bit int fsl.append('H') - elif field_desc.type == 4: # 32-bit int + elif field_desc.type == 4: + # 32-bit int fsl.append('I') - elif field_desc.type == 9: # Logical + elif field_desc.type == 9: + # Logical fsl.append('B') - elif field_desc.type == 0x0c: # Memo + elif field_desc.type == 0x0c: + # Memo fsl.append('%ds' % field_desc.size) - elif field_desc.type == 0x0d: # Blob + elif field_desc.type == 0x0d: + # Blob fsl.append('%ds' % field_desc.size) - elif field_desc.type == 0x15: # Timestamp + elif field_desc.type == 0x15: + # Timestamp fsl.append('Q') else: fsl.append('%ds' % field_desc.size) @@ -211,23 +214,27 @@ class EasyWorshipSongImport(SongImport): def get_field(self, field_desc_index): field = self.fields[field_desc_index] field_desc = self.field_descs[field_desc_index] - # Check for 'blank' entries if isinstance(field, str): if len(field.rstrip('\0')) == 0: return u'' elif field == 0: return 0 - - if field_desc.type == 1: # string + # Format the field depending on the field type + if field_desc.type == 1: + # string return field.rstrip('\0').decode(u'windows-1252') - elif field_desc.type == 3: # 16-bit int + elif field_desc.type == 3: + # 16-bit int return field ^ 0x8000 - elif field_desc.type == 4: # 32-bit int + elif field_desc.type == 4: + # 32-bit int return field ^ 0x80000000 - elif field_desc.type == 9: # Logical + elif field_desc.type == 9: + # Logical return (field ^ 0x80 == 1) elif field_desc.type == 0x0c or field_desc.type == 0x0d: + # Memo or Blob sub_block, block_start, blob_size = \ struct.unpack_from(' Date: Tue, 21 Sep 2010 20:12:46 +0200 Subject: [PATCH 6/6] Fix bug #644106 Fix a related bug in the song importer. --- openlp/plugins/bibles/forms/importwizardform.py | 3 +++ openlp/plugins/songs/forms/songimportform.py | 2 ++ 2 files changed, 5 insertions(+) diff --git a/openlp/plugins/bibles/forms/importwizardform.py b/openlp/plugins/bibles/forms/importwizardform.py index 84f0f41ee..43df48d5b 100644 --- a/openlp/plugins/bibles/forms/importwizardform.py +++ b/openlp/plugins/bibles/forms/importwizardform.py @@ -290,6 +290,9 @@ class ImportWizardForm(QtGui.QWizard, Ui_BibleImportWizard): def setDefaults(self): settings = QtCore.QSettings() settings.beginGroup(self.bibleplugin.settingsSection) + self.restart() + self.finishButton.setVisible(False) + self.cancelButton.setVisible(True) self.setField(u'source_format', QtCore.QVariant(0)) self.setField(u'osis_location', QtCore.QVariant('')) self.setField(u'csv_booksfile', QtCore.QVariant('')) diff --git a/openlp/plugins/songs/forms/songimportform.py b/openlp/plugins/songs/forms/songimportform.py index 7680a8e96..c62fa058e 100644 --- a/openlp/plugins/songs/forms/songimportform.py +++ b/openlp/plugins/songs/forms/songimportform.py @@ -361,6 +361,8 @@ class ImportWizardForm(QtGui.QWizard, Ui_SongImportWizard): def setDefaults(self): self.restart() + self.finishButton.setVisible(False) + self.cancelButton.setVisible(True) self.formatComboBox.setCurrentIndex(0) self.openLP2FilenameEdit.setText(u'') self.openLP1FilenameEdit.setText(u'')