Status: | Merged |
---|---|
Merged at revision: | 2777 |
Proposed branch: | lp:~trb143/openlp/splitter |
Merge into: | lp:openlp |
Diff against target: |
412 lines (+122/-60) 10 files modified
openlp/core/common/uistrings.py (+1/-1) openlp/core/lib/renderer.py (+3/-0) openlp/core/ui/lib/listpreviewwidget.py (+5/-5) openlp/plugins/songs/forms/duplicatesongremovalform.py (+1/-2) openlp/plugins/songs/forms/editversedialog.py (+13/-6) openlp/plugins/songs/forms/editverseform.py (+24/-9) openlp/plugins/songs/lib/__init__.py (+34/-33) openlp/plugins/songs/lib/mediaitem.py (+7/-3) openlp/plugins/songs/lib/openlyricsxml.py (+6/-1) tests/functional/openlp_plugins/songs/test_editverseform.py (+28/-0) |
To merge this branch: | bzr merge lp:~trb143/openlp/splitter |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Raoul Snyman | Approve | ||
Tomas Groth | Pending | ||
Review via email: mp+331629@code.launchpad.net |
This proposal supersedes a proposal from 2017-09-30.
Commit message
Description of the change
Add option to add a split to a song
This will split the verse when added to the service but keep the verse together for editing.
Useful for the 10 line hymn verses which need 2 slides to display.
Fix some iffy spelling
lp:~trb143/openlp/splitter (revision 2738)
[SUCCESS] https:/
[SUCCESS] https:/
[SUCCESS] https:/
[SUCCESS] https:/
[SUCCESS] https:/
[SUCCESS] https:/
[FAILURE] https:/
Raoul Snyman (raoul-snyman) wrote : Posted in a previous version of this proposal | # |
Tomas Groth (tomasgroth) wrote : Posted in a previous version of this proposal | # |
The openlyrics export does handle the new spilt, which I believe it should. The import should of course also be able to restore it. I'll admit I'm not sure how it should be done...
Raoul Snyman (raoul-snyman) wrote : Posted in a previous version of this proposal | # |
Let's call the buttons "Overflow Split" and "Forced Split"
Tomas Groth (tomasgroth) wrote : Posted in a previous version of this proposal | # |
The openlyrics import/export still needs to handle the new spilt...
Raoul Snyman (raoul-snyman) wrote : | # |
I would prefer a different splitter, but that is just personal preference. Other than that, this looks fine to me.
Also, I'm not entirely sure that the <p> tag is a valid element in OpenLyrics, but let's roll with it and we can always sort out OpenLyrics later.
Preview Diff
1 | === modified file 'openlp/core/common/uistrings.py' | |||
2 | --- openlp/core/common/uistrings.py 2017-09-06 21:36:31 +0000 | |||
3 | +++ openlp/core/common/uistrings.py 2017-10-01 20:11:51 +0000 | |||
4 | @@ -147,7 +147,7 @@ | |||
5 | 147 | self.SaveService = translate('OpenLP.Ui', 'Save Service') | 147 | self.SaveService = translate('OpenLP.Ui', 'Save Service') |
6 | 148 | self.Service = translate('OpenLP.Ui', 'Service') | 148 | self.Service = translate('OpenLP.Ui', 'Service') |
7 | 149 | self.ShortResults = translate('OpenLP.Ui', 'Please type more text to use \'Search As You Type\'') | 149 | self.ShortResults = translate('OpenLP.Ui', 'Please type more text to use \'Search As You Type\'') |
9 | 150 | self.Split = translate('OpenLP.Ui', 'Optional &Split') | 150 | self.Split = translate('OpenLP.Ui', 'Overflow &Split') |
10 | 151 | self.SplitToolTip = translate('OpenLP.Ui', | 151 | self.SplitToolTip = translate('OpenLP.Ui', |
11 | 152 | 'Split a slide into two only if it does not fit on the screen as one slide.') | 152 | 'Split a slide into two only if it does not fit on the screen as one slide.') |
12 | 153 | self.StartingImport = translate('OpenLP.Ui', 'Starting import...') | 153 | self.StartingImport = translate('OpenLP.Ui', 'Starting import...') |
13 | 154 | 154 | ||
14 | === modified file 'openlp/core/lib/renderer.py' | |||
15 | --- openlp/core/lib/renderer.py 2017-09-26 16:39:13 +0000 | |||
16 | +++ openlp/core/lib/renderer.py 2017-10-01 20:11:51 +0000 | |||
17 | @@ -243,6 +243,9 @@ | |||
18 | 243 | elif item.is_capable(ItemCapabilities.CanSoftBreak): | 243 | elif item.is_capable(ItemCapabilities.CanSoftBreak): |
19 | 244 | pages = [] | 244 | pages = [] |
20 | 245 | if '[---]' in text: | 245 | if '[---]' in text: |
21 | 246 | # Remove Overflow split if at start of the text | ||
22 | 247 | if text.startswith('[---]'): | ||
23 | 248 | text = text[5:] | ||
24 | 246 | # Remove two or more option slide breaks next to each other (causing infinite loop). | 249 | # Remove two or more option slide breaks next to each other (causing infinite loop). |
25 | 247 | while '\n[---]\n[---]\n' in text: | 250 | while '\n[---]\n[---]\n' in text: |
26 | 248 | text = text.replace('\n[---]\n[---]\n', '\n[---]\n') | 251 | text = text.replace('\n[---]\n[---]\n', '\n[---]\n') |
27 | 249 | 252 | ||
28 | === modified file 'openlp/core/ui/lib/listpreviewwidget.py' | |||
29 | --- openlp/core/ui/lib/listpreviewwidget.py 2016-12-31 11:01:36 +0000 | |||
30 | +++ openlp/core/ui/lib/listpreviewwidget.py 2017-10-01 20:11:51 +0000 | |||
31 | @@ -209,21 +209,21 @@ | |||
32 | 209 | Switches to the given row. | 209 | Switches to the given row. |
33 | 210 | """ | 210 | """ |
34 | 211 | # Retrieve setting | 211 | # Retrieve setting |
36 | 212 | autoscrolling = Settings().value('advanced/autoscrolling') | 212 | auto_scrolling = Settings().value('advanced/autoscrolling') |
37 | 213 | # Check if auto-scroll disabled (None) and validate value as dict containing 'dist' and 'pos' | 213 | # Check if auto-scroll disabled (None) and validate value as dict containing 'dist' and 'pos' |
38 | 214 | # 'dist' represents the slide to scroll to relative to the new slide (-1 = previous, 0 = current, 1 = next) | 214 | # 'dist' represents the slide to scroll to relative to the new slide (-1 = previous, 0 = current, 1 = next) |
39 | 215 | # 'pos' represents the vert position of of the slide (0 = in view, 1 = top, 2 = middle, 3 = bottom) | 215 | # 'pos' represents the vert position of of the slide (0 = in view, 1 = top, 2 = middle, 3 = bottom) |
42 | 216 | if not (isinstance(autoscrolling, dict) and 'dist' in autoscrolling and 'pos' in autoscrolling and | 216 | if not (isinstance(auto_scrolling, dict) and 'dist' in auto_scrolling and 'pos' in auto_scrolling and |
43 | 217 | isinstance(autoscrolling['dist'], int) and isinstance(autoscrolling['pos'], int)): | 217 | isinstance(auto_scrolling['dist'], int) and isinstance(auto_scrolling['pos'], int)): |
44 | 218 | return | 218 | return |
45 | 219 | # prevent scrolling past list bounds | 219 | # prevent scrolling past list bounds |
47 | 220 | scroll_to_slide = slide + autoscrolling['dist'] | 220 | scroll_to_slide = slide + auto_scrolling['dist'] |
48 | 221 | if scroll_to_slide < 0: | 221 | if scroll_to_slide < 0: |
49 | 222 | scroll_to_slide = 0 | 222 | scroll_to_slide = 0 |
50 | 223 | if scroll_to_slide >= self.slide_count(): | 223 | if scroll_to_slide >= self.slide_count(): |
51 | 224 | scroll_to_slide = self.slide_count() - 1 | 224 | scroll_to_slide = self.slide_count() - 1 |
52 | 225 | # Scroll to item if possible. | 225 | # Scroll to item if possible. |
54 | 226 | self.scrollToItem(self.item(scroll_to_slide, 0), autoscrolling['pos']) | 226 | self.scrollToItem(self.item(scroll_to_slide, 0), auto_scrolling['pos']) |
55 | 227 | self.selectRow(slide) | 227 | self.selectRow(slide) |
56 | 228 | 228 | ||
57 | 229 | def current_slide_number(self): | 229 | def current_slide_number(self): |
58 | 230 | 230 | ||
59 | === modified file 'openlp/plugins/songs/forms/duplicatesongremovalform.py' | |||
60 | --- openlp/plugins/songs/forms/duplicatesongremovalform.py 2017-06-09 06:06:49 +0000 | |||
61 | +++ openlp/plugins/songs/forms/duplicatesongremovalform.py 2017-10-01 20:11:51 +0000 | |||
62 | @@ -25,14 +25,13 @@ | |||
63 | 25 | 25 | ||
64 | 26 | import logging | 26 | import logging |
65 | 27 | import multiprocessing | 27 | import multiprocessing |
66 | 28 | import os | ||
67 | 29 | 28 | ||
68 | 30 | from PyQt5 import QtCore, QtWidgets | 29 | from PyQt5 import QtCore, QtWidgets |
69 | 31 | 30 | ||
70 | 32 | from openlp.core.common import Registry, RegistryProperties, translate | 31 | from openlp.core.common import Registry, RegistryProperties, translate |
71 | 33 | from openlp.core.ui.lib.wizard import OpenLPWizard, WizardStrings | 32 | from openlp.core.ui.lib.wizard import OpenLPWizard, WizardStrings |
72 | 34 | from openlp.plugins.songs.lib import delete_song | 33 | from openlp.plugins.songs.lib import delete_song |
74 | 35 | from openlp.plugins.songs.lib.db import Song, MediaFile | 34 | from openlp.plugins.songs.lib.db import Song |
75 | 36 | from openlp.plugins.songs.forms.songreviewwidget import SongReviewWidget | 35 | from openlp.plugins.songs.forms.songreviewwidget import SongReviewWidget |
76 | 37 | from openlp.plugins.songs.lib.songcompare import songs_probably_equal | 36 | from openlp.plugins.songs.lib.songcompare import songs_probably_equal |
77 | 38 | 37 | ||
78 | 39 | 38 | ||
79 | === modified file 'openlp/plugins/songs/forms/editversedialog.py' | |||
80 | --- openlp/plugins/songs/forms/editversedialog.py 2017-07-04 23:13:51 +0000 | |||
81 | +++ openlp/plugins/songs/forms/editversedialog.py 2017-10-01 20:11:51 +0000 | |||
82 | @@ -42,10 +42,14 @@ | |||
83 | 42 | self.dialog_layout.addWidget(self.verse_text_edit) | 42 | self.dialog_layout.addWidget(self.verse_text_edit) |
84 | 43 | self.verse_type_layout = QtWidgets.QHBoxLayout() | 43 | self.verse_type_layout = QtWidgets.QHBoxLayout() |
85 | 44 | self.verse_type_layout.setObjectName('verse_type_layout') | 44 | self.verse_type_layout.setObjectName('verse_type_layout') |
90 | 45 | self.split_button = QtWidgets.QPushButton(edit_verse_dialog) | 45 | self.forced_split_button = QtWidgets.QPushButton(edit_verse_dialog) |
91 | 46 | self.split_button.setIcon(build_icon(':/general/general_add.png')) | 46 | self.forced_split_button.setIcon(build_icon(':/general/general_add.png')) |
92 | 47 | self.split_button.setObjectName('split_button') | 47 | self.forced_split_button.setObjectName('forced_split_button') |
93 | 48 | self.verse_type_layout.addWidget(self.split_button) | 48 | self.verse_type_layout.addWidget(self.forced_split_button) |
94 | 49 | self.overflow_split_button = QtWidgets.QPushButton(edit_verse_dialog) | ||
95 | 50 | self.overflow_split_button.setIcon(build_icon(':/general/general_add.png')) | ||
96 | 51 | self.overflow_split_button.setObjectName('overflow_split_button') | ||
97 | 52 | self.verse_type_layout.addWidget(self.overflow_split_button) | ||
98 | 49 | self.verse_type_label = QtWidgets.QLabel(edit_verse_dialog) | 53 | self.verse_type_label = QtWidgets.QLabel(edit_verse_dialog) |
99 | 50 | self.verse_type_label.setObjectName('verse_type_label') | 54 | self.verse_type_label.setObjectName('verse_type_label') |
100 | 51 | self.verse_type_layout.addWidget(self.verse_type_label) | 55 | self.verse_type_layout.addWidget(self.verse_type_label) |
101 | @@ -93,8 +97,11 @@ | |||
102 | 93 | self.verse_type_combo_box.setItemText(VerseType.Intro, VerseType.translated_names[VerseType.Intro]) | 97 | self.verse_type_combo_box.setItemText(VerseType.Intro, VerseType.translated_names[VerseType.Intro]) |
103 | 94 | self.verse_type_combo_box.setItemText(VerseType.Ending, VerseType.translated_names[VerseType.Ending]) | 98 | self.verse_type_combo_box.setItemText(VerseType.Ending, VerseType.translated_names[VerseType.Ending]) |
104 | 95 | self.verse_type_combo_box.setItemText(VerseType.Other, VerseType.translated_names[VerseType.Other]) | 99 | self.verse_type_combo_box.setItemText(VerseType.Other, VerseType.translated_names[VerseType.Other]) |
107 | 96 | self.split_button.setText(UiStrings().Split) | 100 | self.overflow_split_button.setText(UiStrings().Split) |
108 | 97 | self.split_button.setToolTip(UiStrings().SplitToolTip) | 101 | self.overflow_split_button.setToolTip(UiStrings().SplitToolTip) |
109 | 102 | self.forced_split_button.setText(translate('SongsPlugin.EditVerseForm', '&Forced Split')) | ||
110 | 103 | self.forced_split_button.setToolTip(translate('SongsPlugin.EditVerseForm', 'Split the verse when displayed ' | ||
111 | 104 | 'regardless of the screen size.')) | ||
112 | 98 | self.insert_button.setText(translate('SongsPlugin.EditVerseForm', '&Insert')) | 105 | self.insert_button.setText(translate('SongsPlugin.EditVerseForm', '&Insert')) |
113 | 99 | self.insert_button.setToolTip(translate('SongsPlugin.EditVerseForm', | 106 | self.insert_button.setToolTip(translate('SongsPlugin.EditVerseForm', |
114 | 100 | 'Split a slide into two by inserting a verse splitter.')) | 107 | 'Split a slide into two by inserting a verse splitter.')) |
115 | 101 | 108 | ||
116 | === modified file 'openlp/plugins/songs/forms/editverseform.py' | |||
117 | --- openlp/plugins/songs/forms/editverseform.py 2017-06-04 12:14:23 +0000 | |||
118 | +++ openlp/plugins/songs/forms/editverseform.py 2017-10-01 20:11:51 +0000 | |||
119 | @@ -48,12 +48,13 @@ | |||
120 | 48 | self.setupUi(self) | 48 | self.setupUi(self) |
121 | 49 | self.has_single_verse = False | 49 | self.has_single_verse = False |
122 | 50 | self.insert_button.clicked.connect(self.on_insert_button_clicked) | 50 | self.insert_button.clicked.connect(self.on_insert_button_clicked) |
124 | 51 | self.split_button.clicked.connect(self.on_split_button_clicked) | 51 | self.overflow_split_button.clicked.connect(self.on_overflow_split_button_clicked) |
125 | 52 | self.verse_text_edit.cursorPositionChanged.connect(self.on_cursor_position_changed) | 52 | self.verse_text_edit.cursorPositionChanged.connect(self.on_cursor_position_changed) |
126 | 53 | self.verse_type_combo_box.currentIndexChanged.connect(self.on_verse_type_combo_box_changed) | 53 | self.verse_type_combo_box.currentIndexChanged.connect(self.on_verse_type_combo_box_changed) |
127 | 54 | self.forced_split_button.clicked.connect(self.on_forced_split_button_clicked) | ||
128 | 54 | if Settings().value('songs/enable chords'): | 55 | if Settings().value('songs/enable chords'): |
131 | 55 | self.transpose_down_button.clicked.connect(self.on_transepose_down_button_clicked) | 56 | self.transpose_down_button.clicked.connect(self.on_transpose_down_button_clicked) |
132 | 56 | self.transpose_up_button.clicked.connect(self.on_transepose_up_button_clicked) | 57 | self.transpose_up_button.clicked.connect(self.on_transpose_up_button_clicked) |
133 | 57 | 58 | ||
134 | 58 | def insert_verse(self, verse_tag, verse_num=1): | 59 | def insert_verse(self, verse_tag, verse_num=1): |
135 | 59 | """ | 60 | """ |
136 | @@ -68,13 +69,27 @@ | |||
137 | 68 | self.verse_text_edit.insertPlainText('---[{tag}:{number}]---\n'.format(tag=verse_tag, number=verse_num)) | 69 | self.verse_text_edit.insertPlainText('---[{tag}:{number}]---\n'.format(tag=verse_tag, number=verse_num)) |
138 | 69 | self.verse_text_edit.setFocus() | 70 | self.verse_text_edit.setFocus() |
139 | 70 | 71 | ||
143 | 71 | def on_split_button_clicked(self): | 72 | def on_overflow_split_button_clicked(self): |
144 | 72 | """ | 73 | """ |
145 | 73 | The split button has been pressed | 74 | The optional split button has been pressed so we need add the split |
146 | 75 | """ | ||
147 | 76 | self._add_splitter_to_text('[---]') | ||
148 | 77 | |||
149 | 78 | def on_forced_split_button_clicked(self): | ||
150 | 79 | """ | ||
151 | 80 | The force split button has been pressed so we need add the split | ||
152 | 81 | """ | ||
153 | 82 | self._add_splitter_to_text('[--}{--]') | ||
154 | 83 | |||
155 | 84 | def _add_splitter_to_text(self, insert_string): | ||
156 | 85 | """ | ||
157 | 86 | Add a custom splitter to the song text | ||
158 | 87 | |||
159 | 88 | :param insert_string: The string to insert | ||
160 | 89 | :return: | ||
161 | 74 | """ | 90 | """ |
162 | 75 | text = self.verse_text_edit.toPlainText() | 91 | text = self.verse_text_edit.toPlainText() |
163 | 76 | position = self.verse_text_edit.textCursor().position() | 92 | position = self.verse_text_edit.textCursor().position() |
164 | 77 | insert_string = '[---]' | ||
165 | 78 | if position and text[position - 1] != '\n': | 93 | if position and text[position - 1] != '\n': |
166 | 79 | insert_string = '\n' + insert_string | 94 | insert_string = '\n' + insert_string |
167 | 80 | if position == len(text) or text[position] != '\n': | 95 | if position == len(text) or text[position] != '\n': |
168 | @@ -101,7 +116,7 @@ | |||
169 | 101 | """ | 116 | """ |
170 | 102 | self.update_suggested_verse_number() | 117 | self.update_suggested_verse_number() |
171 | 103 | 118 | ||
173 | 104 | def on_transepose_up_button_clicked(self): | 119 | def on_transpose_up_button_clicked(self): |
174 | 105 | """ | 120 | """ |
175 | 106 | The transpose up button clicked | 121 | The transpose up button clicked |
176 | 107 | """ | 122 | """ |
177 | @@ -118,7 +133,7 @@ | |||
178 | 118 | self.verse_text_edit.setFocus() | 133 | self.verse_text_edit.setFocus() |
179 | 119 | self.verse_text_edit.moveCursor(QtGui.QTextCursor.End) | 134 | self.verse_text_edit.moveCursor(QtGui.QTextCursor.End) |
180 | 120 | 135 | ||
182 | 121 | def on_transepose_down_button_clicked(self): | 136 | def on_transpose_down_button_clicked(self): |
183 | 122 | """ | 137 | """ |
184 | 123 | The transpose down button clicked | 138 | The transpose down button clicked |
185 | 124 | """ | 139 | """ |
186 | 125 | 140 | ||
187 | === modified file 'openlp/plugins/songs/lib/__init__.py' | |||
188 | --- openlp/plugins/songs/lib/__init__.py 2017-09-30 20:16:30 +0000 | |||
189 | +++ openlp/plugins/songs/lib/__init__.py 2017-10-01 20:11:51 +0000 | |||
190 | @@ -546,12 +546,12 @@ | |||
191 | 546 | song_plugin.manager.delete_object(Song, song_id) | 546 | song_plugin.manager.delete_object(Song, song_id) |
192 | 547 | 547 | ||
193 | 548 | 548 | ||
195 | 549 | def transpose_lyrics(lyrics, transepose_value): | 549 | def transpose_lyrics(lyrics, transpose_value): |
196 | 550 | """ | 550 | """ |
198 | 551 | Transepose lyrics | 551 | Transpose lyrics |
199 | 552 | 552 | ||
202 | 553 | :param lyrcs: The lyrics to be transposed | 553 | :param lyrics: The lyrics to be transposed |
203 | 554 | :param transepose_value: The value to transpose the lyrics with | 554 | :param transpose_value: The value to transpose the lyrics with |
204 | 555 | :return: The transposed lyrics | 555 | :return: The transposed lyrics |
205 | 556 | """ | 556 | """ |
206 | 557 | # Split text by verse delimiter - both normal and optional | 557 | # Split text by verse delimiter - both normal and optional |
207 | @@ -562,16 +562,17 @@ | |||
208 | 562 | if verse.startswith('---[') or verse == '[---]': | 562 | if verse.startswith('---[') or verse == '[---]': |
209 | 563 | transposed_lyrics += verse | 563 | transposed_lyrics += verse |
210 | 564 | else: | 564 | else: |
212 | 565 | transposed_lyrics += transpose_verse(verse, transepose_value, notation) | 565 | transposed_lyrics += transpose_verse(verse, transpose_value, notation) |
213 | 566 | return transposed_lyrics | 566 | return transposed_lyrics |
214 | 567 | 567 | ||
215 | 568 | 568 | ||
217 | 569 | def transpose_verse(verse_text, transepose_value, notation): | 569 | def transpose_verse(verse_text, transpose_value, notation): |
218 | 570 | """ | 570 | """ |
220 | 571 | Transepose lyrics | 571 | Transpose Verse |
221 | 572 | 572 | ||
224 | 573 | :param lyrcs: The lyrics to be transposed | 573 | :param verse_text: The lyrics to be transposed |
225 | 574 | :param transepose_value: The value to transpose the lyrics with | 574 | :param transpose_value: The value to transpose the lyrics with |
226 | 575 | :param notation: which notation to use | ||
227 | 575 | :return: The transposed lyrics | 576 | :return: The transposed lyrics |
228 | 576 | """ | 577 | """ |
229 | 577 | if '[' not in verse_text: | 578 | if '[' not in verse_text: |
230 | @@ -589,11 +590,11 @@ | |||
231 | 589 | if word == ']': | 590 | if word == ']': |
232 | 590 | in_tag = False | 591 | in_tag = False |
233 | 591 | transposed_lyrics += word | 592 | transposed_lyrics += word |
235 | 592 | elif word == '/': | 593 | elif word == '/' or word == '--}{--': |
236 | 593 | transposed_lyrics += word | 594 | transposed_lyrics += word |
237 | 594 | else: | 595 | else: |
238 | 595 | # This MUST be a chord | 596 | # This MUST be a chord |
240 | 596 | transposed_lyrics += transpose_chord(word, transepose_value, notation) | 597 | transposed_lyrics += transpose_chord(word, transpose_value, notation) |
241 | 597 | # If still inside a chord tag something is wrong! | 598 | # If still inside a chord tag something is wrong! |
242 | 598 | if in_tag: | 599 | if in_tag: |
243 | 599 | return verse_text | 600 | return verse_text |
244 | @@ -629,36 +630,36 @@ | |||
245 | 629 | for i in range(0, len(chord_split)): | 630 | for i in range(0, len(chord_split)): |
246 | 630 | if i > 0: | 631 | if i > 0: |
247 | 631 | transposed_chord += '/' | 632 | transposed_chord += '/' |
250 | 632 | currentchord = chord_split[i] | 633 | current_chord = chord_split[i] |
251 | 633 | if currentchord and currentchord[0] == '(': | 634 | if current_chord and current_chord[0] == '(': |
252 | 634 | transposed_chord += '(' | 635 | transposed_chord += '(' |
255 | 635 | if len(currentchord) > 1: | 636 | if len(current_chord) > 1: |
256 | 636 | currentchord = currentchord[1:] | 637 | current_chord = current_chord[1:] |
257 | 637 | else: | 638 | else: |
264 | 638 | currentchord = '' | 639 | current_chord = '' |
265 | 639 | if len(currentchord) > 0: | 640 | if len(current_chord) > 0: |
266 | 640 | if len(currentchord) > 1: | 641 | if len(current_chord) > 1: |
267 | 641 | if '#b'.find(currentchord[1]) == -1: | 642 | if '#b'.find(current_chord[1]) == -1: |
268 | 642 | note = currentchord[0:1] | 643 | note = current_chord[0:1] |
269 | 643 | rest = currentchord[1:] | 644 | rest = current_chord[1:] |
270 | 644 | else: | 645 | else: |
273 | 645 | note = currentchord[0:2] | 646 | note = current_chord[0:2] |
274 | 646 | rest = currentchord[2:] | 647 | rest = current_chord[2:] |
275 | 647 | else: | 648 | else: |
277 | 648 | note = currentchord | 649 | note = current_chord |
278 | 649 | rest = '' | 650 | rest = '' |
285 | 650 | notenumber = notes_flat.index(note) if note not in notes_sharp else notes_sharp.index(note) | 651 | note_number = notes_flat.index(note) if note not in notes_sharp else notes_sharp.index(note) |
286 | 651 | notenumber += transpose_value | 652 | note_number += transpose_value |
287 | 652 | while notenumber > 11: | 653 | while note_number > 11: |
288 | 653 | notenumber -= 12 | 654 | note_number -= 12 |
289 | 654 | while notenumber < 0: | 655 | while note_number < 0: |
290 | 655 | notenumber += 12 | 656 | note_number += 12 |
291 | 656 | if i == 0: | 657 | if i == 0: |
294 | 657 | current_chord = notes_sharp[notenumber] if notes_preferred[notenumber] == '#' else notes_flat[ | 658 | current_chord = notes_sharp[note_number] if notes_preferred[note_number] == '#' else notes_flat[ |
295 | 658 | notenumber] | 659 | note_number] |
296 | 659 | last_chord = current_chord | 660 | last_chord = current_chord |
297 | 660 | else: | 661 | else: |
299 | 661 | current_chord = notes_flat[notenumber] if last_chord not in notes_sharp else notes_sharp[notenumber] | 662 | current_chord = notes_flat[note_number] if last_chord not in notes_sharp else notes_sharp[note_number] |
300 | 662 | if not (note not in notes_flat and note not in notes_sharp): | 663 | if not (note not in notes_flat and note not in notes_sharp): |
301 | 663 | transposed_chord += current_chord + rest | 664 | transposed_chord += current_chord + rest |
302 | 664 | else: | 665 | else: |
303 | 665 | 666 | ||
304 | === modified file 'openlp/plugins/songs/lib/mediaitem.py' | |||
305 | --- openlp/plugins/songs/lib/mediaitem.py 2017-09-30 20:16:30 +0000 | |||
306 | +++ openlp/plugins/songs/lib/mediaitem.py 2017-10-01 20:11:51 +0000 | |||
307 | @@ -577,7 +577,7 @@ | |||
308 | 577 | if not song.verse_order.strip(): | 577 | if not song.verse_order.strip(): |
309 | 578 | for verse in verse_list: | 578 | for verse in verse_list: |
310 | 579 | # We cannot use from_loose_input() here, because database is supposed to contain English lowercase | 579 | # We cannot use from_loose_input() here, because database is supposed to contain English lowercase |
312 | 580 | # singlechar tags. | 580 | # single char tags. |
313 | 581 | verse_tag = verse[0]['type'] | 581 | verse_tag = verse[0]['type'] |
314 | 582 | verse_index = None | 582 | verse_index = None |
315 | 583 | if len(verse_tag) > 1: | 583 | if len(verse_tag) > 1: |
316 | @@ -588,7 +588,9 @@ | |||
317 | 588 | verse_index = VerseType.from_tag(verse_tag) | 588 | verse_index = VerseType.from_tag(verse_tag) |
318 | 589 | verse_tag = VerseType.translated_tags[verse_index].upper() | 589 | verse_tag = VerseType.translated_tags[verse_index].upper() |
319 | 590 | verse_def = '{tag}{label}'.format(tag=verse_tag, label=verse[0]['label']) | 590 | verse_def = '{tag}{label}'.format(tag=verse_tag, label=verse[0]['label']) |
321 | 591 | service_item.add_from_text(str(verse[1]), verse_def) | 591 | force_verse = verse[1].split('[--}{--]\n') |
322 | 592 | for split_verse in force_verse: | ||
323 | 593 | service_item.add_from_text(split_verse, verse_def) | ||
324 | 592 | else: | 594 | else: |
325 | 593 | # Loop through the verse list and expand the song accordingly. | 595 | # Loop through the verse list and expand the song accordingly. |
326 | 594 | for order in song.verse_order.lower().split(): | 596 | for order in song.verse_order.lower().split(): |
327 | @@ -603,7 +605,9 @@ | |||
328 | 603 | verse_index = VerseType.from_tag(verse[0]['type']) | 605 | verse_index = VerseType.from_tag(verse[0]['type']) |
329 | 604 | verse_tag = VerseType.translated_tags[verse_index] | 606 | verse_tag = VerseType.translated_tags[verse_index] |
330 | 605 | verse_def = '{tag}{label}'.format(tag=verse_tag, label=verse[0]['label']) | 607 | verse_def = '{tag}{label}'.format(tag=verse_tag, label=verse[0]['label']) |
332 | 606 | service_item.add_from_text(verse[1], verse_def) | 608 | force_verse = verse[1].split('[--}{--]\n') |
333 | 609 | for split_verse in force_verse: | ||
334 | 610 | service_item.add_from_text(split_verse, verse_def) | ||
335 | 607 | service_item.title = song.title | 611 | service_item.title = song.title |
336 | 608 | author_list = self.generate_footer(service_item, song) | 612 | author_list = self.generate_footer(service_item, song) |
337 | 609 | service_item.data_string = {'title': song.search_title, 'authors': ', '.join(author_list)} | 613 | service_item.data_string = {'title': song.search_title, 'authors': ', '.join(author_list)} |
338 | 610 | 614 | ||
339 | === modified file 'openlp/plugins/songs/lib/openlyricsxml.py' | |||
340 | --- openlp/plugins/songs/lib/openlyricsxml.py 2017-09-13 06:08:38 +0000 | |||
341 | +++ openlp/plugins/songs/lib/openlyricsxml.py 2017-10-01 20:11:51 +0000 | |||
342 | @@ -71,6 +71,7 @@ | |||
343 | 71 | 71 | ||
344 | 72 | NAMESPACE = 'http://openlyrics.info/namespace/2009/song' | 72 | NAMESPACE = 'http://openlyrics.info/namespace/2009/song' |
345 | 73 | NSMAP = '{{' + NAMESPACE + '}}{tag}' | 73 | NSMAP = '{{' + NAMESPACE + '}}{tag}' |
346 | 74 | NEWPAGETAG = '<p style="page-break-after: always;"/>' | ||
347 | 74 | 75 | ||
348 | 75 | 76 | ||
349 | 76 | class SongXML(object): | 77 | class SongXML(object): |
350 | @@ -281,7 +282,7 @@ | |||
351 | 281 | tags_element = None | 282 | tags_element = None |
352 | 282 | match = re.search('\{/?\w+\}', song.lyrics, re.UNICODE) | 283 | match = re.search('\{/?\w+\}', song.lyrics, re.UNICODE) |
353 | 283 | if match: | 284 | if match: |
355 | 284 | # Named 'format_' - 'format' is built-in fuction in Python. | 285 | # Named 'format_' - 'format' is built-in function in Python. |
356 | 285 | format_ = etree.SubElement(song_xml, 'format') | 286 | format_ = etree.SubElement(song_xml, 'format') |
357 | 286 | tags_element = etree.SubElement(format_, 'tags') | 287 | tags_element = etree.SubElement(format_, 'tags') |
358 | 287 | tags_element.set('application', 'OpenLP') | 288 | tags_element.set('application', 'OpenLP') |
359 | @@ -472,6 +473,7 @@ | |||
360 | 472 | text = text.replace('{{/{tag}}}'.format(tag=tag), '</tag>') | 473 | text = text.replace('{{/{tag}}}'.format(tag=tag), '</tag>') |
361 | 473 | # Replace \n with <br/>. | 474 | # Replace \n with <br/>. |
362 | 474 | text = text.replace('\n', '<br/>') | 475 | text = text.replace('\n', '<br/>') |
363 | 476 | text = text.replace('[--}{--]', NEWPAGETAG) | ||
364 | 475 | element = etree.XML('<lines>{text}</lines>'.format(text=text)) | 477 | element = etree.XML('<lines>{text}</lines>'.format(text=text)) |
365 | 476 | verse_element.append(element) | 478 | verse_element.append(element) |
366 | 477 | return element | 479 | return element |
367 | @@ -634,6 +636,9 @@ | |||
368 | 634 | if element.tail: | 636 | if element.tail: |
369 | 635 | text += element.tail | 637 | text += element.tail |
370 | 636 | return text | 638 | return text |
371 | 639 | elif newlines and element.tag == NSMAP.format(tag='p') and 'page-break-after' in str(element.attrib): | ||
372 | 640 | text += '[--}{--]' | ||
373 | 641 | return text | ||
374 | 637 | # Start formatting tag. | 642 | # Start formatting tag. |
375 | 638 | if element.tag == NSMAP.format(tag='tag'): | 643 | if element.tag == NSMAP.format(tag='tag'): |
376 | 639 | text += '{{{name}}}'.format(name=element.get('name')) | 644 | text += '{{{name}}}'.format(name=element.get('name')) |
377 | 640 | 645 | ||
378 | === modified file 'tests/functional/openlp_plugins/songs/test_editverseform.py' | |||
379 | --- tests/functional/openlp_plugins/songs/test_editverseform.py 2017-05-30 20:06:27 +0000 | |||
380 | +++ tests/functional/openlp_plugins/songs/test_editverseform.py 2017-10-01 20:11:51 +0000 | |||
381 | @@ -72,3 +72,31 @@ | |||
382 | 72 | 72 | ||
383 | 73 | # THEN the verse number must not be changed | 73 | # THEN the verse number must not be changed |
384 | 74 | self.assertEqual(3, self.edit_verse_form.verse_number_box.value(), 'The verse number should be 3') | 74 | self.assertEqual(3, self.edit_verse_form.verse_number_box.value(), 'The verse number should be 3') |
385 | 75 | |||
386 | 76 | def test_on_divide_split_button_clicked(self): | ||
387 | 77 | """ | ||
388 | 78 | Test that divide adds text at the correct position | ||
389 | 79 | """ | ||
390 | 80 | # GIVEN some input values | ||
391 | 81 | self.edit_verse_form.verse_type_combo_box.currentIndex = MagicMock(return_value=4) | ||
392 | 82 | self.edit_verse_form.verse_text_edit.setPlainText('Text\n') | ||
393 | 83 | |||
394 | 84 | # WHEN the method is called | ||
395 | 85 | self.edit_verse_form.on_forced_split_button_clicked() | ||
396 | 86 | # THEN the verse number must not be changed | ||
397 | 87 | self.assertEqual('[--}{--]\nText\n', self.edit_verse_form.verse_text_edit.toPlainText(), | ||
398 | 88 | 'The verse number should be [--}{--]\nText\n') | ||
399 | 89 | |||
400 | 90 | def test_on_split_button_clicked(self): | ||
401 | 91 | """ | ||
402 | 92 | Test that divide adds text at the correct position | ||
403 | 93 | """ | ||
404 | 94 | # GIVEN some input values | ||
405 | 95 | self.edit_verse_form.verse_type_combo_box.currentIndex = MagicMock(return_value=4) | ||
406 | 96 | self.edit_verse_form.verse_text_edit.setPlainText('Text\n') | ||
407 | 97 | |||
408 | 98 | # WHEN the method is called | ||
409 | 99 | self.edit_verse_form.on_overflow_split_button_clicked() | ||
410 | 100 | # THEN the verse number must not be changed | ||
411 | 101 | self.assertEqual('[---]\nText\n', self.edit_verse_form.verse_text_edit.toPlainText(), | ||
412 | 102 | 'The verse number should be [---]\nText\n') |
As per IRC, mrs_fly's suggestion was "Auto Split" and "Force Split". I'm going to e-mail the mailing list and see what others think.