예제 #1
0
    def set_verse(self, text, single=False, tag='%s1' % VerseType.tags[VerseType.Verse]):
        """
        Save the verse

        :param text: The text
        :param single: is this a single verse
        :param tag: The tag
        """
        self.has_single_verse = single
        if single:
            verse_type_index = VerseType.from_tag(tag[0], None)
            verse_number = tag[1:]
            if verse_type_index is not None:
                self.verse_type_combo_box.setCurrentIndex(verse_type_index)
            self.verse_number_box.setValue(int(verse_number))
            self.insert_button.setVisible(False)
        else:
            if not text:
                text = '---[%s:1]---\n' % VerseType.translated_names[VerseType.Verse]
            self.verse_type_combo_box.setCurrentIndex(0)
            self.verse_number_box.setValue(1)
            self.insert_button.setVisible(True)
        self.verse_text_edit.setPlainText(text)
        self.verse_text_edit.setFocus()
        self.verse_text_edit.moveCursor(QtGui.QTextCursor.End)
예제 #2
0
    def set_verse(self, text, single=False, tag='%s1' % VerseType.tags[VerseType.Verse]):
        """
        Save the verse

        :param text: The text
        :param single: is this a single verse
        :param tag: The tag
        """
        self.has_single_verse = single
        if single:
            verse_type_index = VerseType.from_tag(tag[0], None)
            verse_number = tag[1:]
            if verse_type_index is not None:
                self.verse_type_combo_box.setCurrentIndex(verse_type_index)
            self.verse_number_box.setValue(int(verse_number))
            self.insert_button.setVisible(False)
        else:
            if not text:
                text = '---[%s:1]---\n' % VerseType.translated_names[VerseType.Verse]
            self.verse_type_combo_box.setCurrentIndex(0)
            self.verse_number_box.setValue(1)
            self.insert_button.setVisible(True)
        self.verse_text_edit.setPlainText(text)
        self.verse_text_edit.setFocus()
        self.verse_text_edit.moveCursor(QtGui.QTextCursor.End)
예제 #3
0
    def song_to_line_dict(self, song):

        song_xml = SongXML()
        if song.chords:
            verse_chords_xml = song_xml.get_verses(song.chords)
        else:
            verse_chords_xml = song_xml.get_verses(song.lyrics)

        section_line_dict = {}
        for count, verse in enumerate(verse_chords_xml):
            # This silently migrates from localized verse type markup.
            # If we trusted the database, this would be unnecessary.
            verse_tag = verse[0]['type']
            index = None
            if len(verse_tag) > 1:
                index = VerseType.from_translated_string(verse_tag)
                if index is None:
                    index = VerseType.from_string(verse_tag, None)
                else:
                    verse_tags_translated = True
            if index is None:
                index = VerseType.from_tag(verse_tag)
            verse[0]['type'] = VerseType.tags[index]
            if verse[0]['label'] == '':
                verse[0]['label'] = '1'
            section_header = '%s%s' % (verse[0]['type'], verse[0]['label'])

            line_list = []
            for line in verse[1].split('\n'):
                line_list.append(line)

            section_line_dict[section_header] = line_list

        return section_line_dict
예제 #4
0
    def song_to_line_dict(self, song):

        song_xml = SongXML()
        if song.chords:
            verse_chords_xml = song_xml.get_verses(song.chords)
        else:
            verse_chords_xml = song_xml.get_verses(song.lyrics)

        section_line_dict = {}
        for count, verse in enumerate(verse_chords_xml):
            # This silently migrates from localized verse type markup.
            # If we trusted the database, this would be unnecessary.
            verse_tag = verse[0]['type']
            index = None
            if len(verse_tag) > 1:
                index = VerseType.from_translated_string(verse_tag)
                if index is None:
                    index = VerseType.from_string(verse_tag, None)
                else:
                    verse_tags_translated = True
            if index is None:
                index = VerseType.from_tag(verse_tag)
            verse[0]['type'] = VerseType.tags[index]
            if verse[0]['label'] == '':
                verse[0]['label'] = '1'
            section_header = '%s%s' % (verse[0]['type'], verse[0]['label'])

            line_list = []
            for line in verse[1].split('\n'):
                line_list.append(line)

            section_line_dict[section_header] = line_list

        return section_line_dict
예제 #5
0
파일: test_lib.py 프로젝트: jkunle/paul
    def from_tag_with_none_default_test(self):
        """
        Test that the from_tag() method returns a sane default when passed an invalid tag and None as default.
        """
        # GIVEN: A mocked out translate() function that just returns what it was given
        with patch('openlp.plugins.songs.lib.translate') as mocked_translate:
            mocked_translate.side_effect = lambda x, y: y

            # WHEN: We run the from_tag() method with an invalid verse type, we get the specified default back
            result = VerseType.from_tag('m', None)

            # THEN: The result should be None
            self.assertIsNone(result, 'The result should be None, but was "%s"' % result)
예제 #6
0
파일: test_lib.py 프로젝트: jkunle/paul
    def from_tag_with_specified_default_test(self):
        """
        Test that the from_tag() method returns the specified default when passed an invalid tag.
        """
        # GIVEN: A mocked out translate() function that just returns what it was given
        with patch('openlp.plugins.songs.lib.translate') as mocked_translate:
            mocked_translate.side_effect = lambda x, y: y

            # WHEN: We run the from_tag() method with an invalid verse type, we get the specified default back
            result = VerseType.from_tag('x', VerseType.Chorus)

            # THEN: The result should be VerseType.Chorus
            self.assertEqual(result, VerseType.Chorus, 'The result should be VerseType.Chorus, but was "%s"' % result)
예제 #7
0
파일: test_lib.py 프로젝트: jkunle/paul
    def from_tag_test(self):
        """
        Test that the from_tag() method returns the correct VerseType.
        """
        # GIVEN: A mocked out translate() function that just returns what it was given
        with patch('openlp.plugins.songs.lib.translate') as mocked_translate:
            mocked_translate.side_effect = lambda x, y: y

            # WHEN: We run the from_tag() method with a valid verse type, we get the name back
            result = VerseType.from_tag('v')

            # THEN: The result should be VerseType.Verse
            self.assertEqual(result, VerseType.Verse, 'The result should be VerseType.Verse, but was "%s"' % result)
예제 #8
0
    def from_tag_with_invalid_default_test(self):
        """
        Test that the from_tag() method returns a sane default when passed an invalid tag and an invalid default.
        """
        # GIVEN: A mocked out translate() function that just returns what it was given
        with patch('openlp.plugins.songs.lib.translate') as mocked_translate:
            mocked_translate.side_effect = lambda x, y: y

            # WHEN: We run the from_tag() method with an invalid verse type, we get the specified default back
            result = VerseType.from_tag('m', 29)

            # THEN: The result should be VerseType.Other
            self.assertEqual(result, VerseType.Other, 'The result should be VerseType.Other, but was "%s"' % result)
예제 #9
0
    def from_tag_test(self):
        """
        Test that the from_tag() method returns the correct VerseType.
        """
        # GIVEN: A mocked out translate() function that just returns what it was given
        with patch('openlp.plugins.songs.lib.translate') as mocked_translate:
            mocked_translate.side_effect = lambda x, y: y

            # WHEN: We run the from_tag() method with a valid verse type, we get the name back
            result = VerseType.from_tag('v')

            # THEN: The result should be VerseType.Verse
            self.assertEqual(result, VerseType.Verse, 'The result should be VerseType.Verse, but was "%s"' % result)
예제 #10
0
파일: test_lib.py 프로젝트: ipic/projecao
    def test_from_tag_with_invalid_default(self):
        """
        Test that the from_tag() method returns a sane default when passed an invalid tag and an invalid default.
        """
        # GIVEN: A mocked out translate() function that just returns what it was given
        with patch('openlp.plugins.songs.lib.translate') as mocked_translate:
            mocked_translate.side_effect = lambda x, y: y

            # WHEN: We run the from_tag() method with an invalid verse type, we get the specified default back
            result = VerseType.from_tag('@', 'asdf')

            # THEN: The result should be VerseType.Other
            assert result == VerseType.Other, 'The result should be VerseType.Other, but was "%s"' % result
