← Back to team overview

openlp-core team mailing list archive

[Merge] lp:~mahfiaz/openlp/easislidesimport into lp:openlp

 

mahfiaz has proposed merging lp:~mahfiaz/openlp/easislidesimport into lp:openlp.

Requested reviews:
  Jon Tibble (meths)

For more details, see:
https://code.launchpad.net/~mahfiaz/openlp/easislidesimport/+merge/46548

Easislides import plugin. It's probably violating OpenLP high coding standard a little less now.
-- 
https://code.launchpad.net/~mahfiaz/openlp/easislidesimport/+merge/46548
Your team OpenLP Core is subscribed to branch lp:openlp.
=== modified file 'openlp/plugins/songs/forms/songimportform.py'
--- openlp/plugins/songs/forms/songimportform.py	2011-01-15 19:24:50 +0000
+++ openlp/plugins/songs/forms/songimportform.py	2011-01-17 23:29:49 +0000
@@ -128,6 +128,9 @@
         QtCore.QObject.connect(self.genericRemoveButton,
             QtCore.SIGNAL(u'clicked()'),
             self.onGenericRemoveButtonClicked)
+        QtCore.QObject.connect(self.easiSlidesBrowseButton,
+            QtCore.SIGNAL(u'clicked()'),
+            self.onEasiSlidesBrowseButtonClicked)
         QtCore.QObject.connect(self.ewBrowseButton,
             QtCore.SIGNAL(u'clicked()'),
             self.onEWBrowseButtonClicked)
@@ -177,6 +180,8 @@
         self.addMultiFileSelectItem(u'songsOfFellowship', None, True)
         # Generic Document/Presentation import
         self.addMultiFileSelectItem(u'generic', None, True)
+        # EasySlides
+        self.addSingleFileSelectItem(u'easiSlides')
         # EasyWorship
         self.addSingleFileSelectItem(u'ew')
         # Words of Worship
@@ -226,10 +231,12 @@
             translate('SongsPlugin.ImportWizardForm',
             'Generic Document/Presentation'))
         self.formatComboBox.setItemText(8,
+            translate('SongsPlugin.ImportWizardForm', 'EasiSlides'))
+        self.formatComboBox.setItemText(9,
             translate('SongsPlugin.ImportWizardForm', 'EasyWorship'))
-        self.formatComboBox.setItemText(9,
+        self.formatComboBox.setItemText(10,
             translate('SongsPlugin.ImportWizardForm', 'SongBeamer'))
-#        self.formatComboBox.setItemText(9,
+#        self.formatComboBox.setItemText(11,
 #            translate('SongsPlugin.ImportWizardForm', 'CSV'))
         self.openLP2FilenameLabel.setText(
             translate('SongsPlugin.ImportWizardForm', 'Filename:'))
@@ -281,6 +288,10 @@
             translate('SongsPlugin.ImportWizardForm', 'The generic document/'
             'presentation importer has been disabled because OpenLP cannot '
             'find OpenOffice.org on your computer.'))
+        self.easiSlidesFilenameLabel.setText(
+            translate('SongsPlugin.ImportWizardForm', 'Filename:'))
+        self.easiSlidesBrowseButton.setText(
+            translate('SongsPlugin.ImportWizardForm', 'Browse...'))
         self.ewFilenameLabel.setText(
             translate('SongsPlugin.ImportWizardForm', 'Filename:'))
         self.ewBrowseButton.setText(
@@ -311,6 +322,8 @@
             QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Fixed)
         self.openLP1FormLabelSpacer.changeSize(width, 0,
             QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Fixed)
+        self.easiSlidesFormLabelSpacer.changeSize(width, 0, 
+            QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Fixed)
         self.ewFormLabelSpacer.changeSize(width, 0, QtGui.QSizePolicy.Fixed,
             QtGui.QSizePolicy.Fixed)
 #        self.csvFormLabelSpacer.changeSize(width, 0, QtGui.QSizePolicy.Fixed,
@@ -404,6 +417,16 @@
                         'presentation file to import from.'))
                     self.genericAddButton.setFocus()
                     return False
