forked from openlp/openlp
Head
This commit is contained in:
commit
bd173bd217
@ -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
|
||||
|
@ -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'</div></body></html>'
|
||||
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'<br>'):
|
||||
html_text = html_text[:len(html_text)-4]
|
||||
formatted.append(html_text)
|
||||
|
@ -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,17 +210,21 @@ 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)
|
||||
if not self.force_page:
|
||||
self.display.buildHtml(serviceItem)
|
||||
raw_html = serviceItem.get_rendered_frame(0)
|
||||
preview = self.display.text(raw_html)
|
||||
@ -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):
|
||||
"""
|
||||
|
@ -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):
|
||||
|
@ -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
|
||||
|
@ -213,7 +213,7 @@ class BGExtract(object):
|
||||
finally:
|
||||
if not page:
|
||||
return None
|
||||
cleaner = [(re.compile(' |<br />'), lambda match: '')]
|
||||
cleaner = [(re.compile(' |<br />|\'\+\''), lambda match: '')]
|
||||
soup = None
|
||||
try:
|
||||
soup = BeautifulSoup(page, markupMassage=cleaner)
|
||||
|
@ -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))
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user