예제 #11
0
    def _process_lyrics(self, foilpresenterfolie, song):
        """
        Processes the verses and search_lyrics for the song.

        :param foilpresenterfolie: The foilpresenterfolie object (lxml.objectify.ObjectifiedElement).
        :param song: The song object.
        """
        sxml = SongXML()
        temp_verse_order = {}
        temp_verse_order_backup = []
        temp_sortnr_backup = 1
        temp_sortnr_liste = []
        verse_count = {
            VerseType.tags[VerseType.Verse]: 1,
            VerseType.tags[VerseType.Chorus]: 1,
            VerseType.tags[VerseType.Bridge]: 1,
            VerseType.tags[VerseType.Ending]: 1,
            VerseType.tags[VerseType.Other]: 1,
            VerseType.tags[VerseType.Intro]: 1,
            VerseType.tags[VerseType.PreChorus]: 1
        }
        if not hasattr(foilpresenterfolie.strophen, 'strophe'):
            self.importer.log_error(
                to_str(foilpresenterfolie.titel),
                str(
                    translate(
                        'SongsPlugin.FoilPresenterSongImport',
                        'Invalid Foilpresenter song file. No verses found.')))
            self.save_song = False
            return
        for strophe in foilpresenterfolie.strophen.strophe:
            text = to_str(strophe.text_) if hasattr(strophe, 'text_') else ''
            verse_name = to_str(strophe.key)
            children = strophe.getchildren()
            sortnr = False
            for child in children:
                if child.tag == 'sortnr':
                    verse_sortnr = to_str(strophe.sortnr)
                    sortnr = True
                # In older Version there is no sortnr, but we need one
            if not sortnr:
                verse_sortnr = str(temp_sortnr_backup)
                temp_sortnr_backup += 1
            # Foilpresenter allows e. g. "Ref" or "1", but we need "C1" or "V1".
            temp_sortnr_liste.append(verse_sortnr)
            temp_verse_name = re.compile('[0-9].*').sub('', verse_name)
            temp_verse_name = temp_verse_name[:3].lower()
            if temp_verse_name == 'ref':
                verse_type = VerseType.tags[VerseType.Chorus]
            elif temp_verse_name == 'r':
                verse_type = VerseType.tags[VerseType.Chorus]
            elif temp_verse_name == '':
                verse_type = VerseType.tags[VerseType.Verse]
            elif temp_verse_name == 'v':
                verse_type = VerseType.tags[VerseType.Verse]
            elif temp_verse_name == 'bri':
                verse_type = VerseType.tags[VerseType.Bridge]
            elif temp_verse_name == 'cod':
                verse_type = VerseType.tags[VerseType.Ending]
            elif temp_verse_name == 'sch':
                verse_type = VerseType.tags[VerseType.Ending]
            elif temp_verse_name == 'pre':
                verse_type = VerseType.tags[VerseType.PreChorus]
            elif temp_verse_name == 'int':
                verse_type = VerseType.tags[VerseType.Intro]
            else:
                verse_type = VerseType.tags[VerseType.Other]
            verse_number = re.compile('[a-zA-Z.+-_ ]*').sub('', verse_name)
            # Foilpresenter allows e. g. "C", but we need "C1".
            if not verse_number:
                verse_number = str(verse_count[verse_type])
                verse_count[verse_type] += 1
            else:
                # test if foilpresenter have the same versenumber two times with
                # different parts raise the verse number
                for value in temp_verse_order_backup:
                    if value == ''.join((verse_type, verse_number)):
                        verse_number = str(int(verse_number) + 1)
            verse_type_index = VerseType.from_tag(verse_type[0])
            verse_type = VerseType.tags[verse_type_index]
            temp_verse_order[verse_sortnr] = ''.join(
                (verse_type[0], verse_number))
            temp_verse_order_backup.append(''.join(
                (verse_type[0], verse_number)))
            sxml.add_verse_to_lyrics(verse_type, verse_number, text)
        song.lyrics = str(sxml.extract_xml(), 'utf-8')
        # Process verse order
        verse_order = []
        verse_strophenr = []
        try:
            for strophennummer in foilpresenterfolie.reihenfolge.strophennummer:
                verse_strophenr.append(strophennummer)
        except AttributeError:
            pass
        # Currently we do not support different "parts"!
        if '0' in temp_verse_order:
            for vers in temp_verse_order_backup:
                verse_order.append(vers)
        else:
            for number in verse_strophenr:
                numberx = temp_sortnr_liste[int(number)]
                verse_order.append(temp_verse_order[str(numberx)])
        song.verse_order = ' '.join(verse_order)