+            elif source_format == SongFormat.EasiSlides:
+                if self.easiSlidesFilenameEdit.text().isEmpty():
+                    criticalErrorMessageBox(
+                        translate('SongsPlugin.ImportWizardForm',
+                        'No Easislides Songs file selected'),
+                        translate('SongsPlugin.ImportWizardForm',
+                        'You need to select an xml song file exported from '
+                        'EasiSlides, to import from.'))
+                    self.easiSlidesBrowseButton.setFocus()
+                    return False
             elif source_format == SongFormat.EasyWorship:
                 if self.ewFilenameEdit.text().isEmpty():
                     criticalErrorMessageBox(
@@ -625,6 +648,13 @@
         """
         self.removeSelectedItems(self.genericFileListWidget)
 
+    def onEasiSlidesBrowseButtonClicked(self):
+        self.getFileName(
+            translate('SongsPlugin.ImportWizardForm',
+            'Select EasiSlides songfile'),
+            self.easiSlidesFilenameEdit
+        )
+        
     def onEWBrowseButtonClicked(self):
         """
         Get EasyWorship song database files
@@ -674,6 +704,7 @@
         self.ccliFileListWidget.clear()
         self.songsOfFellowshipFileListWidget.clear()
         self.genericFileListWidget.clear()
+        self.easiSlidesFilenameEdit.setText(u'')
         self.ewFilenameEdit.setText(u'')
         self.songBeamerFileListWidget.clear()
         #self.csvFilenameEdit.setText(u'')
@@ -737,8 +768,13 @@
             importer = self.plugin.importSongs(SongFormat.Generic,
                 filenames=self.getListOfFiles(self.genericFileListWidget)
             )
+        elif source_format == SongFormat.EasiSlides:
+            # Import an EasiSlides export file
+            importer = self.plugin.importSongs(SongFormat.EasiSlides,
+                filename=unicode(self.easiSlidesFilenameEdit.text())
+            )
         elif source_format == SongFormat.EasyWorship:
-            # Import an OpenLP 2.0 database
+            # Import an EasyWorship database
             importer = self.plugin.importSongs(SongFormat.EasyWorship,
                 filename=unicode(self.ewFilenameEdit.text())
             )

=== added file 'openlp/plugins/songs/lib/easislidesimport.py'
--- openlp/plugins/songs/lib/easislidesimport.py	1970-01-01 00:00:00 +0000
+++ openlp/plugins/songs/lib/easislidesimport.py	2011-01-17 23:29:49 +0000
@@ -0,0 +1,357 @@
+# -*- 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, Jonathan Corwin, Michael      #
+# Gorven, Scott Guerrieri, Meinert Jordan, Andreas Preikschat, Christian      #
+# Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon Tibble,    #
+# Carsten Tinggaard, 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                          #
+###############################################################################
+
+import logging
+import os
+from lxml import etree, objectify
+from lxml.etree import Error, LxmlError
+import re
+
+from openlp.core.lib import translate
+from openlp.plugins.songs.lib.songimport import SongImport
+
+log = logging.getLogger(__name__)
+
+class EasiSlidesImport(SongImport):
+    """
+    Import songs exported from EasiSlides
+
+    The format example is here: 
+    http://wiki.openlp.org/Development:EasiSlides_-_Song_Data_Format
+    """
+    def __init__(self, manager, **kwargs):
+        """
+        Initialise the class.
+        """
+        SongImport.__init__(self, manager)
+        self.filename = kwargs[u'filename']
+        self.song = None
+        self.commit = True
+
+    def do_import(self):
+        """
+        Import either each of the files in self.filenames - each element of
+        which can be either a single opensong file, or a zipfile containing
+        multiple opensong files. If `self.commit` is set False, the
+        import will not be committed to the database (useful for test scripts).
+        """
+        self.import_wizard.progressBar.setMaximum(1)
+        
+        log.info(u'Importing XML file %s', self.filename)
+        parser = etree.XMLParser(remove_blank_text=True)
+        file = etree.parse(self.filename, parser)
+        xml = unicode(etree.tostring(file))
+        song_xml = objectify.fromstring(xml)
+        
+        self.import_wizard.incrementProgressBar(
+            unicode(translate('SongsPlugin.ImportWizardForm',
+                u'Importing %s...')) % os.path.split(self.filename)[-1])
+        self.import_wizard.progressBar.setMaximum(len(song_xml.Item))
+        
+        for song in song_xml.Item:
+            self.import_wizard.incrementProgressBar(
+                unicode(translate('SongsPlugin.ImportWizardForm',
+                    u'Importing %s, song %s...')) % 
+                    (os.path.split(self.filename)[-1], song.Title1))
+            success = self._parse_song(song)
+            if not success or self.stop_import_flag:
+                return False
+            elif self.commit:
+                self.finish()
+        return True
+    
+    def _parse_song(self, song):
+        self._success = True
+        self._add_title(song)
+        self._add_alttitle(song)
+        self._add_number(song)
+        self._add_authors(song)
+        self._add_copyright(song)
+        self._add_book(song)
+        self._parse_and_add_lyrics(song)
+        return self._success
+        
+    def _add_title(self, song):
+        try:
+            self.title = unicode(song.Title1).strip()
+        except UnicodeDecodeError:
+            log.exception(u'Unicode decode error while decoding Title1')
+            self._success = False
+        except AttributeError:
+            log.exception(u'no Title1')
+            self._success = False
+        
+    def _add_alttitle(self, song):
+        try:
+            self.alternate_title = unicode(song.Title2).strip()
+        except UnicodeDecodeError:
+            log.exception(u'Unicode decode error while decoding Title2')
+            self._success = False
+        except AttributeError:
+            pass
+    
+    def _add_number(self, song):
+        try:
+            number = int(song.SongNumber)
+            if number != 0:
+                self.song_number = number
+        except UnicodeDecodeError:
+            log.exception(u'Unicode decode error while decoding SongNumber')
+            self._success = False
+        except AttributeError:
+            pass
+
+    def _add_authors(self, song):
+        try:
+            authors = unicode(song.Writer).split(u',')
+            for author in authors:
+                author = author.strip()
+                if len(author) > 0:
+                    self.authors.append(author)
+        except UnicodeDecodeError:
+            log.exception(u'Unicode decode error while decoding Writer')
+            self._success = False
+        except AttributeError:
+            pass
+            
+    def _add_copyright(self, song):
+        copyright = []
+        try:
+            copyright.append(unicode(song.Copyright).strip())
+        except UnicodeDecodeError:
+            log.exception(u'Unicode decode error while decoding Copyright')
+            self._success = False
+        except AttributeError:
+            pass
+        try:
+            copyright.append(unicode(song.LicenceAdmin1).strip())
+        except UnicodeDecodeError:
+            log.exception(u'Unicode decode error while decoding LicenceAdmin1')
+            self._success = False
+        except AttributeError:
+            pass
+        try:
+            copyright.append(unicode(song.LicenceAdmin2).strip())
+        except UnicodeDecodeError:
+            log.exception(u'Unicode decode error while decoding LicenceAdmin2')
+            self._success = False
+        except AttributeError:
+            pass
+        self.add_copyright(u' '.join(copyright))
+        
+    def _add_book(self, song):
+        try:
+            self.song_book_name = unicode(song.BookReference).strip()
+        except UnicodeDecodeError:
+            log.exception(u'Unicode decode error while decoding BookReference')
+            self._success = False
+        except AttributeError:
+            pass
+        
+    def _parse_and_add_lyrics(self, song):
+        try:
+            lyrics = unicode(song.Contents).strip()
+        except UnicodeDecodeError:
+            log.exception(u'Unicode decode error while decoding Contents')
+            self._success = False
+        except AttributeError:
+            log.exception(u'no Contents')
+            self._success = False
+            
+        lines = lyrics.split(u'\n')
+        
+        # we go over all lines first, to determine information,
+        # which tells us how to parse verses later
+        regionlines = {}
+        separatorlines = 0
+        for line in lines:
+            line = line.strip()
+            if len(line) == 0:
+                continue
+            elif line[1:7] == u'region':
+                # this is region separator, probably [region 2]
+                region = self._extractRegion(line)
+                if regionlines.has_key(region):
+                    regionlines[region] = regionlines[region] + 1
+                else:
+                    regionlines[region] = 1
+            elif line[0] == u'[':
+                separatorlines = separatorlines + 1
+        
+        # if the song has separators
+        separators = (separatorlines > 0)
+        # the number of different regions in song - 1
+        if len(regionlines) > 1:
+            log.info(u'EasiSlidesImport: the file contained a song named "%s"'
+                u'with more than two regions, but only two regions are',
+                u'tested, encountered regions were: %s',
+                self.title, u','.join(regionlines.keys()))
+        # if the song has regions
+        regions = (len(regionlines) > 0)
+        # if the regions are inside verses
+        regionsInVerses = (regions and \
+                    regionlines[regionlines.keys()[0]] > 1)
+        
+        MarkTypes = {
+            u'CHORUS': u'C',
+            u'VERSE': u'V',
+            u'INTRO': u'I',
+            u'ENDING': u'E',
+            u'BRIDGE': u'B',
+            u'PRECHORUS': u'P'}
+            
+        verses = {}
+        # list as [region, versetype, versenum, instance]
+        our_verse_order = []
+        defaultregion = u'1'
+        reg = defaultregion
+        verses[reg] = {}
+        # instance differentiates occurrences of same verse tag
+        vt = u'V'
+        vn = u'1'
+        inst = 1
+
+        for line in lines:
+            line = line.strip()
+            
+            if len(line) == 0:
+                if separators:
+                    # separators are used, so empty line means slide break
+                    # inside verse
+                    if self._listHas(verses, [reg, vt, vn, inst]):
+                        inst = inst + 1
+                else:
+                    # separators are not used, so empty line starts a new verse
+                    vt = u'V'
+                    if verses[reg].has_key(vt):
+                        vn = len(verses[reg][vt].keys())+1
+                    else:
+                        vn = u'1'
+                    inst = 1
+                continue
+            elif line[0:7] == u'[region':
+                reg = self._extractRegion(line)
+                if not verses.has_key(reg):
+                    verses[reg] = {}
+                if not regionsInVerses:
+                    vt = u'V'
+                    vn = u'1'
+                    inst = 1
+                continue
+            elif line[0] == u'[':
+                # this is a normal section marker
+                marker = line[1:line.find(u']')].upper()
+                vn = u'1'
+                # have we got any digits?
+                # If so, versenumber is everything from the digits to the end
+                match = re.match(u'(.*)(\d+.*)', marker)
+                if match:
+                    marker = match.group(1).strip()
+                    vn = match.group(2)
+                if len(marker) == 0:
+                    vt = u'V'
+                elif MarkTypes.has_key(marker):
+                    vt = MarkTypes[marker]
+                else:
+                    vt = u'O'
+                if regionsInVerses:
+                    region = defaultregion
+                inst = 1
+                if self._listHas(verses, [reg, vt, vn, inst]):
+                    inst = len(verses[reg][vt][vn])+1
+                continue
+            
+            if not [reg, vt, vn, inst] in our_verse_order:
+                our_verse_order.append([reg, vt, vn, inst])
+            
+            if not verses[reg].has_key(vt):
+                verses[reg][vt] = {}
+            if not verses[reg][vt].has_key(vn):
+                verses[reg][vt][vn] = {}
+            if not verses[reg][vt][vn].has_key(inst):
+                verses[reg][vt][vn][inst] = []
+            
+            words = self.tidy_text(line)
+            verses[reg][vt][vn][inst].append(words)
+        # done parsing
+        
+        versetags = []
+        
+        # we use our_verse_order to ensure, we insert lyrics in the same order
+        # as these appeared originally in the file
+        for [reg, vt, vn, inst] in our_verse_order:
+            if self._listHas(verses, [reg, vt, vn, inst]):
+                versetag = u'%s%s' % (vt, vn)
+                versetags.append(versetag)
+                lines = u'\n'.join(verses[reg][vt][vn][inst])
+                self.verses.append([versetag, lines])
+        
+        SeqTypes = {
+            u'p': u'P1',
+            u'q': u'P2',
+            u'c': u'C1',
+            u't': u'C2',
+            u'b': u'B1',
+            u'w': u'B2',
+            u'e': u'E1'}
+        # Make use of Sequence data, determining the order of verses
+        try:
+            order = unicode(song.Sequence).strip().split(u',')
+            for tag in order:
+                if len(tag) == 0:
+                    continue
+                elif tag[0].isdigit():
+                    tag = u'V' + tag
+                elif SeqTypes.has_key(tag.lower()):
+                    tag = SeqTypes[tag.lower()]
+                else:
+                    continue
+                
+                if tag in versetags:
+                    self.verse_order_list.append(tag)
+                else:
+                    log.info(u'Got order item %s, which is not in versetags,'
+                        u'dropping item from presentation order', tag)
+        except UnicodeDecodeError:
+            log.exception(u'Unicode decode error while decoding Sequence')
+            self._success = False
+        except AttributeError:
+            pass
+        
+    def _listHas(self, lst, subitems):
+        for i in subitems:
+            if type(lst) == type({}) and lst.has_key(i):
+                lst = lst[i]
+            elif type(lst) == type([]) and i in lst:
+                lst = lst[i]
+            else:
+                return False
+        return True
+    
+    def _extractRegion(self, line):
+        # this was true already: line[0:7] == u'[region':
+        right_bracket = line.find(u']')
+        return line[7:right_bracket].strip()

=== modified file 'openlp/plugins/songs/lib/importer.py'
--- openlp/plugins/songs/lib/importer.py	2011-01-02 16:42:09 +0000
+++ openlp/plugins/songs/lib/importer.py	2011-01-17 23:29:49 +0000
@@ -25,6 +25,7 @@
 ###############################################################################
 
 from opensongimport import OpenSongImport
+from easislidesimport import EasiSlidesImport
 from olpimport import OpenLPSongImport
 from openlyricsimport import OpenLyricsImport
 from wowimport import WowImport
@@ -65,8 +66,9 @@
     SongsOfFellowship = 6
     Generic = 7
     #CSV = 8
-    EasyWorship = 8
-    SongBeamer = 9
+    EasiSlides = 8
+    EasyWorship = 9
+    SongBeamer = 10
 
     @staticmethod
     def get_class(format):
@@ -92,6 +94,8 @@
             return OooImport
         elif format == SongFormat.CCLI:
             return CCLIFileImport
+        elif format == SongFormat.EasiSlides:
+            return EasiSlidesImport
         elif format == SongFormat.EasyWorship:
             return EasyWorshipSongImport
         elif format == SongFormat.SongBeamer:
@@ -112,6 +116,7 @@
             SongFormat.CCLI,
             SongFormat.SongsOfFellowship,
             SongFormat.Generic,
+            SongFormat.EasiSlides,
             SongFormat.EasyWorship,
             SongFormat.SongBeamer
         ]
@@ -128,4 +133,4 @@
 SongFormat.set_availability(SongFormat.SongsOfFellowship, has_sof)
 SongFormat.set_availability(SongFormat.Generic, has_ooo)
 
-__all__ = [u'SongFormat']
\ No newline at end of file
+__all__ = [u'SongFormat']

=== modified file 'openlp/plugins/songs/lib/songimport.py'
--- openlp/plugins/songs/lib/songimport.py	2011-01-13 17:55:29 +0000
+++ openlp/plugins/songs/lib/songimport.py	2011-01-17 23:29:49 +0000
@@ -265,6 +265,7 @@
         log.info(u'commiting song %s to database', self.title)
         song = Song()
         song.title = self.title
+        song.alternate_title = self.alternate_title
         song.search_title = self.remove_punctuation(self.title).lower() \
             + '@' + self.remove_punctuation(self.alternate_title).lower()
         song.song_number = self.song_number


Follow ups