diff --git a/documentation/manual/source/glossary.rst b/documentation/manual/source/glossary.rst index 41a8f4ac6..6f4ebcdd6 100644 --- a/documentation/manual/source/glossary.rst +++ b/documentation/manual/source/glossary.rst @@ -48,7 +48,7 @@ Service Manger -------------- The service manager contains the media items in your service file. This is the -area from wich your media items go live, and you can also save, open, and edit +area from which your media items go live, and you can also save, open, and edit services files. .. image:: pics/servicemanager.png diff --git a/openlp/core/lib/renderer.py b/openlp/core/lib/renderer.py index 9b8b78818..68839f16d 100644 --- a/openlp/core/lib/renderer.py +++ b/openlp/core/lib/renderer.py @@ -32,7 +32,7 @@ import logging from PyQt4 import QtWebKit from openlp.core.lib import expand_tags, build_lyrics_format_css, \ - build_lyrics_outline_css + build_lyrics_outline_css, Receiver log = logging.getLogger(__name__) @@ -92,13 +92,20 @@ class Renderer(object): (build_lyrics_format_css(self._theme, self.page_width, self.page_height), build_lyrics_outline_css(self._theme)) - def format_slide(self, words, line_break): + def format_slide(self, words, line_break, force_page=False): """ Figure out how much text can appear on a slide, using the current theme settings. ``words`` The words to be fitted on the slide. + + ``line_break`` + Add line endings after each line of text used for bibles. + + ``force_page`` + Flag to tell message lines in page. + """ log.debug(u'format_slide - Start') line_end = u'' @@ -114,13 +121,19 @@ class Renderer(object): formatted = [] html_text = u'' styled_text = u'' + line_count = 0 for line in text: + if line_count != -1: + line_count += 1 styled_line = expand_tags(line) + line_end styled_text += styled_line html = self.page_shell + styled_text + u'' self.web.setHtml(html) # Text too long so go to next page if self.web_frame.contentsSize().height() > self.page_height: + if force_page and line_count > 0: + Receiver.send_message(u'theme_line_count', line_count) + line_count = -1 if html_text.endswith(u'
'): html_text = html_text[:len(html_text)-4] formatted.append(html_text) diff --git a/openlp/core/lib/rendermanager.py b/openlp/core/lib/rendermanager.py index bf561b4b3..81cde12a0 100644 --- a/openlp/core/lib/rendermanager.py +++ b/openlp/core/lib/rendermanager.py @@ -67,8 +67,9 @@ class RenderManager(object): self.service_theme = u'' self.theme_level = u'' self.override_background = None - self.themedata = None + self.theme_data = None self.alertTab = None + self.force_page = False def update_display(self): """ @@ -80,7 +81,7 @@ class RenderManager(object): self.display.imageManager = self.image_manager self.display.setup() self.renderer.bg_frame = None - self.themedata = None + self.theme_data = None self.image_manager.update_display(self.width, self.height) def set_global_theme(self, global_theme, theme_level=ThemeLevel.Global): @@ -99,7 +100,7 @@ class RenderManager(object): self.theme_level = theme_level self.global_theme_data = \ self.theme_manager.getThemeData(self.global_theme) - self.themedata = None + self.theme_data = None def set_service_theme(self, service_theme): """ @@ -109,7 +110,7 @@ class RenderManager(object): The service-level theme to be set. """ self.service_theme = service_theme - self.themedata = None + self.theme_data = None def set_override_theme(self, theme, overrideLevels=False): """ @@ -146,19 +147,19 @@ class RenderManager(object): self.theme = self.service_theme else: self.theme = self.global_theme - if self.theme != self.renderer.theme_name or self.themedata is None \ + if self.theme != self.renderer.theme_name or self.theme_data is None \ or overrideLevels: log.debug(u'theme is now %s', self.theme) # Force the theme to be the one passed in. if overrideLevels: - self.themedata = theme + self.theme_data = theme else: - self.themedata = self.theme_manager.getThemeData(self.theme) + self.theme_data = self.theme_manager.getThemeData(self.theme) self.calculate_default(self.screens.current[u'size']) - self.renderer.set_theme(self.themedata) - self.build_text_rectangle(self.themedata) - self.image_manager.add_image(self.themedata.theme_name, - self.themedata.background_filename) + self.renderer.set_theme(self.theme_data) + self.build_text_rectangle(self.theme_data) + self.image_manager.add_image(self.theme_data.theme_name, + self.theme_data.background_filename) return self.renderer._rect, self.renderer._rect_footer def build_text_rectangle(self, theme): @@ -187,14 +188,19 @@ class RenderManager(object): theme.font_footer_height - 1) self.renderer.set_text_rectangle(main_rect, footer_rect) - def generate_preview(self, themedata): + def generate_preview(self, theme_data, force_page=False): """ Generate a preview of a theme. - ``themedata`` + ``theme_data`` The theme to generated a preview for. + + ``force_page`` + Flag to tell message lines per page need to be generated. """ log.debug(u'generate preview') + # save value for use in format_slide + self.force_page = force_page # set the default image size for previews self.calculate_default(self.screens.preview[u'size']) verse = u'The Lord said to {r}Noah{/r}: \n' \ @@ -204,23 +210,27 @@ class RenderManager(object): 'Get those children out of the muddy, muddy \n' \ '{r}C{/r}{b}h{/b}{bl}i{/bl}{y}l{/y}{g}d{/g}{pk}' \ 'r{/pk}{o}e{/o}{pp}n{/pp} of the Lord\n' + # make big page for theme edit dialog to get line count + if self.force_page: + verse = verse + verse + verse footer = [] footer.append(u'Arky Arky (Unknown)' ) footer.append(u'Public Domain') footer.append(u'CCLI 123456') # build a service item to generate preview serviceItem = ServiceItem() - serviceItem.theme = themedata + serviceItem.theme = theme_data serviceItem.add_from_text(u'', verse, footer) serviceItem.render_manager = self serviceItem.raw_footer = footer serviceItem.render(True) - self.display.buildHtml(serviceItem) - raw_html = serviceItem.get_rendered_frame(0) - preview = self.display.text(raw_html) - # Reset the real screen size for subsequent render requests - self.calculate_default(self.screens.current[u'size']) - return preview + if not self.force_page: + self.display.buildHtml(serviceItem) + raw_html = serviceItem.get_rendered_frame(0) + preview = self.display.text(raw_html) + # Reset the real screen size for subsequent render requests + self.calculate_default(self.screens.current[u'size']) + return preview def format_slide(self, words, line_break): """ @@ -228,9 +238,12 @@ class RenderManager(object): ``words`` The words to go on the slides. + + ``line_break`` + Add line endings after each line of text used for bibles. """ log.debug(u'format slide') - return self.renderer.format_slide(words, line_break) + return self.renderer.format_slide(words, line_break, self.force_page) def calculate_default(self, screen): """ diff --git a/openlp/core/ui/themeform.py b/openlp/core/ui/themeform.py index 0ea5f057f..cc52abafc 100644 --- a/openlp/core/ui/themeform.py +++ b/openlp/core/ui/themeform.py @@ -29,7 +29,8 @@ import os from PyQt4 import QtCore, QtGui -from openlp.core.lib import translate, BackgroundType, BackgroundGradientType +from openlp.core.lib import translate, BackgroundType, BackgroundGradientType, \ + Receiver from openlp.core.utils import get_images_filter from themewizard import Ui_ThemeWizard @@ -96,10 +97,40 @@ class ThemeForm(QtGui.QWizard, Ui_ThemeWizard): QtCore.QObject.connect(self, QtCore.SIGNAL(u'currentIdChanged(int)'), self.pageChanged) + QtCore.QObject.connect(Receiver.get_receiver(), + QtCore.SIGNAL(u'theme_line_count'), + self.updateLinesText) + QtCore.QObject.connect(self.mainSizeSpinBox, + QtCore.SIGNAL(u'valueChanged(int)'), + self.calculateLines) + QtCore.QObject.connect(self.mainSizeSpinBox, + QtCore.SIGNAL(u'editingFinished()'), + self.calculateLines) + QtCore.QObject.connect(self.lineSpacingSpinBox, + QtCore.SIGNAL(u'valueChanged(int)'), + self.calculateLines) + QtCore.QObject.connect(self.lineSpacingSpinBox, + QtCore.SIGNAL(u'editingFinished()'), + self.calculateLines) + QtCore.QObject.connect(self.outlineSizeSpinBox, + QtCore.SIGNAL(u'valueChanged(int)'), + self.calculateLines) + QtCore.QObject.connect(self.outlineSizeSpinBox, + QtCore.SIGNAL(u'editingFinished()'), + self.calculateLines) + QtCore.QObject.connect(self.shadowSizeSpinBox, + QtCore.SIGNAL(u'valueChanged(int)'), + self.calculateLines) + QtCore.QObject.connect(self.shadowSizeSpinBox, + QtCore.SIGNAL(u'editingFinished()'), + self.calculateLines) + QtCore.QObject.connect(self.mainFontComboBox, + QtCore.SIGNAL(u'activated(int)'), + self.calculateLines) def pageChanged(self, pageId): """ - Detects Page changes and updates. + Detects Page changes and updates as approprate. """ if pageId == 6: self.updateTheme() @@ -184,6 +215,22 @@ class ThemeForm(QtGui.QWizard, Ui_ThemeWizard): self.backgroundPage.registerField( u'name', self.themeNameEdit) + def calculateLines(self): + """ + Calculate the number of lines on a page by rendering text + """ + # Do not trigger on start up + if self.page != 0: + self.updateTheme() + frame = self.thememanager.generateImage(self.theme, True) + + def updateLinesText(self, lines): + """ + Updates the lines on a page on the wizard + """ + self.mainLineCountLabel.setText(unicode(translate('OpenLP.ThemeForm', \ + '(%d lines per slide)' % int(lines)))) + def onOutlineCheckCheckBoxChanged(self, state): """ Change state as Outline check box changed @@ -194,6 +241,7 @@ class ThemeForm(QtGui.QWizard, Ui_ThemeWizard): self.theme.font_main_outline = False self.outlineColorPushButton.setEnabled(self.theme.font_main_outline) self.outlineSizeSpinBox.setEnabled(self.theme.font_main_outline) + self.calculateLines() def onShadowCheckCheckBoxChanged(self, state): """ @@ -205,6 +253,7 @@ class ThemeForm(QtGui.QWizard, Ui_ThemeWizard): self.theme.font_main_shadow = False self.shadowColorPushButton.setEnabled(self.theme.font_main_shadow) self.shadowSizeSpinBox.setEnabled(self.theme.font_main_shadow) + self.calculateLines() def onMainDefaultPositionCheckBox(self, value): """ @@ -244,6 +293,7 @@ class ThemeForm(QtGui.QWizard, Ui_ThemeWizard): Set up the pages for Initial run through dialog """ log.debug(u'initializePage %s' % id) + self.page = id if id == 1: self.setBackgroundTabValues() elif id == 2: @@ -578,15 +628,15 @@ class ThemeForm(QtGui.QWizard, Ui_ThemeWizard): (QtGui.QMessageBox.Ok), QtGui.QMessageBox.Ok) return - save_from = None - save_to = None + saveFrom = None + saveTo = None if self.theme.background_type == \ BackgroundType.to_string(BackgroundType.Image): filename = \ os.path.split(unicode(self.theme.background_filename))[1] - save_to = os.path.join(self.path, self.theme.theme_name, filename) - save_from = self.theme.background_filename - if self.thememanager.saveTheme(self.theme, save_from, save_to): + saveTo = os.path.join(self.path, self.theme.theme_name, filename) + saveFrom = self.theme.background_filename + if self.thememanager.saveTheme(self.theme, saveFrom, saveTo): return QtGui.QDialog.accept(self) def _colorButton(self, field): diff --git a/openlp/core/ui/thememanager.py b/openlp/core/ui/thememanager.py index 0f0802bf2..65913a9f6 100644 --- a/openlp/core/ui/thememanager.py +++ b/openlp/core/ui/thememanager.py @@ -181,7 +181,7 @@ class ThemeManager(QtGui.QWidget): '%s (default)')) % newName self.themeListWidget.item(count).setText(name) - def changeGlobalFromScreen(self, index = -1): + def changeGlobalFromScreen(self, index=-1): """ Change the global theme when a theme is double clicked upon in the Theme Manager list @@ -252,17 +252,14 @@ class ThemeManager(QtGui.QWidget): Takes a theme and makes a new copy of it as well as saving it. """ log.debug(u'cloneThemeData') - themeData.new_document(newThemeName) - themeData.build_xml_from_attrs() - save_to = None - save_from = None + saveTo = None + saveFrom = None if themeData.background_type == u'image': - save_to = os.path.join(self.path, newThemeName, + saveTo = os.path.join(self.path, newThemeName, os.path.split(unicode(themeData.background_filename))[1]) - save_from = themeData.background_filename - theme = themeData.extract_xml() - pretty_theme = themeData.extract_formatted_xml() - self.saveTheme(newThemeName, theme, pretty_theme, save_from, save_to) + saveFrom = themeData.background_filename + themeData.theme_name = newThemeName + self.saveTheme(themeData, saveFrom, saveTo) def onEditTheme(self): """ @@ -462,17 +459,17 @@ class ThemeManager(QtGui.QWidget): """ return self.themelist - def getThemeData(self, themename): + def getThemeData(self, themeName): """ Returns a theme object from an XML file - ``themename`` + ``themeName`` Name of the theme to load from file """ - log.debug(u'getthemedata for theme %s', themename) - xml_file = os.path.join(self.path, unicode(themename), - unicode(themename) + u'.xml') - xml = get_text_file_string(xml_file) + log.debug(u'getthemedata for theme %s', themeName) + xmlFile = os.path.join(self.path, unicode(themeName), + unicode(themeName) + u'.xml') + xml = get_text_file_string(xmlFile) if not xml: return self.baseTheme() else: @@ -640,7 +637,7 @@ class ThemeManager(QtGui.QWidget): newtheme.display_vertical_align = vAlignCorrection return newtheme.extract_xml() - def saveTheme(self, theme, image_from, image_to): + def saveTheme(self, theme, imageFrom, imageTo): """ Called by thememaintenance Dialog to save the theme and to trigger the reload of the theme list @@ -673,8 +670,8 @@ class ThemeManager(QtGui.QWidget): self.deleteTheme(self.saveThemeName) if result == QtGui.QMessageBox.Yes: # Save the theme, overwriting the existing theme if necessary. - if image_to and self.oldBackgroundImage and \ - image_to != self.oldBackgroundImage: + if imageTo and self.oldBackgroundImage and \ + imageTo != self.oldBackgroundImage: try: os.remove(self.oldBackgroundImage) except OSError: @@ -688,12 +685,12 @@ class ThemeManager(QtGui.QWidget): finally: if outfile: outfile.close() - if image_from and image_from != image_to: + if imageFrom and imageFrom != imageTo: try: encoding = get_filesystem_encoding() shutil.copyfile( - unicode(image_from).encode(encoding), - unicode(image_to).encode(encoding)) + unicode(imageFrom).encode(encoding), + unicode(imageTo).encode(encoding)) except IOError: log.exception(u'Failed to save theme image') self.generateAndSaveImage(self.path, name, theme) @@ -729,7 +726,6 @@ class ThemeManager(QtGui.QWidget): def generateAndSaveImage(self, dir, name, theme): log.debug(u'generateAndSaveImage %s %s', dir, name) - #theme = self.createThemeFromXml(theme_xml, dir) theme_xml = theme.extract_xml() frame = self.generateImage(theme) samplepathname = os.path.join(self.path, name + u'.png') @@ -742,12 +738,18 @@ class ThemeManager(QtGui.QWidget): pixmap.save(thumb, u'png') log.debug(u'Theme image written to %s', samplepathname) - def generateImage(self, themedata): + def generateImage(self, themeData, forcePage=False): """ Call the RenderManager to build a Sample Image + + ``themeData`` + The theme to generated a preview for. + + ``forcePage`` + Flag to tell message lines per page need to be generated. """ - log.debug(u'generateImage \n%s ', themedata) - return self.parent.RenderManager.generate_preview(themedata) + log.debug(u'generateImage \n%s ', themeData) + return self.parent.RenderManager.generate_preview(themeData, forcePage) def getPreviewImage(self, theme): """ @@ -768,14 +770,14 @@ class ThemeManager(QtGui.QWidget): newtheme = ThemeXML() return newtheme - def createThemeFromXml(self, theme_xml, path): + def createThemeFromXml(self, themeXml, path): """ Return a theme object using information parsed from XML - ``theme_xml`` + ``themeXml`` The XML data to load into the theme """ theme = ThemeXML() - theme.parse(theme_xml) + theme.parse(themeXml) theme.extend_image_filename(path) return theme diff --git a/openlp/plugins/songs/lib/mediaitem.py b/openlp/plugins/songs/lib/mediaitem.py index 21de00fce..cb2d6a6e0 100644 --- a/openlp/plugins/songs/lib/mediaitem.py +++ b/openlp/plugins/songs/lib/mediaitem.py @@ -415,17 +415,12 @@ class SongMediaItem(MediaManagerItem): if search_results: for song in search_results: count = 0 - # temp debug to find why service items do not edit - log.debug(u'author list %s' % author_list) for author in song.authors: - log.debug(u'author %s' % author.display_name) if author.display_name in author_list: count += 1 - log.debug(u'found %s : %s' % (count, len(author_list))) if count == len(author_list): editId = song.id uuid = item._uuid if editId != 0: Receiver.send_message(u'service_item_update', u'%s:%s' %(editId, uuid)) -