예제 #12
0
    def setupUi(self):
        self.song_vertical_layout = QtWidgets.QVBoxLayout(self)
        self.song_vertical_layout.setObjectName('song_vertical_layout')
        self.song_group_box = QtWidgets.QGroupBox(self)
        self.song_group_box.setObjectName('song_group_box')
        self.song_group_box.setFixedWidth(300)
        self.song_group_box_layout = QtWidgets.QVBoxLayout(self.song_group_box)
        self.song_group_box_layout.setObjectName('song_group_box_layout')
        self.song_info_form_layout = QtWidgets.QFormLayout()
        self.song_info_form_layout.setObjectName('song_info_form_layout')
        # Add title widget.
        self.song_title_label = QtWidgets.QLabel(self)
        self.song_title_label.setObjectName('song_title_label')
        self.song_info_form_layout.setWidget(0,
                                             QtWidgets.QFormLayout.LabelRole,
                                             self.song_title_label)
        self.song_title_content = QtWidgets.QLabel(self)
        self.song_title_content.setObjectName('song_title_content')
        self.song_title_content.setText(self.song.title)
        self.song_title_content.setWordWrap(True)
        self.song_info_form_layout.setWidget(0,
                                             QtWidgets.QFormLayout.FieldRole,
                                             self.song_title_content)
        # Add alternate title widget.
        self.song_alternate_title_label = QtWidgets.QLabel(self)
        self.song_alternate_title_label.setObjectName(
            'song_alternate_title_label')
        self.song_info_form_layout.setWidget(1,
                                             QtWidgets.QFormLayout.LabelRole,
                                             self.song_alternate_title_label)
        self.song_alternate_title_content = QtWidgets.QLabel(self)
        self.song_alternate_title_content.setObjectName(
            'song_alternate_title_content')
        self.song_alternate_title_content.setText(self.song.alternate_title)
        self.song_alternate_title_content.setWordWrap(True)
        self.song_info_form_layout.setWidget(1,
                                             QtWidgets.QFormLayout.FieldRole,
                                             self.song_alternate_title_content)
        # Add CCLI number widget.
        self.song_ccli_number_label = QtWidgets.QLabel(self)
        self.song_ccli_number_label.setObjectName('song_ccli_number_label')
        self.song_info_form_layout.setWidget(2,
                                             QtWidgets.QFormLayout.LabelRole,
                                             self.song_ccli_number_label)
        self.song_ccli_number_content = QtWidgets.QLabel(self)
        self.song_ccli_number_content.setObjectName('song_ccli_number_content')
        self.song_ccli_number_content.setText(self.song.ccli_number)
        self.song_ccli_number_content.setWordWrap(True)
        self.song_info_form_layout.setWidget(2,
                                             QtWidgets.QFormLayout.FieldRole,
                                             self.song_ccli_number_content)
        # Add copyright widget.
        self.song_copyright_label = QtWidgets.QLabel(self)
        self.song_copyright_label.setObjectName('song_copyright_label')
        self.song_info_form_layout.setWidget(3,
                                             QtWidgets.QFormLayout.LabelRole,
                                             self.song_copyright_label)
        self.song_copyright_content = QtWidgets.QLabel(self)
        self.song_copyright_content.setObjectName('song_copyright_content')
        self.song_copyright_content.setWordWrap(True)
        self.song_copyright_content.setText(self.song.copyright)
        self.song_info_form_layout.setWidget(3,
                                             QtWidgets.QFormLayout.FieldRole,
                                             self.song_copyright_content)
        # Add comments widget.
        self.song_comments_label = QtWidgets.QLabel(self)
        self.song_comments_label.setObjectName('song_comments_label')
        self.song_info_form_layout.setWidget(4,
                                             QtWidgets.QFormLayout.LabelRole,
                                             self.song_comments_label)
        self.song_comments_content = QtWidgets.QLabel(self)
        self.song_comments_content.setObjectName('song_comments_content')
        self.song_comments_content.setText(self.song.comments)
        self.song_comments_content.setWordWrap(True)
        self.song_info_form_layout.setWidget(4,
                                             QtWidgets.QFormLayout.FieldRole,
                                             self.song_comments_content)
        # Add authors widget.
        self.song_authors_label = QtWidgets.QLabel(self)
        self.song_authors_label.setObjectName('song_authors_label')
        self.song_info_form_layout.setWidget(5,
                                             QtWidgets.QFormLayout.LabelRole,
                                             self.song_authors_label)
        self.song_authors_content = QtWidgets.QLabel(self)
        self.song_authors_content.setObjectName('song_authors_content')
        self.song_authors_content.setWordWrap(True)
        authors_text = ', '.join(
            [author.display_name for author in self.song.authors])
        self.song_authors_content.setText(authors_text)
        self.song_info_form_layout.setWidget(5,
                                             QtWidgets.QFormLayout.FieldRole,
                                             self.song_authors_content)
        # Add verse order widget.
        self.song_verse_order_label = QtWidgets.QLabel(self)
        self.song_verse_order_label.setObjectName('song_verse_order_label')
        self.song_info_form_layout.setWidget(6,
                                             QtWidgets.QFormLayout.LabelRole,
                                             self.song_verse_order_label)
        self.song_verse_order_content = QtWidgets.QLabel(self)
        self.song_verse_order_content.setObjectName('song_verse_order_content')
        self.song_verse_order_content.setText(self.song.verse_order)
        self.song_verse_order_content.setWordWrap(True)
        self.song_info_form_layout.setWidget(6,
                                             QtWidgets.QFormLayout.FieldRole,
                                             self.song_verse_order_content)
        self.song_group_box_layout.addLayout(self.song_info_form_layout)
        # Add verses widget.
        self.song_info_verse_list_widget = QtWidgets.QTableWidget(
            self.song_group_box)
        self.song_info_verse_list_widget.setColumnCount(1)
        self.song_info_verse_list_widget.horizontalHeader().setVisible(False)
        self.song_info_verse_list_widget.setObjectName(
            'song_info_verse_list_widget')
        self.song_info_verse_list_widget.setSelectionMode(
            QtWidgets.QAbstractItemView.NoSelection)
        self.song_info_verse_list_widget.setEditTriggers(
            QtWidgets.QAbstractItemView.NoEditTriggers)
        self.song_info_verse_list_widget.setHorizontalScrollBarPolicy(
            QtCore.Qt.ScrollBarAlwaysOff)
        self.song_info_verse_list_widget.setVerticalScrollBarPolicy(
            QtCore.Qt.ScrollBarAlwaysOff)
        self.song_info_verse_list_widget.setAlternatingRowColors(True)
        song_xml = SongXML()
        verses = song_xml.get_verses(self.song.lyrics)
        self.song_info_verse_list_widget.setRowCount(len(verses))
        song_tags = []
        for verse_number, verse in enumerate(verses):
            item = QtWidgets.QTableWidgetItem()
            item.setText(verse[1])
            self.song_info_verse_list_widget.setItem(verse_number, 0, item)

            # We cannot use from_loose_input() here, because database
            # is supposed to contain English lowercase singlechar tags.
            verse_tag = verse[0]['type']
            verse_index = None
            if len(verse_tag) > 1:
                verse_index = VerseType.from_translated_string(verse_tag)
                if verse_index is None:
                    verse_index = VerseType.from_string(verse_tag, None)
            if verse_index is None:
                verse_index = VerseType.from_tag(verse_tag)
            verse_tag = VerseType.translated_tags[verse_index].upper()
            song_tags.append(str(verse_tag + verse[0]['label']))
        self.song_info_verse_list_widget.setVerticalHeaderLabels(song_tags)
        # Resize table fields to content and table to columns
        self.song_info_verse_list_widget.setColumnWidth(
            0, self.song_group_box.width())
        self.song_info_verse_list_widget.resizeRowsToContents()
        # The 6 is a trial and error value since verticalHeader().length() + offset() is a little bit to small.
        # It seems there is no clean way to determine the real height of the table contents.
        # The "correct" value slightly fluctuates depending on the theme used, in the worst case
        # Some pixels are missing at the bottom of the table, but all themes I tried still allowed
        # to read the last verse line, so I'll just leave it at that.
        self.song_info_verse_list_widget.setFixedHeight(
            self.song_info_verse_list_widget.verticalHeader().length() +
            self.song_info_verse_list_widget.verticalHeader().offset() + 6)
        self.song_group_box_layout.addWidget(self.song_info_verse_list_widget)
        self.song_group_box_layout.addStretch()
        self.song_vertical_layout.addWidget(self.song_group_box)
        self.song_remove_button = QtWidgets.QPushButton(self)
        self.song_remove_button.setObjectName('song_remove_button')
        self.song_remove_button.setIcon(build_icon(':/songs/song_delete.png'))
        self.song_remove_button.setSizePolicy(QtWidgets.QSizePolicy.Fixed,
                                              QtWidgets.QSizePolicy.Fixed)
        self.song_vertical_layout.addWidget(self.song_remove_button,
                                            alignment=QtCore.Qt.AlignHCenter)
예제 #13
0
    def setupUi(self):
        self.song_vertical_layout = QtGui.QVBoxLayout(self)
        self.song_vertical_layout.setObjectName('song_vertical_layout')
        self.song_group_box = QtGui.QGroupBox(self)
        self.song_group_box.setObjectName('song_group_box')
        self.song_group_box.setFixedWidth(300)
        self.song_group_box_layout = QtGui.QVBoxLayout(self.song_group_box)
        self.song_group_box_layout.setObjectName('song_group_box_layout')
        self.song_info_form_layout = QtGui.QFormLayout()
        self.song_info_form_layout.setObjectName('song_info_form_layout')
        # Add title widget.
        self.song_title_label = QtGui.QLabel(self)
        self.song_title_label.setObjectName('song_title_label')
        self.song_info_form_layout.setWidget(0, QtGui.QFormLayout.LabelRole, self.song_title_label)
        self.song_title_content = QtGui.QLabel(self)
        self.song_title_content.setObjectName('song_title_content')
        self.song_title_content.setText(self.song.title)
        self.song_title_content.setWordWrap(True)
        self.song_info_form_layout.setWidget(0, QtGui.QFormLayout.FieldRole, self.song_title_content)
        # Add alternate title widget.
        self.song_alternate_title_label = QtGui.QLabel(self)
        self.song_alternate_title_label.setObjectName('song_alternate_title_label')
        self.song_info_form_layout.setWidget(1, QtGui.QFormLayout.LabelRole, self.song_alternate_title_label)
        self.song_alternate_title_content = QtGui.QLabel(self)
        self.song_alternate_title_content.setObjectName('song_alternate_title_content')
        self.song_alternate_title_content.setText(self.song.alternate_title)
        self.song_alternate_title_content.setWordWrap(True)
        self.song_info_form_layout.setWidget(1, QtGui.QFormLayout.FieldRole, self.song_alternate_title_content)
        # Add CCLI number widget.
        self.song_ccli_number_label = QtGui.QLabel(self)
        self.song_ccli_number_label.setObjectName('song_ccli_number_label')
        self.song_info_form_layout.setWidget(2, QtGui.QFormLayout.LabelRole, self.song_ccli_number_label)
        self.song_ccli_number_content = QtGui.QLabel(self)
        self.song_ccli_number_content.setObjectName('song_ccli_number_content')
        self.song_ccli_number_content.setText(self.song.ccli_number)
        self.song_ccli_number_content.setWordWrap(True)
        self.song_info_form_layout.setWidget(2, QtGui.QFormLayout.FieldRole, self.song_ccli_number_content)
        # Add copyright widget.
        self.song_copyright_label = QtGui.QLabel(self)
        self.song_copyright_label.setObjectName('song_copyright_label')
        self.song_info_form_layout.setWidget(3, QtGui.QFormLayout.LabelRole, self.song_copyright_label)
        self.song_copyright_content = QtGui.QLabel(self)
        self.song_copyright_content.setObjectName('song_copyright_content')
        self.song_copyright_content.setWordWrap(True)
        self.song_copyright_content.setText(self.song.copyright)
        self.song_info_form_layout.setWidget(3, QtGui.QFormLayout.FieldRole, self.song_copyright_content)
        # Add comments widget.
        self.song_comments_label = QtGui.QLabel(self)
        self.song_comments_label.setObjectName('song_comments_label')
        self.song_info_form_layout.setWidget(4, QtGui.QFormLayout.LabelRole, self.song_comments_label)
        self.song_comments_content = QtGui.QLabel(self)
        self.song_comments_content.setObjectName('song_comments_content')
        self.song_comments_content.setText(self.song.comments)
        self.song_comments_content.setWordWrap(True)
        self.song_info_form_layout.setWidget(4, QtGui.QFormLayout.FieldRole, self.song_comments_content)
        # Add authors widget.
        self.song_authors_label = QtGui.QLabel(self)
        self.song_authors_label.setObjectName('song_authors_label')
        self.song_info_form_layout.setWidget(5, QtGui.QFormLayout.LabelRole, self.song_authors_label)
        self.song_authors_content = QtGui.QLabel(self)
        self.song_authors_content.setObjectName('song_authors_content')
        self.song_authors_content.setWordWrap(True)
        authors_text = ', '.join([author.display_name for author in self.song.authors])
        self.song_authors_content.setText(authors_text)
        self.song_info_form_layout.setWidget(5, QtGui.QFormLayout.FieldRole, self.song_authors_content)
        # Add verse order widget.
        self.song_verse_order_label = QtGui.QLabel(self)
        self.song_verse_order_label.setObjectName('song_verse_order_label')
        self.song_info_form_layout.setWidget(6, QtGui.QFormLayout.LabelRole, self.song_verse_order_label)
        self.song_verse_order_content = QtGui.QLabel(self)
        self.song_verse_order_content.setObjectName('song_verse_order_content')
        self.song_verse_order_content.setText(self.song.verse_order)
        self.song_verse_order_content.setWordWrap(True)
        self.song_info_form_layout.setWidget(6, QtGui.QFormLayout.FieldRole, self.song_verse_order_content)
        self.song_group_box_layout.addLayout(self.song_info_form_layout)
        # Add verses widget.
        self.song_info_verse_list_widget = QtGui.QTableWidget(self.song_group_box)
        self.song_info_verse_list_widget.setColumnCount(1)
        self.song_info_verse_list_widget.horizontalHeader().setVisible(False)
        self.song_info_verse_list_widget.setObjectName('song_info_verse_list_widget')
        self.song_info_verse_list_widget.setSelectionMode(QtGui.QAbstractItemView.NoSelection)
        self.song_info_verse_list_widget.setEditTriggers(QtGui.QAbstractItemView.NoEditTriggers)
        self.song_info_verse_list_widget.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
        self.song_info_verse_list_widget.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
        self.song_info_verse_list_widget.setAlternatingRowColors(True)
        song_xml = SongXML()
        verses = song_xml.get_verses(self.song.lyrics)
        self.song_info_verse_list_widget.setRowCount(len(verses))
        song_tags = []
        for verse_number, verse in enumerate(verses):
            item = QtGui.QTableWidgetItem()
            item.setText(verse[1])
            self.song_info_verse_list_widget.setItem(verse_number, 0, item)

            # We cannot use from_loose_input() here, because database
            # is supposed to contain English lowercase singlechar tags.
            verse_tag = verse[0]['type']
            verse_index = None
            if len(verse_tag) > 1:
                verse_index = VerseType.from_translated_string(verse_tag)
                if verse_index is None:
                    verse_index = VerseType.from_string(verse_tag, None)
            if verse_index is None:
                verse_index = VerseType.from_tag(verse_tag)
            verse_tag = VerseType.translated_tags[verse_index].upper()
            song_tags.append(str(verse_tag + verse[0]['label']))
        self.song_info_verse_list_widget.setVerticalHeaderLabels(song_tags)
        # Resize table fields to content and table to columns
        self.song_info_verse_list_widget.setColumnWidth(0, self.song_group_box.width())
        self.song_info_verse_list_widget.resizeRowsToContents()
        # The 6 is a trial and error value since verticalHeader().length() + offset() is a little bit to small.
        # It seems there is no clean way to determine the real height of the table contents.
        # The "correct" value slightly fluctuates depending on the theme used, in the worst case
        # Some pixels are missing at the bottom of the table, but all themes I tried still allowed
        # to read the last verse line, so I'll just leave it at that.
        self.song_info_verse_list_widget.setFixedHeight(self.song_info_verse_list_widget.verticalHeader().length() +
                                                        self.song_info_verse_list_widget.verticalHeader().offset() + 6)
        self.song_group_box_layout.addWidget(self.song_info_verse_list_widget)
        self.song_group_box_layout.addStretch()
        self.song_vertical_layout.addWidget(self.song_group_box)
        self.song_remove_button = QtGui.QPushButton(self)
        self.song_remove_button.setObjectName('song_remove_button')
        self.song_remove_button.setIcon(build_icon(':/songs/song_delete.png'))
        self.song_remove_button.setSizePolicy(QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Fixed)
        self.song_vertical_layout.addWidget(self.song_remove_button, alignment=QtCore.Qt.AlignHCenter)
예제 #14
0
파일: mediaitem.py 프로젝트: ipic/projecao
    def generate_slide_data(self,
                            service_item,
                            *,
                            item=None,
                            context=ServiceItemContext.Service,
                            **kwargs):
        """
        Generate the slide data. Needs to be implemented by the plugin.

        :param service_item: The service item to be built on
        :param item: The Song item to be used
        :param context: Why is it being generated
        :param kwargs: Consume other unused args specified by the base implementation, but not use by this one.
        """
        log.debug('generate_slide_data: {service}, {item}, {remote}'.format(
            service=service_item, item=item, remote=self.remote_song))
        item_id = self._get_id_of_item_to_generate(item, self.remote_song)
        service_item.add_capability(ItemCapabilities.CanEdit)
        service_item.add_capability(ItemCapabilities.CanPreview)
        service_item.add_capability(ItemCapabilities.CanLoop)
        service_item.add_capability(ItemCapabilities.OnLoadUpdate)
        service_item.add_capability(ItemCapabilities.AddIfNewItem)
        service_item.add_capability(ItemCapabilities.CanSoftBreak)
        service_item.add_capability(ItemCapabilities.HasMetaData)
        song = self.plugin.manager.get_object(Song, item_id)
        service_item.theme = song.theme_name
        service_item.edit_id = item_id
        verse_list = SongXML().get_verses(song.lyrics)
        if self.settings.value(
                'songs/add songbook slide') and song.songbook_entries:
            first_slide = '\n'
            for songbook_entry in song.songbook_entries:
                first_slide += '{book} #{num}'.format(
                    book=songbook_entry.songbook.name,
                    num=songbook_entry.entry)
                if songbook_entry.songbook.publisher:
                    first_slide += ' ({pub})'.format(
                        pub=songbook_entry.songbook.publisher)
                first_slide += '\n\n'

            service_item.add_from_text(first_slide, 'O1')
        # no verse list or only 1 space (in error)
        verse_tags_translated = False
        if VerseType.from_translated_string(str(
                verse_list[0][0]['type'])) is not None:
            verse_tags_translated = True
        if not song.verse_order.strip():
            for verse in verse_list:
                # We cannot use from_loose_input() here, because database is supposed to contain English lowercase
                # single char tags.
                verse_tag = verse[0]['type']
                verse_index = None
                if len(verse_tag) > 1:
                    verse_index = VerseType.from_translated_string(verse_tag)
                    if verse_index is None:
                        verse_index = VerseType.from_string(verse_tag, None)
                if verse_index is None:
                    verse_index = VerseType.from_tag(verse_tag)
                verse_tag = VerseType.translated_tags[verse_index].upper()
                verse_def = '{tag}{label}'.format(tag=verse_tag,
                                                  label=verse[0]['label'])
                force_verse = verse[1].split('[--}{--]\n')
                for split_verse in force_verse:
                    service_item.add_from_text(split_verse, verse_def)
        else:
            # Loop through the verse list and expand the song accordingly.
            for order in song.verse_order.lower().split():
                if not order:
                    break
                for verse in verse_list:
                    if verse[0]['type'][0].lower() == \
                            order[0] and (verse[0]['label'].lower() == order[1:] or not order[1:]):
                        if verse_tags_translated:
                            verse_index = VerseType.from_translated_tag(
                                verse[0]['type'])
                        else:
                            verse_index = VerseType.from_tag(verse[0]['type'])
                        verse_tag = VerseType.translated_tags[verse_index]
                        verse_def = '{tag}{label}'.format(
                            tag=verse_tag, label=verse[0]['label'])
                        force_verse = verse[1].split('[--}{--]\n')
                        for split_verse in force_verse:
                            service_item.add_from_text(split_verse, verse_def)
        service_item.title = song.title
        author_list = self.generate_footer(service_item, song)
        service_item.data_string = {
            'title': song.search_title,
            'authors': ', '.join(author_list)
        }
        service_item.xml_version = self.open_lyrics.song_to_xml(song)
        # Add the audio file to the service item.
        if song.media_files:
            if State().check_preconditions('media'):
                service_item.add_capability(
                    ItemCapabilities.HasBackgroundAudio)
                total_length = 0
                for m in song.media_files:
                    total_length += self.media_controller.media_length(
                        m.file_path)
                service_item.background_audio = [
                    m.file_path for m in song.media_files
                ]
                service_item.set_media_length(total_length)
                service_item.metadata.append(
                    '<em>{label}:</em> {media}'.format(
                        label=translate('SongsPlugin.MediaItem', 'Media'),
                        media=service_item.background_audio))
        return True
예제 #15
0
    def generate_slide_data(self, service_item, item=None, xml_version=False, remote=False,
                            context=ServiceItemContext.Service):
        """
        Generate the slide data. Needs to be implemented by the plugin.

        :param service_item: The service item to be built on
        :param item: The Song item to be used
        :param xml_version: The xml version (not used)
        :param remote: Triggered from remote
        :param context: Why is it being generated
        """
        log.debug('generate_slide_data: {service}, {item}, {remote}'.format(service=service_item, item=item,
                                                                            remote=self.remote_song))
        item_id = self._get_id_of_item_to_generate(item, self.remote_song)
        service_item.add_capability(ItemCapabilities.CanEdit)
        service_item.add_capability(ItemCapabilities.CanPreview)
        service_item.add_capability(ItemCapabilities.CanLoop)
        service_item.add_capability(ItemCapabilities.OnLoadUpdate)
        service_item.add_capability(ItemCapabilities.AddIfNewItem)
        service_item.add_capability(ItemCapabilities.CanSoftBreak)
        song = self.plugin.manager.get_object(Song, item_id)
        service_item.theme = song.theme_name
        service_item.edit_id = item_id
        verse_list = SongXML().get_verses(song.lyrics)
        # no verse list or only 1 space (in error)
        verse_tags_translated = False
        if VerseType.from_translated_string(str(verse_list[0][0]['type'])) is not None:
            verse_tags_translated = True
        if not song.verse_order.strip():
            for verse in verse_list:
                # We cannot use from_loose_input() here, because database is supposed to contain English lowercase
                # singlechar tags.
                verse_tag = verse[0]['type']
                verse_index = None
                if len(verse_tag) > 1:
                    verse_index = VerseType.from_translated_string(verse_tag)
                    if verse_index is None:
                        verse_index = VerseType.from_string(verse_tag, None)
                if verse_index is None:
                    verse_index = VerseType.from_tag(verse_tag)
                verse_tag = VerseType.translated_tags[verse_index].upper()
                verse_def = '{tag}{label}'.format(tag=verse_tag, label=verse[0]['label'])
                service_item.add_from_text(str(verse[1]), verse_def)
        else:
            # Loop through the verse list and expand the song accordingly.
            for order in song.verse_order.lower().split():
                if not order:
                    break
                for verse in verse_list:
                    if verse[0]['type'][0].lower() == \
                            order[0] and (verse[0]['label'].lower() == order[1:] or not order[1:]):
                        if verse_tags_translated:
                            verse_index = VerseType.from_translated_tag(verse[0]['type'])
                        else:
                            verse_index = VerseType.from_tag(verse[0]['type'])
                        verse_tag = VerseType.translated_tags[verse_index]
                        verse_def = '{tag}{text}'.format(tag=verse_tag, text=verse[0]['label'])
                        service_item.add_from_text(verse[1], verse_def)
        service_item.title = song.title
        author_list = self.generate_footer(service_item, song)
        service_item.data_string = {'title': song.search_title, 'authors': ', '.join(author_list)}
        service_item.xml_version = self.open_lyrics.song_to_xml(song)
        # Add the audio file to the service item.
        if song.media_files:
            service_item.add_capability(ItemCapabilities.HasBackgroundAudio)
            service_item.background_audio = [m.file_name for m in song.media_files]
        return True
예제 #16
0
 def do_import_file(self, file):
     """
     Process the OpenSong file - pass in a file-like object, not a file path.
     """
     self.set_defaults()
     try:
         tree = objectify.parse(file)
     except (Error, LxmlError):
         self.log_error(file.name, SongStrings.XMLSyntaxError)
         log.exception('Error parsing XML')
         return
     root = tree.getroot()
     if root.tag != 'song':
         self.log_error(
             file.name,
             str(
                 translate(
                     'SongsPlugin.OpenSongImport',
                     'Invalid OpenSong song file. Missing song tag.')))
         return
     fields = dir(root)
     decode = {
         'copyright': self.add_copyright,
         'ccli': 'ccli_number',
         'author': self.parse_author,
         'title': 'title',
         'aka': 'alternate_title',
         'hymn_number': self.parse_song_book_name_and_number,
         'user1': self.add_comment,
         'user2': self.add_comment,
         'user3': self.add_comment
     }
     for attr, fn_or_string in list(decode.items()):
         if attr in fields:
             ustring = str(root.__getattr__(attr))
             if isinstance(fn_or_string, str):
                 if attr in ['ccli']:
                     ustring = ''.join(re.findall('\d+', ustring))
                     if ustring:
                         setattr(self, fn_or_string, int(ustring))
                     else:
                         setattr(self, fn_or_string, None)
                 else:
                     setattr(self, fn_or_string, ustring)
             else:
                 fn_or_string(ustring)
     # Themes look like "God: Awe/Wonder", but we just want
     # "Awe" and "Wonder".  We use a set to ensure each topic
     # is only added once, in case it is already there, which
     # is actually quite likely if the alttheme is set
     topics = set(self.topics)
     if 'theme' in fields:
         theme = str(root.theme)
         subthemes = theme[theme.find(':') + 1:].split('/')
         for topic in subthemes:
             topics.add(topic.strip())
     if 'alttheme' in fields:
         theme = str(root.alttheme)
         subthemes = theme[theme.find(':') + 1:].split('/')
         for topic in subthemes:
             topics.add(topic.strip())
     self.topics = list(topics)
     self.topics.sort()
     # data storage while importing
     verses = {}
     # keep track of verses appearance order
     our_verse_order = []
     # default verse
     verse_tag = VerseType.tags[VerseType.Verse]
     verse_num = '1'
     # for the case where song has several sections with same marker
     inst = 1
     if 'lyrics' in fields:
         lyrics = str(root.lyrics)
     else:
         lyrics = ''
     for this_line in lyrics.split('\n'):
         if not this_line.strip():
             continue
         # skip this line if it is a comment
         if this_line.startswith(';'):
             continue
         # skip guitar chords and page and column breaks
         if this_line.startswith('.') or this_line.startswith(
                 '---') or this_line.startswith('-!!'):
             continue
         # verse/chorus/etc. marker
         if this_line.startswith('['):
             # drop the square brackets
             right_bracket = this_line.find(']')
             content = this_line[1:right_bracket].lower()
             # have we got any digits? If so, verse number is everything from the digits to the end (openlp does not
             # have concept of part verses, so just ignore any non integers on the end (including floats))
             match = re.match('(\D*)(\d+)', content)
             if match is not None:
                 verse_tag = match.group(1)
                 verse_num = match.group(2)
             else:
                 # otherwise we assume number 1 and take the whole prefix as the verse tag
                 verse_tag = content
                 verse_num = '1'
             verse_index = VerseType.from_loose_input(
                 verse_tag) if verse_tag else 0
             verse_tag = VerseType.tags[verse_index]
             inst = 1
             if [verse_tag, verse_num, inst
                 ] in our_verse_order and verse_num in verses.get(
                     verse_tag, {}):
                 inst = len(verses[verse_tag][verse_num]) + 1
             continue
         # number at start of line.. it's verse number
         if this_line[0].isdigit():
             verse_num = this_line[0]
             this_line = this_line[1:].strip()
         verses.setdefault(verse_tag, {})
         verses[verse_tag].setdefault(verse_num, {})
         if inst not in verses[verse_tag][verse_num]:
             verses[verse_tag][verse_num][inst] = []
             our_verse_order.append([verse_tag, verse_num, inst])
         # Tidy text and remove the ____s from extended words
         this_line = self.tidy_text(this_line)
         this_line = this_line.replace('_', '')
         this_line = this_line.replace('||', '\n[---]\n')
         this_line = this_line.strip()
         # If the line consists solely of a '|', then just use the implicit newline
         # Otherwise, add a newline for each '|'
         if this_line == '|':
             this_line = ''
         else:
             this_line = this_line.replace('|', '\n')
         verses[verse_tag][verse_num][inst].append(this_line)
     # done parsing
     # add verses in original order
     verse_joints = {}
     for (verse_tag, verse_num, inst) in our_verse_order:
         lines = '\n'.join(verses[verse_tag][verse_num][inst])
         length = 0
         while length < len(verse_num) and verse_num[length].isnumeric():
             length += 1
         verse_def = '{tag}{number}'.format(tag=verse_tag,
                                            number=verse_num[:length])
         verse_joints[verse_def] = '{verse}\n[---]\n{lines}'.format(verse=verse_joints[verse_def], lines=lines) \
             if verse_def in verse_joints else lines
     # Parsing the dictionary produces the elements in a non-intuitive order.  While it "works", it's not a
     # natural layout should the user come back to edit the song.  Instead we sort by the verse type, so that we
     # get all the verses in order (v1, v2, ...), then the chorus(es), bridge(s), pre-chorus(es) etc.  We use a
     # tuple for the key, since tuples naturally sort in this manner.
     verse_defs = sorted(
         verse_joints.keys(),
         key=lambda verse_def:
         (VerseType.from_tag(verse_def[0]), int(verse_def[1:])))
     for verse_def in verse_defs:
         lines = verse_joints[verse_def]
         self.add_verse(lines, verse_def)
     if not self.verses:
         self.add_verse('')
     # figure out the presentation order, if present
     if 'presentation' in fields and root.presentation:
         order = str(root.presentation)
         # We make all the tags in the lyrics lower case, so match that here and then split into a list on the
         # whitespace.
         order = order.lower().split()
         for verse_def in order:
             match = re.match('(\D*)(\d+.*)', verse_def)
             if match is not None:
                 verse_tag = match.group(1)
                 verse_num = match.group(2)
                 if not verse_tag:
                     verse_tag = VerseType.tags[VerseType.Verse]
             else:
                 # Assume it's no.1 if there are no digits
                 verse_tag = verse_def
                 verse_num = '1'
             verse_index = VerseType.from_loose_input(verse_tag)
             verse_tag = VerseType.tags[verse_index]
             verse_def = '{tag}{number}'.format(tag=verse_tag,
                                                number=verse_num)
             if verse_num in verses.get(verse_tag, {}):
                 self.verse_order_list.append(verse_def)
             else:
                 log.info(
                     'Got order {order} but not in verse tags, dropping this item from presentation '
                     'order'.format(order=verse_def))
     if not self.finish():
         self.log_error(file.name)
예제 #17
0
 def generateSlideData(self, service_item, item=None, xmlVersion=False,
             remote=False, context=ServiceItemContext.Service):
     log.debug(u'generateSlideData: %s, %s, %s' % (service_item, item, self.remoteSong))
     item_id = self._getIdOfItemToGenerate(item, self.remoteSong)
     service_item.add_capability(ItemCapabilities.CanEdit)
     service_item.add_capability(ItemCapabilities.CanPreview)
     service_item.add_capability(ItemCapabilities.CanLoop)
     service_item.add_capability(ItemCapabilities.OnLoadUpdate)
     service_item.add_capability(ItemCapabilities.AddIfNewItem)
     service_item.add_capability(ItemCapabilities.CanSoftBreak)
     song = self.plugin.manager.get_object(Song, item_id)
     service_item.theme = song.theme_name
     service_item.edit_id = item_id
     if song.lyrics.startswith(u'<?xml version='):
         verse_list = SongXML().get_verses(song.lyrics)
         # no verse list or only 1 space (in error)
         verse_tags_translated = False
         if VerseType.from_translated_string(unicode(verse_list[0][0][u'type'])) is not None:
             verse_tags_translated = True
         if not song.verse_order.strip():
             for verse in verse_list:
                 # We cannot use from_loose_input() here, because database
                 # is supposed to contain English lowercase singlechar tags.
                 verse_tag = verse[0][u'type']
                 verse_index = None
                 if len(verse_tag) > 1:
                     verse_index = VerseType.from_translated_string(verse_tag)
                     if verse_index is None:
                         verse_index = VerseType.from_string(verse_tag, None)
                 if verse_index is None:
                     verse_index = VerseType.from_tag(verse_tag)
                 verse_tag = VerseType.TranslatedTags[verse_index].upper()
                 verse_def = u'%s%s' % (verse_tag, verse[0][u'label'])
                 service_item.add_from_text(unicode(verse[1]), verse_def)
         else:
             # Loop through the verse list and expand the song accordingly.
             for order in song.verse_order.lower().split():
                 if not order:
                     break
                 for verse in verse_list:
                     if verse[0][u'type'][0].lower() == order[0] and (verse[0][u'label'].lower() == order[1:] or \
                             not order[1:]):
                         if verse_tags_translated:
                             verse_index = VerseType.from_translated_tag(verse[0][u'type'])
                         else:
                             verse_index = VerseType.from_tag(verse[0][u'type'])
                         verse_tag = VerseType.TranslatedTags[verse_index]
                         verse_def = u'%s%s' % (verse_tag, verse[0][u'label'])
                         service_item.add_from_text(verse[1], verse_def)
     else:
         verses = song.lyrics.split(u'\n\n')
         for slide in verses:
             service_item.add_from_text(unicode(slide))
     service_item.title = song.title
     author_list = [unicode(author.display_name) for author in song.authors]
     service_item.raw_footer.append(song.title)
     service_item.raw_footer.append(create_separated_list(author_list))
     service_item.raw_footer.append(song.copyright)
     if Settings().value(u'general/ccli number'):
         service_item.raw_footer.append(translate('SongsPlugin.MediaItem', 'CCLI License: ') +
             Settings().value(u'general/ccli number'))
     service_item.audit = [
         song.title, author_list, song.copyright, unicode(song.ccli_number)
     ]
     service_item.data_string = {u'title': song.search_title, u'authors': u', '.join(author_list)}
     service_item.xml_version = self.openLyrics.song_to_xml(song)
     # Add the audio file to the service item.
     if song.media_files:
         service_item.add_capability(ItemCapabilities.HasBackgroundAudio)
         service_item.background_audio = [m.file_name for m in song.media_files]
     return True
예제 #18
0
    def _process_lyrics(self, foilpresenterfolie, song):
        """
        Processes the verses and search_lyrics for the song.

        :param foilpresenterfolie: The foilpresenterfolie object (lxml.objectify.ObjectifiedElement).
        :param song: The song object.
        """
        sxml = SongXML()
        temp_verse_order = {}
        temp_verse_order_backup = []
        temp_sortnr_backup = 1
        temp_sortnr_liste = []
        verse_count = {
            VerseType.tags[VerseType.Verse]: 1,
            VerseType.tags[VerseType.Chorus]: 1,
            VerseType.tags[VerseType.Bridge]: 1,
            VerseType.tags[VerseType.Ending]: 1,
            VerseType.tags[VerseType.Other]: 1,
            VerseType.tags[VerseType.Intro]: 1,
            VerseType.tags[VerseType.PreChorus]: 1
        }
        if not hasattr(foilpresenterfolie.strophen, 'strophe'):
            self.importer.log_error(self._child(foilpresenterfolie.titel),
                                    str(translate('SongsPlugin.FoilPresenterSongImport',
                                                  'Invalid Foilpresenter song file. No verses found.')))
            self.save_song = False
            return
        for strophe in foilpresenterfolie.strophen.strophe:
            text = self._child(strophe.text_) if hasattr(strophe, 'text_') else ''
            verse_name = self._child(strophe.key)
            children = strophe.getchildren()
            sortnr = False
            for child in children:
                if child.tag == 'sortnr':
                    verse_sortnr = self._child(strophe.sortnr)
                    sortnr = True
                # In older Version there is no sortnr, but we need one
            if not sortnr:
                verse_sortnr = str(temp_sortnr_backup)
                temp_sortnr_backup += 1
            # Foilpresenter allows e. g. "Ref" or "1", but we need "C1" or "V1".
            temp_sortnr_liste.append(verse_sortnr)
            temp_verse_name = re.compile('[0-9].*').sub('', verse_name)
            temp_verse_name = temp_verse_name[:3].lower()
            if temp_verse_name == 'ref':
                verse_type = VerseType.tags[VerseType.Chorus]
            elif temp_verse_name == 'r':
                verse_type = VerseType.tags[VerseType.Chorus]
            elif temp_verse_name == '':
                verse_type = VerseType.tags[VerseType.Verse]
            elif temp_verse_name == 'v':
                verse_type = VerseType.tags[VerseType.Verse]
            elif temp_verse_name == 'bri':
                verse_type = VerseType.tags[VerseType.Bridge]
            elif temp_verse_name == 'cod':
                verse_type = VerseType.tags[VerseType.Ending]
            elif temp_verse_name == 'sch':
                verse_type = VerseType.tags[VerseType.Ending]
            elif temp_verse_name == 'pre':
                verse_type = VerseType.tags[VerseType.PreChorus]
            elif temp_verse_name == 'int':
                verse_type = VerseType.tags[VerseType.Intro]
            else:
                verse_type = VerseType.tags[VerseType.Other]
            verse_number = re.compile('[a-zA-Z.+-_ ]*').sub('', verse_name)
            # Foilpresenter allows e. g. "C", but we need "C1".
            if not verse_number:
                verse_number = str(verse_count[verse_type])
                verse_count[verse_type] += 1
            else:
                # test if foilpresenter have the same versenumber two times with
                # different parts raise the verse number
                for value in temp_verse_order_backup:
                    if value == ''.join((verse_type, verse_number)):
                        verse_number = str(int(verse_number) + 1)
            verse_type_index = VerseType.from_tag(verse_type[0])
            verse_type = VerseType.tags[verse_type_index]
            temp_verse_order[verse_sortnr] = ''.join((verse_type[0], verse_number))
            temp_verse_order_backup.append(''.join((verse_type[0], verse_number)))
            sxml.add_verse_to_lyrics(verse_type, verse_number, text)
        song.lyrics = str(sxml.extract_xml(), 'utf-8')
        # Process verse order
        verse_order = []
        verse_strophenr = []
        try:
            for strophennummer in foilpresenterfolie.reihenfolge.strophennummer:
                verse_strophenr.append(strophennummer)
        except AttributeError:
            pass
        # Currently we do not support different "parts"!
        if '0' in temp_verse_order:
            for vers in temp_verse_order_backup:
                verse_order.append(vers)
        else:
            for number in verse_strophenr:
                numberx = temp_sortnr_liste[int(number)]
                verse_order.append(temp_verse_order[str(numberx)])
        song.verse_order = ' '.join(verse_order)
예제 #19
0
    def load_song(self, song_id, preview=False):
        """
        Loads a song.

        ``song_id``
            The song id (int).

        ``preview``
            Should be ``True`` if the song is also previewed (boolean).
        """
        log.debug('Load Song')
        self.initialise()
        self.song_tab_widget.setCurrentIndex(0)
        self.load_authors()
        self.load_topics()
        self.load_books()
        self.load_media_files()
        self.song = self.manager.get_object(Song, song_id)
        self.title_edit.setText(self.song.title)
        self.alternative_edit.setText(
            self.song.alternate_title if self.song.alternate_title else '')
        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.song_book_combo_box, str(book_name.name))
        else:
            self.song_book_combo_box.setEditText('')
            self.song_book_combo_box.setCurrentIndex(0)
        if self.song.theme_name:
            find_and_set_in_combo_box(self.theme_combo_box, str(self.song.theme_name))
        else:
            # Clear the theme combo box in case it was previously set (bug #1212801)
            self.theme_combo_box.setEditText('')
            self.theme_combo_box.setCurrentIndex(0)
        self.copyright_edit.setText(self.song.copyright if self.song.copyright else '')
        self.comments_edit.setPlainText(self.song.comments if self.song.comments else '')
        self.ccli_number_edit.setText(self.song.ccli_number if self.song.ccli_number else '')
        self.song_book_number_edit.setText(self.song.song_number if self.song.song_number else '')
        # lazy xml migration for now
        self.verse_list_widget.clear()
        self.verse_list_widget.setRowCount(0)
        verse_tags_translated = False
        if self.song.lyrics.startswith('<?xml version='):
            songXML = SongXML()
            verse_list = songXML.get_verses(self.song.lyrics)
            for count, verse in enumerate(verse_list):
                self.verse_list_widget.setRowCount(self.verse_list_widget.rowCount() + 1)
                # This silently migrates from localized verse type markup.
                # If we trusted the database, this would be unnecessary.
                verse_tag = verse[0]['type']
                index = None
                if len(verse_tag) > 1:
                    index = VerseType.from_translated_string(verse_tag)
                    if index is None:
                        index = VerseType.from_string(verse_tag, None)
                    else:
                        verse_tags_translated = True
                if index is None:
                    index = VerseType.from_tag(verse_tag)
                verse[0]['type'] = VerseType.tags[index]
                if verse[0]['label'] == '':
                    verse[0]['label'] = '1'
                verse_def = '%s%s' % (verse[0]['type'], verse[0]['label'])
                item = QtGui.QTableWidgetItem(verse[1])
                item.setData(QtCore.Qt.UserRole, verse_def)
                self.verse_list_widget.setItem(count, 0, item)
        else:
            verses = self.song.lyrics.split('\n\n')
            for count, verse in enumerate(verses):
                self.verse_list_widget.setRowCount(self.verse_list_widget.rowCount() + 1)
                item = QtGui.QTableWidgetItem(verse)
                verse_def = '%s%s' % (VerseType.tags[VerseType.Verse], str(count + 1))
                item.setData(QtCore.Qt.UserRole, verse_def)
                self.verse_list_widget.setItem(count, 0, item)
        if self.song.verse_order:
            # we translate verse order
            translated = []
            for verse_def in self.song.verse_order.split():
                verse_index = None
                if verse_tags_translated:
                    verse_index = VerseType.from_translated_tag(verse_def[0], None)
                if verse_index is None:
                    verse_index = VerseType.from_tag(verse_def[0])
                verse_tag = VerseType.translated_tags[verse_index].upper()
                translated.append('%s%s' % (verse_tag, verse_def[1:]))
            self.verse_order_edit.setText(' '.join(translated))
        else:
            self.verse_order_edit.setText('')
        self.tag_rows()
        # clear the results
        self.authors_list_view.clear()
        for author in self.song.authors:
            author_name = QtGui.QListWidgetItem(str(author.display_name))
            author_name.setData(QtCore.Qt.UserRole, author.id)
            self.authors_list_view.addItem(author_name)
        # clear the results
        self.topics_list_view.clear()
        for topic in self.song.topics:
            topic_name = QtGui.QListWidgetItem(str(topic.name))
            topic_name.setData(QtCore.Qt.UserRole, topic.id)
            self.topics_list_view.addItem(topic_name)
        self.audio_list_widget.clear()
        for media in self.song.media_files:
            media_file = QtGui.QListWidgetItem(os.path.split(media.file_name)[1])
            media_file.setData(QtCore.Qt.UserRole, media.file_name)
            self.audio_list_widget.addItem(media_file)
        self.title_edit.setFocus()
        # Hide or show the preview button.
        self.preview_button.setVisible(preview)
        # Check if all verse tags are used.
        self.on_verse_order_text_changed(self.verse_order_edit.text())
예제 #20
0
 def do_import_file(self, file):
     """
     Process the OpenSong file - pass in a file-like object, not a file path.
     """
     self.set_defaults()
     try:
         tree = objectify.parse(file)
     except (Error, LxmlError):
         self.log_error(file.name, SongStrings.XMLSyntaxError)
         log.exception('Error parsing XML')
         return
     root = tree.getroot()
     if root.tag != 'song':
         self.log_error(file.name, str(
             translate('SongsPlugin.OpenSongImport', 'Invalid OpenSong song file. Missing song tag.')))
         return
     fields = dir(root)
     decode = {
         'copyright': self.add_copyright,
         'ccli': 'ccli_number',
         'author': self.parse_author,
         'title': 'title',
         'aka': 'alternate_title',
         'hymn_number': self.parse_song_book_name_and_number,
         'user1': self.add_comment,
         'user2': self.add_comment,
         'user3': self.add_comment
     }
     for attr, fn_or_string in list(decode.items()):
         if attr in fields:
             ustring = str(root.__getattr__(attr))
             if isinstance(fn_or_string, str):
                 if attr in ['ccli']:
                     if ustring:
                         setattr(self, fn_or_string, int(ustring))
                     else:
                         setattr(self, fn_or_string, None)
                 else:
                     setattr(self, fn_or_string, ustring)
             else:
                 fn_or_string(ustring)
     # Themes look like "God: Awe/Wonder", but we just want
     # "Awe" and "Wonder".  We use a set to ensure each topic
     # is only added once, in case it is already there, which
     # is actually quite likely if the alttheme is set
     topics = set(self.topics)
     if 'theme' in fields:
         theme = str(root.theme)
         subthemes = theme[theme.find(':')+1:].split('/')
         for topic in subthemes:
             topics.add(topic.strip())
     if 'alttheme' in fields:
         theme = str(root.alttheme)
         subthemes = theme[theme.find(':')+1:].split('/')
         for topic in subthemes:
             topics.add(topic.strip())
     self.topics = list(topics)
     self.topics.sort()
     # data storage while importing
     verses = {}
     # keep track of verses appearance order
     our_verse_order = []
     # default verse
     verse_tag = VerseType.tags[VerseType.Verse]
     verse_num = '1'
     # for the case where song has several sections with same marker
     inst = 1
     if 'lyrics' in fields:
         lyrics = str(root.lyrics)
     else:
         lyrics = ''
     for this_line in lyrics.split('\n'):
         if not this_line.strip():
             continue
         # skip this line if it is a comment
         if this_line.startswith(';'):
             continue
         # skip guitar chords and page and column breaks
         if this_line.startswith('.') or this_line.startswith('---') or this_line.startswith('-!!'):
             continue
         # verse/chorus/etc. marker
         if this_line.startswith('['):
             # drop the square brackets
             right_bracket = this_line.find(']')
             content = this_line[1:right_bracket].lower()
             # have we got any digits? If so, verse number is everything from the digits to the end (openlp does not
             # have concept of part verses, so just ignore any non integers on the end (including floats))
             match = re.match('(\D*)(\d+)', content)
             if match is not None:
                 verse_tag = match.group(1)
                 verse_num = match.group(2)
             else:
                 # otherwise we assume number 1 and take the whole prefix as the verse tag
                 verse_tag = content
                 verse_num = '1'
             verse_index = VerseType.from_loose_input(verse_tag) if verse_tag else 0
             verse_tag = VerseType.tags[verse_index]
             inst = 1
             if [verse_tag, verse_num, inst] in our_verse_order and verse_num in verses.get(verse_tag, {}):
                 inst = len(verses[verse_tag][verse_num]) + 1
             continue
         # number at start of line.. it's verse number
         if this_line[0].isdigit():
             verse_num = this_line[0]
             this_line = this_line[1:].strip()
         verses.setdefault(verse_tag, {})
         verses[verse_tag].setdefault(verse_num, {})
         if inst not in verses[verse_tag][verse_num]:
             verses[verse_tag][verse_num][inst] = []
             our_verse_order.append([verse_tag, verse_num, inst])
         # Tidy text and remove the ____s from extended words
         this_line = self.tidy_text(this_line)
         this_line = this_line.replace('_', '')
         this_line = this_line.replace('||', '\n[---]\n')
         this_line = this_line.strip()
         # If the line consists solely of a '|', then just use the implicit newline
         # Otherwise, add a newline for each '|'
         if this_line == '|':
             this_line = ''
         else:
             this_line = this_line.replace('|', '\n')
         verses[verse_tag][verse_num][inst].append(this_line)
     # done parsing
     # add verses in original order
     verse_joints = {}
     for (verse_tag, verse_num, inst) in our_verse_order:
         lines = '\n'.join(verses[verse_tag][verse_num][inst])
         length = 0
         while length < len(verse_num) and verse_num[length].isnumeric():
             length += 1
         verse_def = '%s%s' % (verse_tag, verse_num[:length])
         verse_joints[verse_def] = '%s\n[---]\n%s' % (verse_joints[verse_def], lines) \
             if verse_def in verse_joints else lines
     # Parsing the dictionary produces the elements in a non-intuitive order.  While it "works", it's not a
     # natural layout should the user come back to edit the song.  Instead we sort by the verse type, so that we
     # get all the verses in order (v1, v2, ...), then the chorus(es), bridge(s), pre-chorus(es) etc.  We use a
     # tuple for the key, since tuples naturally sort in this manner.
     verse_defs = sorted(verse_joints.keys(),
                         key=lambda verse_def: (VerseType.from_tag(verse_def[0]), int(verse_def[1:])))
     for verse_def in verse_defs:
         lines = verse_joints[verse_def]
         self.add_verse(lines, verse_def)
     if not self.verses:
         self.add_verse('')
     # figure out the presentation order, if present
     if 'presentation' in fields and root.presentation:
         order = str(root.presentation)
         # We make all the tags in the lyrics lower case, so match that here and then split into a list on the
         # whitespace.
         order = order.lower().split()
         for verse_def in order:
             match = re.match('(\D*)(\d+.*)', verse_def)
             if match is not None:
                 verse_tag = match.group(1)
                 verse_num = match.group(2)
                 if not verse_tag:
                     verse_tag = VerseType.tags[VerseType.Verse]
             else:
                 # Assume it's no.1 if there are no digits
                 verse_tag = verse_def
                 verse_num = '1'
             verse_index = VerseType.from_loose_input(verse_tag)
             verse_tag = VerseType.tags[verse_index]
             verse_def = '%s%s' % (verse_tag, verse_num)
             if verse_num in verses.get(verse_tag, {}):
                 self.verse_order_list.append(verse_def)
             else:
                 log.info('Got order %s but not in verse tags, dropping this item from presentation order',
                          verse_def)
     if not self.finish():
         self.log_error(file.name)
예제 #21
0
    def generate_slide_data(self, service_item, item=None, xml_version=False, remote=False,
                            context=ServiceItemContext.Service):
        """
        Generate the slide data. Needs to be implemented by the plugin.

        :param service_item: The service item to be built on
        :param item: The Song item to be used
        :param xml_version: The xml version (not used)
        :param remote: Triggered from remote
        :param context: Why is it being generated
        """
        log.debug('generate_slide_data: %s, %s, %s' % (service_item, item, self.remote_song))
        item_id = self._get_id_of_item_to_generate(item, self.remote_song)
        service_item.add_capability(ItemCapabilities.CanEdit)
        service_item.add_capability(ItemCapabilities.CanPreview)
        service_item.add_capability(ItemCapabilities.CanLoop)
        service_item.add_capability(ItemCapabilities.OnLoadUpdate)
        service_item.add_capability(ItemCapabilities.AddIfNewItem)
        service_item.add_capability(ItemCapabilities.CanSoftBreak)
        song = self.plugin.manager.get_object(Song, item_id)
        service_item.theme = song.theme_name
        service_item.edit_id = item_id
        verse_list = SongXML().get_verses(song.lyrics)
        # no verse list or only 1 space (in error)
        verse_tags_translated = False
        if VerseType.from_translated_string(str(verse_list[0][0]['type'])) is not None:
            verse_tags_translated = True
        if not song.verse_order.strip():
            for verse in verse_list:
                # We cannot use from_loose_input() here, because database is supposed to contain English lowercase
                # singlechar tags.
                verse_tag = verse[0]['type']
                verse_index = None
                if len(verse_tag) > 1:
                    verse_index = VerseType.from_translated_string(verse_tag)
                    if verse_index is None:
                        verse_index = VerseType.from_string(verse_tag, None)
                if verse_index is None:
                    verse_index = VerseType.from_tag(verse_tag)
                verse_tag = VerseType.translated_tags[verse_index].upper()
                verse_def = '%s%s' % (verse_tag, verse[0]['label'])
                service_item.add_from_text(str(verse[1]), verse_def)
        else:
            # Loop through the verse list and expand the song accordingly.
            for order in song.verse_order.lower().split():
                if not order:
                    break
                for verse in verse_list:
                    if verse[0]['type'][0].lower() == \
                            order[0] and (verse[0]['label'].lower() == order[1:] or not order[1:]):
                        if verse_tags_translated:
                            verse_index = VerseType.from_translated_tag(verse[0]['type'])
                        else:
                            verse_index = VerseType.from_tag(verse[0]['type'])
                        verse_tag = VerseType.translated_tags[verse_index]
                        verse_def = '%s%s' % (verse_tag, verse[0]['label'])
                        service_item.add_from_text(verse[1], verse_def)
        service_item.title = song.title
        author_list = self.generate_footer(service_item, song)
        service_item.data_string = {'title': song.search_title, 'authors': ', '.join(author_list)}
        service_item.set_extra_data_dict(self.open_lyrics.song_to_line_dict(song))
        service_item.xml_version = self.open_lyrics.song_to_xml(song)
        # Add the audio file to the service item.
        if song.media_files:
            service_item.add_capability(ItemCapabilities.HasBackgroundAudio)
            service_item.background_audio = [m.file_name for m in song.media_files]
        return True