forked from openlp/openlp
add configurethemes.png
This commit is contained in:
commit
7857b60c66
BIN
documentation/manual/source/pics/configurethemes.png
Normal file
BIN
documentation/manual/source/pics/configurethemes.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 94 KiB |
@ -46,7 +46,7 @@ from openlp.core.ui.firsttimeform import FirstTimeForm
|
|||||||
from openlp.core.ui.exceptionform import ExceptionForm
|
from openlp.core.ui.exceptionform import ExceptionForm
|
||||||
from openlp.core.ui import SplashScreen, ScreenList
|
from openlp.core.ui import SplashScreen, ScreenList
|
||||||
from openlp.core.utils import AppLocation, LanguageManager, VersionThread, \
|
from openlp.core.utils import AppLocation, LanguageManager, VersionThread, \
|
||||||
get_application_version
|
get_application_version, DelayStartThread
|
||||||
|
|
||||||
log = logging.getLogger()
|
log = logging.getLogger()
|
||||||
|
|
||||||
@ -130,6 +130,7 @@ class OpenLP(QtGui.QApplication):
|
|||||||
u'general/update check', QtCore.QVariant(True)).toBool()
|
u'general/update check', QtCore.QVariant(True)).toBool()
|
||||||
if update_check:
|
if update_check:
|
||||||
VersionThread(self.mainWindow).start()
|
VersionThread(self.mainWindow).start()
|
||||||
|
DelayStartThread(self.mainWindow).start()
|
||||||
return self.exec_()
|
return self.exec_()
|
||||||
|
|
||||||
def isAlreadyRunning(self):
|
def isAlreadyRunning(self):
|
||||||
@ -250,4 +251,4 @@ if __name__ == u'__main__':
|
|||||||
"""
|
"""
|
||||||
Instantiate and run the application.
|
Instantiate and run the application.
|
||||||
"""
|
"""
|
||||||
main()
|
main()
|
||||||
|
@ -289,6 +289,5 @@ from htmlbuilder import build_html, build_lyrics_format_css, \
|
|||||||
from toolbar import OpenLPToolbar
|
from toolbar import OpenLPToolbar
|
||||||
from dockwidget import OpenLPDockWidget
|
from dockwidget import OpenLPDockWidget
|
||||||
from renderer import Renderer
|
from renderer import Renderer
|
||||||
from rendermanager import RenderManager
|
|
||||||
from mediamanageritem import MediaManagerItem
|
from mediamanageritem import MediaManagerItem
|
||||||
from openlp.core.utils.actions import ActionList
|
from openlp.core.utils.actions import ActionList
|
||||||
|
@ -554,4 +554,4 @@ class MediaManagerItem(QtGui.QWidget):
|
|||||||
item_id = remoteItem
|
item_id = remoteItem
|
||||||
else:
|
else:
|
||||||
item_id = (item.data(QtCore.Qt.UserRole)).toInt()[0]
|
item_id = (item.data(QtCore.Qt.UserRole)).toInt()[0]
|
||||||
return item_id
|
return item_id
|
||||||
|
@ -161,7 +161,7 @@ class Plugin(QtCore.QObject):
|
|||||||
self.log = logging.getLogger(self.name)
|
self.log = logging.getLogger(self.name)
|
||||||
self.previewController = plugin_helpers[u'preview']
|
self.previewController = plugin_helpers[u'preview']
|
||||||
self.liveController = plugin_helpers[u'live']
|
self.liveController = plugin_helpers[u'live']
|
||||||
self.renderManager = plugin_helpers[u'render']
|
self.renderer = plugin_helpers[u'renderer']
|
||||||
self.serviceManager = plugin_helpers[u'service']
|
self.serviceManager = plugin_helpers[u'service']
|
||||||
self.settingsForm = plugin_helpers[u'settings form']
|
self.settingsForm = plugin_helpers[u'settings form']
|
||||||
self.mediadock = plugin_helpers[u'toolbox']
|
self.mediadock = plugin_helpers[u'toolbox']
|
||||||
@ -359,4 +359,4 @@ class Plugin(QtCore.QObject):
|
|||||||
use of the singular name of the plugin object so must only be called
|
use of the singular name of the plugin object so must only be called
|
||||||
after this has been set.
|
after this has been set.
|
||||||
"""
|
"""
|
||||||
self.textStrings[name] = {u'title': title, u'tooltip': tooltip}
|
self.textStrings[name] = {u'title': title, u'tooltip': tooltip}
|
||||||
|
@ -23,46 +23,260 @@
|
|||||||
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
|
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
|
||||||
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
||||||
###############################################################################
|
###############################################################################
|
||||||
"""
|
|
||||||
The :mod:`renderer` module enables OpenLP to take the input from plugins and
|
|
||||||
format it for the output display.
|
|
||||||
"""
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from PyQt4 import QtWebKit
|
from PyQt4 import QtCore, QtWebKit
|
||||||
|
|
||||||
from openlp.core.lib import expand_tags, build_lyrics_format_css, \
|
from openlp.core.lib import ServiceItem, ImageManager, expand_tags, \
|
||||||
build_lyrics_outline_css, Receiver
|
build_lyrics_format_css, build_lyrics_outline_css, Receiver, \
|
||||||
|
ItemCapabilities
|
||||||
|
from openlp.core.lib.theme import ThemeLevel
|
||||||
|
from openlp.core.ui import MainDisplay
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
VERSE = u'The Lord said to {r}Noah{/r}: \n' \
|
||||||
|
'There\'s gonna be a {su}floody{/su}, {sb}floody{/sb}\n' \
|
||||||
|
'The Lord said to {g}Noah{/g}:\n' \
|
||||||
|
'There\'s gonna be a {st}floody{/st}, {it}floody{/it}\n' \
|
||||||
|
'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'
|
||||||
|
FOOTER = [u'Arky Arky (Unknown)', u'Public Domain', u'CCLI 123456']
|
||||||
|
|
||||||
|
HTML_END = u'</div></body></html>'
|
||||||
|
|
||||||
class Renderer(object):
|
class Renderer(object):
|
||||||
"""
|
"""
|
||||||
Genarates a pixmap image of a array of text. The Text is formatted to
|
Class to pull all Renderer interactions into one place. The plugins will
|
||||||
make sure it fits on the screen and if not extra frames are generated.
|
call helper methods to do the rendering but this class will provide
|
||||||
|
display defense code.
|
||||||
|
|
||||||
|
``theme_manager``
|
||||||
|
The ThemeManager instance, used to get the current theme details.
|
||||||
|
|
||||||
|
``screens``
|
||||||
|
Contains information about the Screens.
|
||||||
|
|
||||||
|
``screen_number``
|
||||||
|
Defaults to *0*. The index of the output/display screen.
|
||||||
"""
|
"""
|
||||||
log.info(u'Renderer Loaded')
|
log.info(u'Renderer Loaded')
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self, theme_manager, screens):
|
||||||
"""
|
"""
|
||||||
Initialise the renderer.
|
Initialise the render manager.
|
||||||
"""
|
"""
|
||||||
self._rect = None
|
log.debug(u'Initilisation started')
|
||||||
self.theme_name = None
|
self.screens = screens
|
||||||
self._theme = None
|
self.image_manager = ImageManager()
|
||||||
|
self.display = MainDisplay(self, screens, False)
|
||||||
|
self.display.imageManager = self.image_manager
|
||||||
|
self.theme_manager = theme_manager
|
||||||
|
self.service_theme = u''
|
||||||
|
self.theme_level = u''
|
||||||
|
self.override_background = None
|
||||||
|
self.theme_data = None
|
||||||
|
self.force_page = False
|
||||||
|
|
||||||
def set_theme(self, theme):
|
def update_display(self):
|
||||||
"""
|
"""
|
||||||
Set the theme to be used.
|
Updates the render manager's information about the current screen.
|
||||||
|
"""
|
||||||
|
log.debug(u'Update Display')
|
||||||
|
self._calculate_default(self.screens.current[u'size'])
|
||||||
|
self.display = MainDisplay(self, self.screens, False)
|
||||||
|
self.display.imageManager = self.image_manager
|
||||||
|
self.display.setup()
|
||||||
|
self.bg_frame = 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):
|
||||||
|
"""
|
||||||
|
Set the global-level theme and the theme level.
|
||||||
|
|
||||||
|
``global_theme``
|
||||||
|
The global-level theme to be set.
|
||||||
|
|
||||||
|
``theme_level``
|
||||||
|
Defaults to *``ThemeLevel.Global``*. The theme level, can be
|
||||||
|
``ThemeLevel.Global``, ``ThemeLevel.Service`` or
|
||||||
|
``ThemeLevel.Song``.
|
||||||
|
"""
|
||||||
|
self.global_theme = global_theme
|
||||||
|
self.theme_level = theme_level
|
||||||
|
self.global_theme_data = \
|
||||||
|
self.theme_manager.getThemeData(self.global_theme)
|
||||||
|
self.theme_data = None
|
||||||
|
|
||||||
|
def set_service_theme(self, service_theme):
|
||||||
|
"""
|
||||||
|
Set the service-level theme.
|
||||||
|
|
||||||
|
``service_theme``
|
||||||
|
The service-level theme to be set.
|
||||||
|
"""
|
||||||
|
self.service_theme = service_theme
|
||||||
|
self.theme_data = None
|
||||||
|
|
||||||
|
def set_override_theme(self, override_theme, override_levels=False):
|
||||||
|
"""
|
||||||
|
Set the appropriate theme depending on the theme level.
|
||||||
|
Called by the service item when building a display frame
|
||||||
|
|
||||||
``theme``
|
``theme``
|
||||||
The theme to be used.
|
The name of the song-level theme. None means the service
|
||||||
"""
|
item wants to use the given value.
|
||||||
log.debug(u'set theme')
|
|
||||||
self._theme = theme
|
|
||||||
self.theme_name = theme.theme_name
|
|
||||||
|
|
||||||
def set_text_rectangle(self, rect_main, rect_footer):
|
``override_levels``
|
||||||
|
Used to force the theme data passed in to be used.
|
||||||
|
|
||||||
|
"""
|
||||||
|
log.debug(u'set override theme to %s', override_theme)
|
||||||
|
theme_level = self.theme_level
|
||||||
|
if override_levels:
|
||||||
|
theme_level = ThemeLevel.Song
|
||||||
|
if theme_level == ThemeLevel.Global:
|
||||||
|
theme = self.global_theme
|
||||||
|
elif theme_level == ThemeLevel.Service:
|
||||||
|
if self.service_theme == u'':
|
||||||
|
theme = self.global_theme
|
||||||
|
else:
|
||||||
|
theme = self.service_theme
|
||||||
|
else:
|
||||||
|
# Images have a theme of -1
|
||||||
|
if override_theme and override_theme != -1:
|
||||||
|
theme = override_theme
|
||||||
|
elif theme_level == ThemeLevel.Song or \
|
||||||
|
theme_level == ThemeLevel.Service:
|
||||||
|
if self.service_theme == u'':
|
||||||
|
theme = self.global_theme
|
||||||
|
else:
|
||||||
|
theme = self.service_theme
|
||||||
|
else:
|
||||||
|
theme = self.global_theme
|
||||||
|
log.debug(u'theme is now %s', theme)
|
||||||
|
# Force the theme to be the one passed in.
|
||||||
|
if override_levels:
|
||||||
|
self.theme_data = override_theme
|
||||||
|
else:
|
||||||
|
self.theme_data = self.theme_manager.getThemeData(theme)
|
||||||
|
self._calculate_default(self.screens.current[u'size'])
|
||||||
|
self._build_text_rectangle(self.theme_data)
|
||||||
|
self.image_manager.add_image(self.theme_data.theme_name,
|
||||||
|
self.theme_data.background_filename)
|
||||||
|
return self._rect, self._rect_footer
|
||||||
|
|
||||||
|
def generate_preview(self, theme_data, force_page=False):
|
||||||
|
"""
|
||||||
|
Generate a preview of a theme.
|
||||||
|
|
||||||
|
``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'])
|
||||||
|
# build a service item to generate preview
|
||||||
|
serviceItem = ServiceItem()
|
||||||
|
serviceItem.theme = theme_data
|
||||||
|
if self.force_page:
|
||||||
|
# make big page for theme edit dialog to get line count
|
||||||
|
serviceItem.add_from_text(u'', VERSE + VERSE + VERSE, FOOTER)
|
||||||
|
else:
|
||||||
|
self.image_manager.del_image(theme_data.theme_name)
|
||||||
|
serviceItem.add_from_text(u'', VERSE, FOOTER)
|
||||||
|
serviceItem.renderer = 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)
|
||||||
|
# Reset the real screen size for subsequent render requests
|
||||||
|
self._calculate_default(self.screens.current[u'size'])
|
||||||
|
return preview
|
||||||
|
|
||||||
|
def format_slide(self, text, line_break, item):
|
||||||
|
"""
|
||||||
|
Calculate how much text can fit on a slide.
|
||||||
|
|
||||||
|
``text``
|
||||||
|
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')
|
||||||
|
# clean up line endings
|
||||||
|
lines = self._lines_split(text)
|
||||||
|
pages = self._paginate_slide(lines, line_break, self.force_page)
|
||||||
|
if len(pages) > 1:
|
||||||
|
# Songs and Custom
|
||||||
|
if item.is_capable(ItemCapabilities.AllowsVirtualSplit):
|
||||||
|
# Do not forget the line breaks !
|
||||||
|
slides = text.split(u'[---]')
|
||||||
|
pages = []
|
||||||
|
for slide in slides:
|
||||||
|
lines = slide.strip(u'\n').split(u'\n')
|
||||||
|
new_pages = self._paginate_slide(lines, line_break,
|
||||||
|
self.force_page)
|
||||||
|
pages.extend(new_pages)
|
||||||
|
# Bibles
|
||||||
|
elif item.is_capable(ItemCapabilities.AllowsWordSplit):
|
||||||
|
pages = self._paginate_slide_words(text, line_break)
|
||||||
|
return pages
|
||||||
|
|
||||||
|
def _calculate_default(self, screen):
|
||||||
|
"""
|
||||||
|
Calculate the default dimentions of the screen.
|
||||||
|
|
||||||
|
``screen``
|
||||||
|
The QSize of the screen.
|
||||||
|
"""
|
||||||
|
log.debug(u'calculate default %s', screen)
|
||||||
|
self.width = screen.width()
|
||||||
|
self.height = screen.height()
|
||||||
|
self.screen_ratio = float(self.height) / float(self.width)
|
||||||
|
log.debug(u'calculate default %d, %d, %f',
|
||||||
|
self.width, self.height, self.screen_ratio)
|
||||||
|
# 90% is start of footer
|
||||||
|
self.footer_start = int(self.height * 0.90)
|
||||||
|
|
||||||
|
def _build_text_rectangle(self, theme):
|
||||||
|
"""
|
||||||
|
Builds a text block using the settings in ``theme``
|
||||||
|
and the size of the display screen.height.
|
||||||
|
Note the system has a 10 pixel border round the screen
|
||||||
|
|
||||||
|
``theme``
|
||||||
|
The theme to build a text block for.
|
||||||
|
"""
|
||||||
|
log.debug(u'_build_text_rectangle')
|
||||||
|
main_rect = None
|
||||||
|
footer_rect = None
|
||||||
|
if not theme.font_main_override:
|
||||||
|
main_rect = QtCore.QRect(10, 0, self.width - 20, self.footer_start)
|
||||||
|
else:
|
||||||
|
main_rect = QtCore.QRect(theme.font_main_x, theme.font_main_y,
|
||||||
|
theme.font_main_width - 1, theme.font_main_height - 1)
|
||||||
|
if not theme.font_footer_override:
|
||||||
|
footer_rect = QtCore.QRect(10, self.footer_start, self.width - 20,
|
||||||
|
self.height - self.footer_start)
|
||||||
|
else:
|
||||||
|
footer_rect = QtCore.QRect(theme.font_footer_x,
|
||||||
|
theme.font_footer_y, theme.font_footer_width - 1,
|
||||||
|
theme.font_footer_height - 1)
|
||||||
|
self._set_text_rectangle(main_rect, footer_rect)
|
||||||
|
|
||||||
|
def _set_text_rectangle(self, rect_main, rect_footer):
|
||||||
"""
|
"""
|
||||||
Sets the rectangle within which text should be rendered.
|
Sets the rectangle within which text should be rendered.
|
||||||
|
|
||||||
@ -77,9 +291,9 @@ class Renderer(object):
|
|||||||
self._rect_footer = rect_footer
|
self._rect_footer = rect_footer
|
||||||
self.page_width = self._rect.width()
|
self.page_width = self._rect.width()
|
||||||
self.page_height = self._rect.height()
|
self.page_height = self._rect.height()
|
||||||
if self._theme.font_main_shadow:
|
if self.theme_data.font_main_shadow:
|
||||||
self.page_width -= int(self._theme.font_main_shadow_size)
|
self.page_width -= int(self.theme_data.font_main_shadow_size)
|
||||||
self.page_height -= int(self._theme.font_main_shadow_size)
|
self.page_height -= int(self.theme_data.font_main_shadow_size)
|
||||||
self.web = QtWebKit.QWebView()
|
self.web = QtWebKit.QWebView()
|
||||||
self.web.setVisible(False)
|
self.web.setVisible(False)
|
||||||
self.web.resize(self.page_width, self.page_height)
|
self.web.resize(self.page_width, self.page_height)
|
||||||
@ -89,59 +303,146 @@ class Renderer(object):
|
|||||||
u'*{margin: 0; padding: 0; border: 0;} '\
|
u'*{margin: 0; padding: 0; border: 0;} '\
|
||||||
u'#main {position:absolute; top:0px; %s %s}</style><body>' \
|
u'#main {position:absolute; top:0px; %s %s}</style><body>' \
|
||||||
u'<div id="main">' % \
|
u'<div id="main">' % \
|
||||||
(build_lyrics_format_css(self._theme, self.page_width,
|
(build_lyrics_format_css(self.theme_data, self.page_width,
|
||||||
self.page_height), build_lyrics_outline_css(self._theme))
|
self.page_height), build_lyrics_outline_css(self.theme_data))
|
||||||
|
|
||||||
def format_slide(self, words, line_break, force_page=False):
|
def _paginate_slide(self, lines, line_break, force_page=False):
|
||||||
"""
|
"""
|
||||||
Figure out how much text can appear on a slide, using the current
|
Figure out how much text can appear on a slide, using the current
|
||||||
theme settings.
|
theme settings.
|
||||||
|
|
||||||
``words``
|
``lines``
|
||||||
The words to be fitted on the slide.
|
The words to be fitted on the slide split into lines.
|
||||||
|
|
||||||
``line_break``
|
``line_break``
|
||||||
Add line endings after each line of text used for bibles.
|
Add line endings after each line of text (used for bibles).
|
||||||
|
|
||||||
``force_page``
|
``force_page``
|
||||||
Flag to tell message lines in page.
|
Flag to tell message lines in page.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
log.debug(u'format_slide - Start')
|
log.debug(u'_paginate_slide - Start')
|
||||||
line_end = u''
|
line_end = u''
|
||||||
if line_break:
|
if line_break:
|
||||||
line_end = u'<br>'
|
line_end = u'<br>'
|
||||||
words = words.replace(u'\r\n', u'\n')
|
|
||||||
verses_text = words.split(u'\n')
|
|
||||||
text = []
|
|
||||||
for verse in verses_text:
|
|
||||||
lines = verse.split(u'\n')
|
|
||||||
for line in lines:
|
|
||||||
text.append(line)
|
|
||||||
formatted = []
|
formatted = []
|
||||||
html_text = u''
|
html_text = u''
|
||||||
styled_text = u''
|
styled_text = u''
|
||||||
line_count = 0
|
line_count = 0
|
||||||
for line in text:
|
for line in lines:
|
||||||
if line_count != -1:
|
if line_count != -1:
|
||||||
line_count += 1
|
line_count += 1
|
||||||
styled_line = expand_tags(line) + line_end
|
styled_line = expand_tags(line) + line_end
|
||||||
styled_text += styled_line
|
styled_text += styled_line
|
||||||
html = self.page_shell + styled_text + u'</div></body></html>'
|
html = self.page_shell + styled_text + HTML_END
|
||||||
self.web.setHtml(html)
|
self.web.setHtml(html)
|
||||||
# Text too long so go to next page
|
# Text too long so go to next page
|
||||||
if self.web_frame.contentsSize().height() > self.page_height:
|
if self.web_frame.contentsSize().height() > self.page_height:
|
||||||
if force_page and line_count > 0:
|
if force_page and line_count > 0:
|
||||||
Receiver.send_message(u'theme_line_count', line_count)
|
Receiver.send_message(u'theme_line_count', line_count)
|
||||||
line_count = -1
|
line_count = -1
|
||||||
if html_text.endswith(u'<br>'):
|
while html_text.endswith(u'<br>'):
|
||||||
html_text = html_text[:len(html_text)-4]
|
html_text = html_text[:-4]
|
||||||
formatted.append(html_text)
|
formatted.append(html_text)
|
||||||
html_text = u''
|
html_text = u''
|
||||||
styled_text = styled_line
|
styled_text = styled_line
|
||||||
html_text += line + line_end
|
html_text += line + line_end
|
||||||
if html_text.endswith(u'<br>'):
|
while html_text.endswith(u'<br>'):
|
||||||
html_text = html_text[:len(html_text)-4]
|
html_text = html_text[:-4]
|
||||||
formatted.append(html_text)
|
formatted.append(html_text)
|
||||||
log.debug(u'format_slide - End')
|
log.debug(u'_paginate_slide - End')
|
||||||
return formatted
|
return formatted
|
||||||
|
|
||||||
|
def _paginate_slide_words(self, text, line_break):
|
||||||
|
"""
|
||||||
|
Figure out how much text can appear on a slide, using the current
|
||||||
|
theme settings. This version is to handle text which needs to be split
|
||||||
|
into words to get it to fit.
|
||||||
|
|
||||||
|
``text``
|
||||||
|
The words to be fitted on the slide split into lines.
|
||||||
|
|
||||||
|
``line_break``
|
||||||
|
Add line endings after each line of text used for bibles.
|
||||||
|
|
||||||
|
"""
|
||||||
|
log.debug(u'_paginate_slide_words - Start')
|
||||||
|
line_end = u''
|
||||||
|
if line_break:
|
||||||
|
line_end = u'<br>'
|
||||||
|
formatted = []
|
||||||
|
previous_html = u''
|
||||||
|
previous_raw = u''
|
||||||
|
lines = text.split(u'\n')
|
||||||
|
for line in lines:
|
||||||
|
styled_line = expand_tags(line)
|
||||||
|
html = self.page_shell + previous_html + styled_line + HTML_END
|
||||||
|
self.web.setHtml(html)
|
||||||
|
# Text too long so go to next page
|
||||||
|
if self.web_frame.contentsSize().height() > self.page_height:
|
||||||
|
# Check if there was a verse before the current one and append
|
||||||
|
# it, when it fits on the page.
|
||||||
|
if previous_html:
|
||||||
|
html = self.page_shell + previous_html + HTML_END
|
||||||
|
self.web.setHtml(html)
|
||||||
|
if self.web_frame.contentsSize().height() <= \
|
||||||
|
self.page_height:
|
||||||
|
while previous_raw.endswith(u'<br>'):
|
||||||
|
previous_raw = previous_raw[:-4]
|
||||||
|
formatted.append(previous_raw)
|
||||||
|
previous_html = u''
|
||||||
|
previous_raw = u''
|
||||||
|
html = self.page_shell + styled_line + HTML_END
|
||||||
|
self.web.setHtml(html)
|
||||||
|
# Now check if the current verse will fit, if it does
|
||||||
|
# not we have to start to process the verse word by
|
||||||
|
# word.
|
||||||
|
if self.web_frame.contentsSize().height() <= \
|
||||||
|
self.page_height:
|
||||||
|
previous_html = styled_line + line_end
|
||||||
|
previous_raw = line + line_end
|
||||||
|
continue
|
||||||
|
words = self._words_split(line)
|
||||||
|
for word in words:
|
||||||
|
styled_word = expand_tags(word)
|
||||||
|
html = self.page_shell + previous_html + styled_word + \
|
||||||
|
HTML_END
|
||||||
|
self.web.setHtml(html)
|
||||||
|
# Text too long so go to next page
|
||||||
|
if self.web_frame.contentsSize().height() > \
|
||||||
|
self.page_height:
|
||||||
|
while previous_raw.endswith(u'<br>'):
|
||||||
|
previous_raw = previous_raw[:-4]
|
||||||
|
formatted.append(previous_raw)
|
||||||
|
previous_html = u''
|
||||||
|
previous_raw = u''
|
||||||
|
previous_html += styled_word
|
||||||
|
previous_raw += word
|
||||||
|
previous_html += line_end
|
||||||
|
previous_raw += line_end
|
||||||
|
else:
|
||||||
|
previous_html += styled_line + line_end
|
||||||
|
previous_raw += line + line_end
|
||||||
|
while previous_raw.endswith(u'<br>'):
|
||||||
|
previous_raw = previous_raw[:-4]
|
||||||
|
formatted.append(previous_raw)
|
||||||
|
log.debug(u'_paginate_slide_words - End')
|
||||||
|
return formatted
|
||||||
|
|
||||||
|
def _words_split(self, line):
|
||||||
|
"""
|
||||||
|
Split the slide up by word so can wrap better
|
||||||
|
"""
|
||||||
|
# this parse we are to be wordy
|
||||||
|
line = line.replace(u'\n', u' ')
|
||||||
|
words = line.split(u' ')
|
||||||
|
return [word + u' ' for word in words]
|
||||||
|
|
||||||
|
def _lines_split(self, text):
|
||||||
|
"""
|
||||||
|
Split the slide up by physical line
|
||||||
|
"""
|
||||||
|
# this parse we do not want to use this so remove it
|
||||||
|
text = text.replace(u'\n[---]', u'')
|
||||||
|
lines = text.split(u'\n')
|
||||||
|
return [line.replace(u'[---]', u'') for line in lines]
|
||||||
|
@ -1,261 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
|
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
# OpenLP - Open Source Lyrics Projection #
|
|
||||||
# --------------------------------------------------------------------------- #
|
|
||||||
# Copyright (c) 2008-2011 Raoul Snyman #
|
|
||||||
# Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael #
|
|
||||||
# Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, Armin Köhler, #
|
|
||||||
# Andreas Preikschat, Mattias Põldaru, Christian Richter, Philip Ridout, #
|
|
||||||
# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund #
|
|
||||||
# --------------------------------------------------------------------------- #
|
|
||||||
# This program is free software; you can redistribute it and/or modify it #
|
|
||||||
# under the terms of the GNU General Public License as published by the Free #
|
|
||||||
# Software Foundation; version 2 of the License. #
|
|
||||||
# #
|
|
||||||
# This program is distributed in the hope that it will be useful, but WITHOUT #
|
|
||||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
|
|
||||||
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
|
|
||||||
# more details. #
|
|
||||||
# #
|
|
||||||
# You should have received a copy of the GNU General Public License along #
|
|
||||||
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
|
|
||||||
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
|
||||||
###############################################################################
|
|
||||||
|
|
||||||
import logging
|
|
||||||
|
|
||||||
from PyQt4 import QtCore
|
|
||||||
|
|
||||||
from openlp.core.lib import Renderer, ServiceItem, ImageManager
|
|
||||||
from openlp.core.lib.theme import ThemeLevel
|
|
||||||
from openlp.core.ui import MainDisplay
|
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
VERSE = u'The Lord said to {r}Noah{/r}: \n' \
|
|
||||||
'There\'s gonna be a {su}floody{/su}, {sb}floody{/sb}\n' \
|
|
||||||
'The Lord said to {g}Noah{/g}:\n' \
|
|
||||||
'There\'s gonna be a {st}floody{/st}, {it}floody{/it}\n' \
|
|
||||||
'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'
|
|
||||||
FOOTER = [u'Arky Arky (Unknown)', u'Public Domain', u'CCLI 123456']
|
|
||||||
|
|
||||||
class RenderManager(object):
|
|
||||||
"""
|
|
||||||
Class to pull all Renderer interactions into one place. The plugins will
|
|
||||||
call helper methods to do the rendering but this class will provide
|
|
||||||
display defense code.
|
|
||||||
|
|
||||||
``theme_manager``
|
|
||||||
The ThemeManager instance, used to get the current theme details.
|
|
||||||
|
|
||||||
``screens``
|
|
||||||
Contains information about the Screens.
|
|
||||||
|
|
||||||
``screen_number``
|
|
||||||
Defaults to *0*. The index of the output/display screen.
|
|
||||||
"""
|
|
||||||
log.info(u'RenderManager Loaded')
|
|
||||||
|
|
||||||
def __init__(self, theme_manager, screens):
|
|
||||||
"""
|
|
||||||
Initialise the render manager.
|
|
||||||
"""
|
|
||||||
log.debug(u'Initilisation started')
|
|
||||||
self.screens = screens
|
|
||||||
self.image_manager = ImageManager()
|
|
||||||
self.display = MainDisplay(self, screens, False)
|
|
||||||
self.display.imageManager = self.image_manager
|
|
||||||
self.theme_manager = theme_manager
|
|
||||||
self.renderer = Renderer()
|
|
||||||
self.calculate_default(self.screens.current[u'size'])
|
|
||||||
self.theme = u''
|
|
||||||
self.service_theme = u''
|
|
||||||
self.theme_level = u''
|
|
||||||
self.override_background = None
|
|
||||||
self.theme_data = None
|
|
||||||
self.force_page = False
|
|
||||||
|
|
||||||
def update_display(self):
|
|
||||||
"""
|
|
||||||
Updates the render manager's information about the current screen.
|
|
||||||
"""
|
|
||||||
log.debug(u'Update Display')
|
|
||||||
self.calculate_default(self.screens.current[u'size'])
|
|
||||||
self.display = MainDisplay(self, self.screens, False)
|
|
||||||
self.display.imageManager = self.image_manager
|
|
||||||
self.display.setup()
|
|
||||||
self.renderer.bg_frame = 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):
|
|
||||||
"""
|
|
||||||
Set the global-level theme and the theme level.
|
|
||||||
|
|
||||||
``global_theme``
|
|
||||||
The global-level theme to be set.
|
|
||||||
|
|
||||||
``theme_level``
|
|
||||||
Defaults to *``ThemeLevel.Global``*. The theme level, can be
|
|
||||||
``ThemeLevel.Global``, ``ThemeLevel.Service`` or
|
|
||||||
``ThemeLevel.Song``.
|
|
||||||
"""
|
|
||||||
self.global_theme = global_theme
|
|
||||||
self.theme_level = theme_level
|
|
||||||
self.global_theme_data = \
|
|
||||||
self.theme_manager.getThemeData(self.global_theme)
|
|
||||||
self.theme_data = None
|
|
||||||
|
|
||||||
def set_service_theme(self, service_theme):
|
|
||||||
"""
|
|
||||||
Set the service-level theme.
|
|
||||||
|
|
||||||
``service_theme``
|
|
||||||
The service-level theme to be set.
|
|
||||||
"""
|
|
||||||
self.service_theme = service_theme
|
|
||||||
self.theme_data = None
|
|
||||||
|
|
||||||
def set_override_theme(self, theme, overrideLevels=False):
|
|
||||||
"""
|
|
||||||
Set the appropriate theme depending on the theme level.
|
|
||||||
Called by the service item when building a display frame
|
|
||||||
|
|
||||||
``theme``
|
|
||||||
The name of the song-level theme. None means the service
|
|
||||||
item wants to use the given value.
|
|
||||||
|
|
||||||
``overrideLevels``
|
|
||||||
Used to force the theme data passed in to be used.
|
|
||||||
|
|
||||||
"""
|
|
||||||
log.debug(u'set override theme to %s', theme)
|
|
||||||
theme_level = self.theme_level
|
|
||||||
if overrideLevels:
|
|
||||||
theme_level = ThemeLevel.Song
|
|
||||||
if theme_level == ThemeLevel.Global:
|
|
||||||
self.theme = self.global_theme
|
|
||||||
elif theme_level == ThemeLevel.Service:
|
|
||||||
if self.service_theme == u'':
|
|
||||||
self.theme = self.global_theme
|
|
||||||
else:
|
|
||||||
self.theme = self.service_theme
|
|
||||||
else:
|
|
||||||
# Images have a theme of -1
|
|
||||||
if theme and theme != -1:
|
|
||||||
self.theme = theme
|
|
||||||
elif theme_level == ThemeLevel.Song or \
|
|
||||||
theme_level == ThemeLevel.Service:
|
|
||||||
if self.service_theme == u'':
|
|
||||||
self.theme = self.global_theme
|
|
||||||
else:
|
|
||||||
self.theme = self.service_theme
|
|
||||||
else:
|
|
||||||
self.theme = self.global_theme
|
|
||||||
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.theme_data = theme
|
|
||||||
else:
|
|
||||||
self.theme_data = self.theme_manager.getThemeData(self.theme)
|
|
||||||
self.calculate_default(self.screens.current[u'size'])
|
|
||||||
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):
|
|
||||||
"""
|
|
||||||
Builds a text block using the settings in ``theme``
|
|
||||||
and the size of the display screen.height.
|
|
||||||
|
|
||||||
``theme``
|
|
||||||
The theme to build a text block for.
|
|
||||||
"""
|
|
||||||
log.debug(u'build_text_rectangle')
|
|
||||||
main_rect = None
|
|
||||||
footer_rect = None
|
|
||||||
if not theme.font_main_override:
|
|
||||||
main_rect = QtCore.QRect(10, 0, self.width - 20, self.footer_start)
|
|
||||||
else:
|
|
||||||
main_rect = QtCore.QRect(theme.font_main_x, theme.font_main_y,
|
|
||||||
theme.font_main_width - 1, theme.font_main_height - 1)
|
|
||||||
if not theme.font_footer_override:
|
|
||||||
footer_rect = QtCore.QRect(10, self.footer_start, self.width - 20,
|
|
||||||
self.height - self.footer_start)
|
|
||||||
else:
|
|
||||||
footer_rect = QtCore.QRect(theme.font_footer_x,
|
|
||||||
theme.font_footer_y, theme.font_footer_width - 1,
|
|
||||||
theme.font_footer_height - 1)
|
|
||||||
self.renderer.set_text_rectangle(main_rect, footer_rect)
|
|
||||||
|
|
||||||
def generate_preview(self, theme_data, force_page=False):
|
|
||||||
"""
|
|
||||||
Generate a preview of a theme.
|
|
||||||
|
|
||||||
``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'])
|
|
||||||
# build a service item to generate preview
|
|
||||||
serviceItem = ServiceItem()
|
|
||||||
serviceItem.theme = theme_data
|
|
||||||
if self.force_page:
|
|
||||||
# make big page for theme edit dialog to get line count
|
|
||||||
serviceItem.add_from_text(u'', VERSE + VERSE + VERSE, FOOTER)
|
|
||||||
else:
|
|
||||||
self.image_manager.del_image(theme_data.theme_name)
|
|
||||||
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)
|
|
||||||
# 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):
|
|
||||||
"""
|
|
||||||
Calculate how much text can fit on a slide.
|
|
||||||
|
|
||||||
``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, self.force_page)
|
|
||||||
|
|
||||||
def calculate_default(self, screen):
|
|
||||||
"""
|
|
||||||
Calculate the default dimentions of the screen.
|
|
||||||
|
|
||||||
``screen``
|
|
||||||
The QSize of the screen.
|
|
||||||
"""
|
|
||||||
log.debug(u'calculate default %s', screen)
|
|
||||||
self.width = screen.width()
|
|
||||||
self.height = screen.height()
|
|
||||||
self.screen_ratio = float(self.height) / float(self.width)
|
|
||||||
log.debug(u'calculate default %d, %d, %f',
|
|
||||||
self.width, self.height, self.screen_ratio)
|
|
||||||
# 90% is start of footer
|
|
||||||
self.footer_start = int(self.height * 0.90)
|
|
@ -63,6 +63,8 @@ class ItemCapabilities(object):
|
|||||||
ProvidesOwnDisplay = 10
|
ProvidesOwnDisplay = 10
|
||||||
AllowsDetailedTitleDisplay = 11
|
AllowsDetailedTitleDisplay = 11
|
||||||
AllowsVariableStartTime = 12
|
AllowsVariableStartTime = 12
|
||||||
|
AllowsVirtualSplit = 13
|
||||||
|
AllowsWordSplit = 14
|
||||||
|
|
||||||
|
|
||||||
class ServiceItem(object):
|
class ServiceItem(object):
|
||||||
@ -81,7 +83,7 @@ class ServiceItem(object):
|
|||||||
The plugin that this service item belongs to.
|
The plugin that this service item belongs to.
|
||||||
"""
|
"""
|
||||||
if plugin:
|
if plugin:
|
||||||
self.render_manager = plugin.renderManager
|
self.renderer = plugin.renderer
|
||||||
self.name = plugin.name
|
self.name = plugin.name
|
||||||
self.title = u''
|
self.title = u''
|
||||||
self.shortname = u''
|
self.shortname = u''
|
||||||
@ -151,7 +153,7 @@ class ServiceItem(object):
|
|||||||
self.icon = icon
|
self.icon = icon
|
||||||
self.iconic_representation = build_icon(icon)
|
self.iconic_representation = build_icon(icon)
|
||||||
|
|
||||||
def render(self, useOverride=False):
|
def render(self, use_override=False):
|
||||||
"""
|
"""
|
||||||
The render method is what generates the frames for the screen and
|
The render method is what generates the frames for the screen and
|
||||||
obtains the display information from the renderemanager.
|
obtains the display information from the renderemanager.
|
||||||
@ -161,24 +163,23 @@ class ServiceItem(object):
|
|||||||
log.debug(u'Render called')
|
log.debug(u'Render called')
|
||||||
self._display_frames = []
|
self._display_frames = []
|
||||||
self.bg_image_bytes = None
|
self.bg_image_bytes = None
|
||||||
line_break = True
|
line_break = not self.is_capable(ItemCapabilities.NoLineBreaks)
|
||||||
if self.is_capable(ItemCapabilities.NoLineBreaks):
|
|
||||||
line_break = False
|
|
||||||
theme = self.theme if self.theme else None
|
theme = self.theme if self.theme else None
|
||||||
self.main, self.footer = \
|
self.main, self.footer = \
|
||||||
self.render_manager.set_override_theme(theme, useOverride)
|
self.renderer.set_override_theme(theme, use_override)
|
||||||
self.themedata = self.render_manager.renderer._theme
|
self.themedata = self.renderer.theme_data
|
||||||
if self.service_item_type == ServiceItemType.Text:
|
if self.service_item_type == ServiceItemType.Text:
|
||||||
log.debug(u'Formatting slides')
|
log.debug(u'Formatting slides')
|
||||||
for slide in self._raw_frames:
|
for slide in self._raw_frames:
|
||||||
formatted = self.render_manager \
|
formatted = self.renderer \
|
||||||
.format_slide(slide[u'raw_slide'], line_break)
|
.format_slide(slide[u'raw_slide'], line_break, self)
|
||||||
for page in formatted:
|
for page in formatted:
|
||||||
self._display_frames.append(
|
self._display_frames.append({
|
||||||
{u'title': clean_tags(page),
|
u'title': clean_tags(page),
|
||||||
u'text': clean_tags(page.rstrip()),
|
u'text': clean_tags(page.rstrip()),
|
||||||
u'html': expand_tags(page.rstrip()),
|
u'html': expand_tags(page.rstrip()),
|
||||||
u'verseTag': slide[u'verseTag'] })
|
u'verseTag': slide[u'verseTag']
|
||||||
|
})
|
||||||
elif self.service_item_type == ServiceItemType.Image or \
|
elif self.service_item_type == ServiceItemType.Image or \
|
||||||
self.service_item_type == ServiceItemType.Command:
|
self.service_item_type == ServiceItemType.Command:
|
||||||
pass
|
pass
|
||||||
@ -205,7 +206,7 @@ class ServiceItem(object):
|
|||||||
"""
|
"""
|
||||||
self.service_item_type = ServiceItemType.Image
|
self.service_item_type = ServiceItemType.Image
|
||||||
self._raw_frames.append({u'title': title, u'path': path})
|
self._raw_frames.append({u'title': title, u'path': path})
|
||||||
self.render_manager.image_manager.add_image(title, path)
|
self.renderer.image_manager.add_image(title, path)
|
||||||
self._new_item()
|
self._new_item()
|
||||||
|
|
||||||
def add_from_text(self, title, raw_slide, verse_tag=None):
|
def add_from_text(self, title, raw_slide, verse_tag=None):
|
||||||
@ -453,4 +454,5 @@ class ServiceItem(object):
|
|||||||
elif not start and end:
|
elif not start and end:
|
||||||
return end
|
return end
|
||||||
else:
|
else:
|
||||||
return u'%s : %s' % (start, end)
|
return u'%s : %s' % (start, end)
|
||||||
|
|
||||||
|
@ -70,6 +70,8 @@ class MainDisplay(DisplayWidget):
|
|||||||
self.videoHide = False
|
self.videoHide = False
|
||||||
self.override = {}
|
self.override = {}
|
||||||
self.retranslateUi()
|
self.retranslateUi()
|
||||||
|
self.mediaObject = None
|
||||||
|
self.firstTime = True
|
||||||
self.setStyleSheet(u'border: 0px; margin: 0px; padding: 0px;')
|
self.setStyleSheet(u'border: 0px; margin: 0px; padding: 0px;')
|
||||||
self.setWindowFlags(QtCore.Qt.FramelessWindowHint | QtCore.Qt.Tool |
|
self.setWindowFlags(QtCore.Qt.FramelessWindowHint | QtCore.Qt.Tool |
|
||||||
QtCore.Qt.WindowStaysOnTopHint)
|
QtCore.Qt.WindowStaysOnTopHint)
|
||||||
@ -78,6 +80,9 @@ class MainDisplay(DisplayWidget):
|
|||||||
QtCore.SIGNAL(u'maindisplay_hide'), self.hideDisplay)
|
QtCore.SIGNAL(u'maindisplay_hide'), self.hideDisplay)
|
||||||
QtCore.QObject.connect(Receiver.get_receiver(),
|
QtCore.QObject.connect(Receiver.get_receiver(),
|
||||||
QtCore.SIGNAL(u'maindisplay_show'), self.showDisplay)
|
QtCore.SIGNAL(u'maindisplay_show'), self.showDisplay)
|
||||||
|
QtCore.QObject.connect(Receiver.get_receiver(),
|
||||||
|
QtCore.SIGNAL(u'openlp_phonon_creation'),
|
||||||
|
self.createMediaObject)
|
||||||
|
|
||||||
def retranslateUi(self):
|
def retranslateUi(self):
|
||||||
"""
|
"""
|
||||||
@ -102,19 +107,9 @@ class MainDisplay(DisplayWidget):
|
|||||||
self.videoWidget.setGeometry(QtCore.QRect(0, 0,
|
self.videoWidget.setGeometry(QtCore.QRect(0, 0,
|
||||||
self.screen[u'size'].width(), self.screen[u'size'].height()))
|
self.screen[u'size'].width(), self.screen[u'size'].height()))
|
||||||
log.debug(u'Setup Phonon for monitor %s' % self.screens.monitor_number)
|
log.debug(u'Setup Phonon for monitor %s' % self.screens.monitor_number)
|
||||||
self.mediaObject = Phonon.MediaObject(self)
|
if self.isLive:
|
||||||
self.audio = Phonon.AudioOutput(Phonon.VideoCategory, self.mediaObject)
|
if not self.firstTime:
|
||||||
Phonon.createPath(self.mediaObject, self.videoWidget)
|
self.createMediaObject()
|
||||||
Phonon.createPath(self.mediaObject, self.audio)
|
|
||||||
QtCore.QObject.connect(self.mediaObject,
|
|
||||||
QtCore.SIGNAL(u'stateChanged(Phonon::State, Phonon::State)'),
|
|
||||||
self.videoState)
|
|
||||||
QtCore.QObject.connect(self.mediaObject,
|
|
||||||
QtCore.SIGNAL(u'finished()'),
|
|
||||||
self.videoFinished)
|
|
||||||
QtCore.QObject.connect(self.mediaObject,
|
|
||||||
QtCore.SIGNAL(u'tick(qint64)'),
|
|
||||||
self.videoTick)
|
|
||||||
log.debug(u'Setup webView for monitor %s' % self.screens.monitor_number)
|
log.debug(u'Setup webView for monitor %s' % self.screens.monitor_number)
|
||||||
self.webView = QtWebKit.QWebView(self)
|
self.webView = QtWebKit.QWebView(self)
|
||||||
self.webView.setGeometry(0, 0,
|
self.webView.setGeometry(0, 0,
|
||||||
@ -175,6 +170,24 @@ class MainDisplay(DisplayWidget):
|
|||||||
log.debug(
|
log.debug(
|
||||||
u'Finished setup for monitor %s' % self.screens.monitor_number)
|
u'Finished setup for monitor %s' % self.screens.monitor_number)
|
||||||
|
|
||||||
|
def createMediaObject(self):
|
||||||
|
self.firstTime = False
|
||||||
|
log.debug(u'Creating Phonon objects - Start for %s', self.isLive)
|
||||||
|
self.mediaObject = Phonon.MediaObject(self)
|
||||||
|
self.audio = Phonon.AudioOutput(Phonon.VideoCategory, self.mediaObject)
|
||||||
|
Phonon.createPath(self.mediaObject, self.videoWidget)
|
||||||
|
Phonon.createPath(self.mediaObject, self.audio)
|
||||||
|
QtCore.QObject.connect(self.mediaObject,
|
||||||
|
QtCore.SIGNAL(u'stateChanged(Phonon::State, Phonon::State)'),
|
||||||
|
self.videoState)
|
||||||
|
QtCore.QObject.connect(self.mediaObject,
|
||||||
|
QtCore.SIGNAL(u'finished()'),
|
||||||
|
self.videoFinished)
|
||||||
|
QtCore.QObject.connect(self.mediaObject,
|
||||||
|
QtCore.SIGNAL(u'tick(qint64)'),
|
||||||
|
self.videoTick)
|
||||||
|
log.debug(u'Creating Phonon objects - Finished for %s', self.isLive)
|
||||||
|
|
||||||
def text(self, slide):
|
def text(self, slide):
|
||||||
"""
|
"""
|
||||||
Add the slide text from slideController
|
Add the slide text from slideController
|
||||||
@ -348,6 +361,8 @@ class MainDisplay(DisplayWidget):
|
|||||||
"""
|
"""
|
||||||
Loads and starts a video to run with the option of sound
|
Loads and starts a video to run with the option of sound
|
||||||
"""
|
"""
|
||||||
|
if not self.mediaObject:
|
||||||
|
self.createMediaObject()
|
||||||
log.debug(u'video')
|
log.debug(u'video')
|
||||||
self.webLoaded = True
|
self.webLoaded = True
|
||||||
self.setGeometry(self.screen[u'size'])
|
self.setGeometry(self.screen[u'size'])
|
||||||
|
@ -30,7 +30,7 @@ from tempfile import gettempdir
|
|||||||
|
|
||||||
from PyQt4 import QtCore, QtGui
|
from PyQt4 import QtCore, QtGui
|
||||||
|
|
||||||
from openlp.core.lib import RenderManager, build_icon, OpenLPDockWidget, \
|
from openlp.core.lib import Renderer, build_icon, OpenLPDockWidget, \
|
||||||
SettingsManager, PluginManager, Receiver, translate
|
SettingsManager, PluginManager, Receiver, translate
|
||||||
from openlp.core.lib.ui import UiStrings, base_action, checkable_action, \
|
from openlp.core.lib.ui import UiStrings, base_action, checkable_action, \
|
||||||
icon_action, shortcut_action
|
icon_action, shortcut_action
|
||||||
@ -122,12 +122,17 @@ class Ui_MainWindow(object):
|
|||||||
self.HelpMenu = QtGui.QMenu(self.MenuBar)
|
self.HelpMenu = QtGui.QMenu(self.MenuBar)
|
||||||
self.HelpMenu.setObjectName(u'HelpMenu')
|
self.HelpMenu.setObjectName(u'HelpMenu')
|
||||||
mainWindow.setMenuBar(self.MenuBar)
|
mainWindow.setMenuBar(self.MenuBar)
|
||||||
self.StatusBar = QtGui.QStatusBar(mainWindow)
|
self.statusBar = QtGui.QStatusBar(mainWindow)
|
||||||
self.StatusBar.setObjectName(u'StatusBar')
|
self.statusBar.setObjectName(u'statusBar')
|
||||||
mainWindow.setStatusBar(self.StatusBar)
|
mainWindow.setStatusBar(self.statusBar)
|
||||||
self.DefaultThemeLabel = QtGui.QLabel(self.StatusBar)
|
self.loadProgressBar = QtGui.QProgressBar(self.statusBar)
|
||||||
self.DefaultThemeLabel.setObjectName(u'DefaultThemeLabel')
|
self.loadProgressBar.setObjectName(u'loadProgressBar')
|
||||||
self.StatusBar.addPermanentWidget(self.DefaultThemeLabel)
|
self.statusBar.addPermanentWidget(self.loadProgressBar)
|
||||||
|
self.loadProgressBar.hide()
|
||||||
|
self.loadProgressBar.setValue(0)
|
||||||
|
self.defaultThemeLabel = QtGui.QLabel(self.statusBar)
|
||||||
|
self.defaultThemeLabel.setObjectName(u'defaultThemeLabel')
|
||||||
|
self.statusBar.addPermanentWidget(self.defaultThemeLabel)
|
||||||
# Create the MediaManager
|
# Create the MediaManager
|
||||||
self.mediaManagerDock = OpenLPDockWidget(mainWindow,
|
self.mediaManagerDock = OpenLPDockWidget(mainWindow,
|
||||||
u'mediaManagerDock', u':/system/system_mediamanager.png')
|
u'mediaManagerDock', u':/system/system_mediamanager.png')
|
||||||
@ -545,9 +550,9 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
|
|||||||
QtCore.SIGNAL(u'openlp_information_message'),
|
QtCore.SIGNAL(u'openlp_information_message'),
|
||||||
self.onInformationMessage)
|
self.onInformationMessage)
|
||||||
# warning cyclic dependency
|
# warning cyclic dependency
|
||||||
# RenderManager needs to call ThemeManager and
|
# renderer needs to call ThemeManager and
|
||||||
# ThemeManager needs to call RenderManager
|
# ThemeManager needs to call Renderer
|
||||||
self.renderManager = RenderManager(
|
self.renderer = Renderer(
|
||||||
self.themeManagerContents, self.screens)
|
self.themeManagerContents, self.screens)
|
||||||
# Define the media Dock Manager
|
# Define the media Dock Manager
|
||||||
self.mediaDockManager = MediaDockManager(self.MediaToolBox)
|
self.mediaDockManager = MediaDockManager(self.MediaToolBox)
|
||||||
@ -555,7 +560,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
|
|||||||
# make the controllers available to the plugins
|
# make the controllers available to the plugins
|
||||||
self.pluginHelpers[u'preview'] = self.previewController
|
self.pluginHelpers[u'preview'] = self.previewController
|
||||||
self.pluginHelpers[u'live'] = self.liveController
|
self.pluginHelpers[u'live'] = self.liveController
|
||||||
self.pluginHelpers[u'render'] = self.renderManager
|
self.pluginHelpers[u'renderer'] = self.renderer
|
||||||
self.pluginHelpers[u'service'] = self.ServiceManagerContents
|
self.pluginHelpers[u'service'] = self.ServiceManagerContents
|
||||||
self.pluginHelpers[u'settings form'] = self.settingsForm
|
self.pluginHelpers[u'settings form'] = self.settingsForm
|
||||||
self.pluginHelpers[u'toolbox'] = self.mediaDockManager
|
self.pluginHelpers[u'toolbox'] = self.mediaDockManager
|
||||||
@ -781,7 +786,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
|
|||||||
their locations
|
their locations
|
||||||
"""
|
"""
|
||||||
log.debug(u'screenChanged')
|
log.debug(u'screenChanged')
|
||||||
self.renderManager.update_display()
|
self.renderer.update_display()
|
||||||
self.setFocus()
|
self.setFocus()
|
||||||
self.activateWindow()
|
self.activateWindow()
|
||||||
|
|
||||||
@ -880,10 +885,10 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
|
|||||||
self.setWindowTitle(title)
|
self.setWindowTitle(title)
|
||||||
|
|
||||||
def showStatusMessage(self, message):
|
def showStatusMessage(self, message):
|
||||||
self.StatusBar.showMessage(message)
|
self.statusBar.showMessage(message)
|
||||||
|
|
||||||
def defaultThemeChanged(self, theme):
|
def defaultThemeChanged(self, theme):
|
||||||
self.DefaultThemeLabel.setText(
|
self.defaultThemeLabel.setText(
|
||||||
unicode(translate('OpenLP.MainWindow', 'Default Theme: %s')) %
|
unicode(translate('OpenLP.MainWindow', 'Default Theme: %s')) %
|
||||||
theme)
|
theme)
|
||||||
|
|
||||||
@ -979,7 +984,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
|
|||||||
for fileId, filename in enumerate(recentFilesToDisplay):
|
for fileId, filename in enumerate(recentFilesToDisplay):
|
||||||
log.debug('Recent file name: %s', filename)
|
log.debug('Recent file name: %s', filename)
|
||||||
action = base_action(self, u'')
|
action = base_action(self, u'')
|
||||||
action.setText(u'&%d %s' %
|
action.setText(u'&%d %s' %
|
||||||
(fileId + 1, QtCore.QFileInfo(filename).fileName()))
|
(fileId + 1, QtCore.QFileInfo(filename).fileName()))
|
||||||
action.setData(QtCore.QVariant(filename))
|
action.setData(QtCore.QVariant(filename))
|
||||||
self.connect(action, QtCore.SIGNAL(u'triggered()'),
|
self.connect(action, QtCore.SIGNAL(u'triggered()'),
|
||||||
@ -1008,3 +1013,34 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
|
|||||||
while self.recentFiles.count() > maxRecentFiles:
|
while self.recentFiles.count() > maxRecentFiles:
|
||||||
# Don't care what API says takeLast works, removeLast doesn't!
|
# Don't care what API says takeLast works, removeLast doesn't!
|
||||||
self.recentFiles.takeLast()
|
self.recentFiles.takeLast()
|
||||||
|
|
||||||
|
def displayProgressBar(self, size):
|
||||||
|
"""
|
||||||
|
Make Progress bar visible and set size
|
||||||
|
"""
|
||||||
|
self.loadProgressBar.show()
|
||||||
|
self.loadProgressBar.setMaximum(size)
|
||||||
|
self.loadProgressBar.setValue(0)
|
||||||
|
Receiver.send_message(u'openlp_process_events')
|
||||||
|
|
||||||
|
def incrementProgressBar(self):
|
||||||
|
"""
|
||||||
|
Increase the Progress Bar value by 1
|
||||||
|
"""
|
||||||
|
self.loadProgressBar.setValue(self.loadProgressBar.value() + 1)
|
||||||
|
Receiver.send_message(u'openlp_process_events')
|
||||||
|
|
||||||
|
def finishedProgressBar(self):
|
||||||
|
"""
|
||||||
|
Trigger it's removal after 2.5 second
|
||||||
|
"""
|
||||||
|
self.timer_id = self.startTimer(2500)
|
||||||
|
|
||||||
|
def timerEvent(self, event):
|
||||||
|
"""
|
||||||
|
Remove the Progress bar from view.
|
||||||
|
"""
|
||||||
|
if event.timerId() == self.timer_id:
|
||||||
|
self.timer_id = 0
|
||||||
|
self.loadProgressBar.hide()
|
||||||
|
Receiver.send_message(u'openlp_process_events')
|
||||||
|
@ -460,7 +460,11 @@ class ServiceManager(QtGui.QWidget):
|
|||||||
service = []
|
service = []
|
||||||
write_list = []
|
write_list = []
|
||||||
total_size = 0
|
total_size = 0
|
||||||
|
Receiver.send_message(u'cursor_busy')
|
||||||
|
# Number of items + 1 to zip it
|
||||||
|
self.mainwindow.displayProgressBar(len(self.serviceItems) + 1)
|
||||||
for item in self.serviceItems:
|
for item in self.serviceItems:
|
||||||
|
self.mainwindow.incrementProgressBar()
|
||||||
service.append({u'serviceitem':
|
service.append({u'serviceitem':
|
||||||
item[u'service_item'].get_service_repr()})
|
item[u'service_item'].get_service_repr()})
|
||||||
if not item[u'service_item'].uses_file():
|
if not item[u'service_item'].uses_file():
|
||||||
@ -501,6 +505,7 @@ class ServiceManager(QtGui.QWidget):
|
|||||||
log.debug(u'ServiceManager.saveFile - allowZip64 is %s' % allow_zip_64)
|
log.debug(u'ServiceManager.saveFile - allowZip64 is %s' % allow_zip_64)
|
||||||
zip = None
|
zip = None
|
||||||
success = True
|
success = True
|
||||||
|
self.mainwindow.incrementProgressBar()
|
||||||
try:
|
try:
|
||||||
zip = zipfile.ZipFile(path_file_name, 'w', zipfile.ZIP_STORED,
|
zip = zipfile.ZipFile(path_file_name, 'w', zipfile.ZIP_STORED,
|
||||||
allow_zip_64)
|
allow_zip_64)
|
||||||
@ -516,6 +521,8 @@ class ServiceManager(QtGui.QWidget):
|
|||||||
finally:
|
finally:
|
||||||
if zip:
|
if zip:
|
||||||
zip.close()
|
zip.close()
|
||||||
|
self.mainwindow.finishedProgressBar()
|
||||||
|
Receiver.send_message(u'cursor_normal')
|
||||||
if success:
|
if success:
|
||||||
self.mainwindow.addRecentFile(path_file_name)
|
self.mainwindow.addRecentFile(path_file_name)
|
||||||
self.setModified(False)
|
self.setModified(False)
|
||||||
@ -576,13 +583,15 @@ class ServiceManager(QtGui.QWidget):
|
|||||||
items = cPickle.load(fileTo)
|
items = cPickle.load(fileTo)
|
||||||
fileTo.close()
|
fileTo.close()
|
||||||
self.newFile()
|
self.newFile()
|
||||||
|
self.mainwindow.displayProgressBar(len(items))
|
||||||
for item in items:
|
for item in items:
|
||||||
|
self.mainwindow.incrementProgressBar()
|
||||||
serviceItem = ServiceItem()
|
serviceItem = ServiceItem()
|
||||||
serviceItem.from_service = True
|
serviceItem.from_service = True
|
||||||
serviceItem.render_manager = self.mainwindow.renderManager
|
serviceItem.renderer = self.mainwindow.renderer
|
||||||
serviceItem.set_from_service(item, self.servicePath)
|
serviceItem.set_from_service(item, self.servicePath)
|
||||||
self.validateItem(serviceItem)
|
self.validateItem(serviceItem)
|
||||||
self.addServiceItem(serviceItem)
|
self.addServiceItem(serviceItem, repaint=False)
|
||||||
if serviceItem.is_capable(ItemCapabilities.OnLoadUpdate):
|
if serviceItem.is_capable(ItemCapabilities.OnLoadUpdate):
|
||||||
Receiver.send_message(u'%s_service_load' %
|
Receiver.send_message(u'%s_service_load' %
|
||||||
serviceItem.name.lower(), serviceItem)
|
serviceItem.name.lower(), serviceItem)
|
||||||
@ -592,7 +601,6 @@ class ServiceManager(QtGui.QWidget):
|
|||||||
self.setModified(False)
|
self.setModified(False)
|
||||||
QtCore.QSettings().setValue(
|
QtCore.QSettings().setValue(
|
||||||
'service/last file', QtCore.QVariant(fileName))
|
'service/last file', QtCore.QVariant(fileName))
|
||||||
Receiver.send_message(u'cursor_normal')
|
|
||||||
else:
|
else:
|
||||||
critical_error_message_box(
|
critical_error_message_box(
|
||||||
message=translate('OpenLP.ServiceManager',
|
message=translate('OpenLP.ServiceManager',
|
||||||
@ -623,6 +631,9 @@ class ServiceManager(QtGui.QWidget):
|
|||||||
fileTo.close()
|
fileTo.close()
|
||||||
if zip:
|
if zip:
|
||||||
zip.close()
|
zip.close()
|
||||||
|
self.mainwindow.finishedProgressBar()
|
||||||
|
Receiver.send_message(u'cursor_normal')
|
||||||
|
self.repaintServiceList(-1, -1)
|
||||||
|
|
||||||
def loadLastFile(self):
|
def loadLastFile(self):
|
||||||
"""
|
"""
|
||||||
@ -989,7 +1000,7 @@ class ServiceManager(QtGui.QWidget):
|
|||||||
"""
|
"""
|
||||||
log.debug(u'onThemeComboBoxSelected')
|
log.debug(u'onThemeComboBoxSelected')
|
||||||
self.service_theme = unicode(self.themeComboBox.currentText())
|
self.service_theme = unicode(self.themeComboBox.currentText())
|
||||||
self.mainwindow.renderManager.set_service_theme(self.service_theme)
|
self.mainwindow.renderer.set_service_theme(self.service_theme)
|
||||||
QtCore.QSettings().setValue(
|
QtCore.QSettings().setValue(
|
||||||
self.mainwindow.serviceSettingsSection + u'/service theme',
|
self.mainwindow.serviceSettingsSection + u'/service theme',
|
||||||
QtCore.QVariant(self.service_theme))
|
QtCore.QVariant(self.service_theme))
|
||||||
@ -1001,7 +1012,7 @@ class ServiceManager(QtGui.QWidget):
|
|||||||
sure the theme combo box is in the correct state.
|
sure the theme combo box is in the correct state.
|
||||||
"""
|
"""
|
||||||
log.debug(u'themeChange')
|
log.debug(u'themeChange')
|
||||||
if self.mainwindow.renderManager.theme_level == ThemeLevel.Global:
|
if self.mainwindow.renderer.theme_level == ThemeLevel.Global:
|
||||||
self.toolbar.actions[u'ThemeLabel'].setVisible(False)
|
self.toolbar.actions[u'ThemeLabel'].setVisible(False)
|
||||||
self.toolbar.actions[u'ThemeWidget'].setVisible(False)
|
self.toolbar.actions[u'ThemeWidget'].setVisible(False)
|
||||||
else:
|
else:
|
||||||
@ -1016,7 +1027,7 @@ class ServiceManager(QtGui.QWidget):
|
|||||||
Receiver.send_message(u'cursor_busy')
|
Receiver.send_message(u'cursor_busy')
|
||||||
log.debug(u'regenerateServiceItems')
|
log.debug(u'regenerateServiceItems')
|
||||||
# force reset of renderer as theme data has changed
|
# force reset of renderer as theme data has changed
|
||||||
self.mainwindow.renderManager.themedata = None
|
self.mainwindow.renderer.themedata = None
|
||||||
if self.serviceItems:
|
if self.serviceItems:
|
||||||
tempServiceItems = self.serviceItems
|
tempServiceItems = self.serviceItems
|
||||||
self.serviceManagerList.clear()
|
self.serviceManagerList.clear()
|
||||||
@ -1056,7 +1067,8 @@ class ServiceManager(QtGui.QWidget):
|
|||||||
newItem)
|
newItem)
|
||||||
self.setModified()
|
self.setModified()
|
||||||
|
|
||||||
def addServiceItem(self, item, rebuild=False, expand=None, replace=False):
|
def addServiceItem(self, item, rebuild=False, expand=None, replace=False,
|
||||||
|
repaint=True):
|
||||||
"""
|
"""
|
||||||
Add a Service item to the list
|
Add a Service item to the list
|
||||||
|
|
||||||
@ -1089,7 +1101,8 @@ class ServiceManager(QtGui.QWidget):
|
|||||||
self.serviceItems.append({u'service_item': item,
|
self.serviceItems.append({u'service_item': item,
|
||||||
u'order': len(self.serviceItems) + 1,
|
u'order': len(self.serviceItems) + 1,
|
||||||
u'expanded': expand})
|
u'expanded': expand})
|
||||||
self.repaintServiceList(len(self.serviceItems) - 1, -1)
|
if repaint:
|
||||||
|
self.repaintServiceList(len(self.serviceItems) - 1, -1)
|
||||||
else:
|
else:
|
||||||
self.serviceItems.insert(self.dropPosition,
|
self.serviceItems.insert(self.dropPosition,
|
||||||
{u'service_item': item, u'order': self.dropPosition,
|
{u'service_item': item, u'order': self.dropPosition,
|
||||||
@ -1278,7 +1291,7 @@ class ServiceManager(QtGui.QWidget):
|
|||||||
self.onThemeChangeAction, context=QtCore.Qt.WidgetShortcut)
|
self.onThemeChangeAction, context=QtCore.Qt.WidgetShortcut)
|
||||||
self.themeMenu.addAction(action)
|
self.themeMenu.addAction(action)
|
||||||
find_and_set_in_combo_box(self.themeComboBox, self.service_theme)
|
find_and_set_in_combo_box(self.themeComboBox, self.service_theme)
|
||||||
self.mainwindow.renderManager.set_service_theme(self.service_theme)
|
self.mainwindow.renderer.set_service_theme(self.service_theme)
|
||||||
self.regenerateServiceItems()
|
self.regenerateServiceItems()
|
||||||
|
|
||||||
def onThemeChangeAction(self):
|
def onThemeChangeAction(self):
|
||||||
|
@ -180,16 +180,25 @@ class SlideController(QtGui.QWidget):
|
|||||||
self.hideMenu.menu().addAction(self.themeScreen)
|
self.hideMenu.menu().addAction(self.themeScreen)
|
||||||
self.hideMenu.menu().addAction(self.desktopScreen)
|
self.hideMenu.menu().addAction(self.desktopScreen)
|
||||||
self.toolbar.addToolbarSeparator(u'Loop Separator')
|
self.toolbar.addToolbarSeparator(u'Loop Separator')
|
||||||
self.toolbar.addToolbarButton(
|
startLoop = self.toolbar.addToolbarButton(
|
||||||
# Does not need translating - control string.
|
# Does not need translating - control string.
|
||||||
u'Start Loop', u':/media/media_time.png',
|
u'Start Loop', u':/media/media_time.png',
|
||||||
translate('OpenLP.SlideController', 'Start continuous loop'),
|
translate('OpenLP.SlideController', 'Start continuous loop'),
|
||||||
self.onStartLoop)
|
self.onStartLoop)
|
||||||
self.toolbar.addToolbarButton(
|
action_list = ActionList.get_instance()
|
||||||
|
action_list.add_action(startLoop, UiStrings().LiveToolbar)
|
||||||
|
stopLoop = self.toolbar.addToolbarButton(
|
||||||
# Does not need translating - control string.
|
# Does not need translating - control string.
|
||||||
u'Stop Loop', u':/media/media_stop.png',
|
u'Stop Loop', u':/media/media_stop.png',
|
||||||
translate('OpenLP.SlideController', 'Stop continuous loop'),
|
translate('OpenLP.SlideController', 'Stop continuous loop'),
|
||||||
self.onStopLoop)
|
self.onStopLoop)
|
||||||
|
action_list.add_action(stopLoop, UiStrings().LiveToolbar)
|
||||||
|
self.toogleLoop = shortcut_action(self, u'toogleLoop',
|
||||||
|
[QtGui.QKeySequence(u'L')], self.onToggleLoop,
|
||||||
|
category=UiStrings().LiveToolbar)
|
||||||
|
self.toogleLoop.setText(translate('OpenLP.SlideController',
|
||||||
|
'Start/Stop continuous loop'))
|
||||||
|
self.addAction(self.toogleLoop)
|
||||||
self.delaySpinBox = QtGui.QSpinBox()
|
self.delaySpinBox = QtGui.QSpinBox()
|
||||||
self.delaySpinBox.setMinimum(1)
|
self.delaySpinBox.setMinimum(1)
|
||||||
self.delaySpinBox.setMaximum(180)
|
self.delaySpinBox.setMaximum(180)
|
||||||
@ -268,15 +277,16 @@ class SlideController(QtGui.QWidget):
|
|||||||
self.slideLayout.setSpacing(0)
|
self.slideLayout.setSpacing(0)
|
||||||
self.slideLayout.setMargin(0)
|
self.slideLayout.setMargin(0)
|
||||||
self.slideLayout.setObjectName(u'SlideLayout')
|
self.slideLayout.setObjectName(u'SlideLayout')
|
||||||
self.mediaObject = Phonon.MediaObject(self)
|
|
||||||
self.video = Phonon.VideoWidget()
|
|
||||||
self.video.setVisible(False)
|
|
||||||
self.audio = Phonon.AudioOutput(Phonon.VideoCategory, self.mediaObject)
|
|
||||||
Phonon.createPath(self.mediaObject, self.video)
|
|
||||||
Phonon.createPath(self.mediaObject, self.audio)
|
|
||||||
if not self.isLive:
|
if not self.isLive:
|
||||||
|
self.mediaObject = Phonon.MediaObject(self)
|
||||||
|
self.video = Phonon.VideoWidget()
|
||||||
|
self.video.setVisible(False)
|
||||||
|
self.audio = Phonon.AudioOutput(Phonon.VideoCategory,
|
||||||
|
self.mediaObject)
|
||||||
|
Phonon.createPath(self.mediaObject, self.video)
|
||||||
|
Phonon.createPath(self.mediaObject, self.audio)
|
||||||
self.video.setGeometry(QtCore.QRect(0, 0, 300, 225))
|
self.video.setGeometry(QtCore.QRect(0, 0, 300, 225))
|
||||||
self.slideLayout.insertWidget(0, self.video)
|
self.slideLayout.insertWidget(0, self.video)
|
||||||
# Actual preview screen
|
# Actual preview screen
|
||||||
self.slidePreview = QtGui.QLabel(self)
|
self.slidePreview = QtGui.QLabel(self)
|
||||||
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed,
|
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed,
|
||||||
@ -380,18 +390,21 @@ class SlideController(QtGui.QWidget):
|
|||||||
action_list.add_action(self.previousItem)
|
action_list.add_action(self.previousItem)
|
||||||
action_list.add_action(self.nextItem)
|
action_list.add_action(self.nextItem)
|
||||||
self.previousService = shortcut_action(parent, u'previousService',
|
self.previousService = shortcut_action(parent, u'previousService',
|
||||||
[QtCore.Qt.Key_Left], self.servicePrevious, UiStrings().LiveToolbar)
|
[QtCore.Qt.Key_Left], self.servicePrevious,
|
||||||
self.previousService.setShortcutContext(QtCore.Qt.WidgetWithChildrenShortcut)
|
category=UiStrings().LiveToolbar,
|
||||||
|
context=QtCore.Qt.WidgetWithChildrenShortcut)
|
||||||
self.previousService.setText(
|
self.previousService.setText(
|
||||||
translate('OpenLP.SlideController', 'Previous Service'))
|
translate('OpenLP.SlideController', 'Previous Service'))
|
||||||
self.nextService = shortcut_action(parent, 'nextService',
|
self.nextService = shortcut_action(parent, 'nextService',
|
||||||
[QtCore.Qt.Key_Right], self.serviceNext, UiStrings().LiveToolbar)
|
[QtCore.Qt.Key_Right], self.serviceNext,
|
||||||
self.nextService.setShortcutContext(QtCore.Qt.WidgetWithChildrenShortcut)
|
category=UiStrings().LiveToolbar,
|
||||||
|
context=QtCore.Qt.WidgetWithChildrenShortcut)
|
||||||
self.nextService.setText(
|
self.nextService.setText(
|
||||||
translate('OpenLP.SlideController', 'Next Service'))
|
translate('OpenLP.SlideController', 'Next Service'))
|
||||||
self.escapeItem = shortcut_action(parent, 'escapeItem',
|
self.escapeItem = shortcut_action(parent, 'escapeItem',
|
||||||
[QtCore.Qt.Key_Escape], self.liveEscape, UiStrings().LiveToolbar)
|
[QtCore.Qt.Key_Escape], self.liveEscape,
|
||||||
self.escapeItem.setShortcutContext(QtCore.Qt.WidgetWithChildrenShortcut)
|
category=UiStrings().LiveToolbar,
|
||||||
|
context=QtCore.Qt.WidgetWithChildrenShortcut)
|
||||||
self.escapeItem.setText(
|
self.escapeItem.setText(
|
||||||
translate('OpenLP.SlideController', 'Escape Item'))
|
translate('OpenLP.SlideController', 'Escape Item'))
|
||||||
|
|
||||||
@ -412,7 +425,7 @@ class SlideController(QtGui.QWidget):
|
|||||||
"""
|
"""
|
||||||
# rebuild display as screen size changed
|
# rebuild display as screen size changed
|
||||||
self.display = MainDisplay(self, self.screens, self.isLive)
|
self.display = MainDisplay(self, self.screens, self.isLive)
|
||||||
self.display.imageManager = self.parent.renderManager.image_manager
|
self.display.imageManager = self.parent.renderer.image_manager
|
||||||
self.display.alertTab = self.alertTab
|
self.display.alertTab = self.alertTab
|
||||||
self.display.setup()
|
self.display.setup()
|
||||||
if self.isLive:
|
if self.isLive:
|
||||||
@ -491,6 +504,9 @@ class SlideController(QtGui.QWidget):
|
|||||||
self.mediabar.setVisible(False)
|
self.mediabar.setVisible(False)
|
||||||
self.toolbar.makeWidgetsInvisible([u'Song Menu'])
|
self.toolbar.makeWidgetsInvisible([u'Song Menu'])
|
||||||
self.toolbar.makeWidgetsInvisible(self.loopList)
|
self.toolbar.makeWidgetsInvisible(self.loopList)
|
||||||
|
self.toogleLoop.setEnabled(False)
|
||||||
|
self.toolbar.actions[u'Start Loop'].setEnabled(False)
|
||||||
|
self.toolbar.actions[u'Stop Loop'].setEnabled(False)
|
||||||
self.toolbar.actions[u'Stop Loop'].setVisible(False)
|
self.toolbar.actions[u'Stop Loop'].setVisible(False)
|
||||||
if item.is_text():
|
if item.is_text():
|
||||||
if QtCore.QSettings().value(
|
if QtCore.QSettings().value(
|
||||||
@ -500,6 +516,9 @@ class SlideController(QtGui.QWidget):
|
|||||||
if item.is_capable(ItemCapabilities.AllowsLoop) and \
|
if item.is_capable(ItemCapabilities.AllowsLoop) and \
|
||||||
len(item.get_frames()) > 1:
|
len(item.get_frames()) > 1:
|
||||||
self.toolbar.makeWidgetsVisible(self.loopList)
|
self.toolbar.makeWidgetsVisible(self.loopList)
|
||||||
|
self.toogleLoop.setEnabled(True)
|
||||||
|
self.toolbar.actions[u'Start Loop'].setEnabled(True)
|
||||||
|
self.toolbar.actions[u'Stop Loop'].setEnabled(True)
|
||||||
if item.is_media():
|
if item.is_media():
|
||||||
self.toolbar.setVisible(False)
|
self.toolbar.setVisible(False)
|
||||||
self.mediabar.setVisible(True)
|
self.mediabar.setVisible(True)
|
||||||
@ -614,19 +633,19 @@ class SlideController(QtGui.QWidget):
|
|||||||
label.setScaledContents(True)
|
label.setScaledContents(True)
|
||||||
if self.serviceItem.is_command():
|
if self.serviceItem.is_command():
|
||||||
image = resize_image(frame[u'image'],
|
image = resize_image(frame[u'image'],
|
||||||
self.parent.renderManager.width,
|
self.parent.renderer.width,
|
||||||
self.parent.renderManager.height)
|
self.parent.renderer.height)
|
||||||
else:
|
else:
|
||||||
# If current slide set background to image
|
# If current slide set background to image
|
||||||
if framenumber == slideno:
|
if framenumber == slideno:
|
||||||
self.serviceItem.bg_image_bytes = \
|
self.serviceItem.bg_image_bytes = \
|
||||||
self.parent.renderManager.image_manager. \
|
self.parent.renderer.image_manager. \
|
||||||
get_image_bytes(frame[u'title'])
|
get_image_bytes(frame[u'title'])
|
||||||
image = self.parent.renderManager.image_manager. \
|
image = self.parent.renderer.image_manager. \
|
||||||
get_image(frame[u'title'])
|
get_image(frame[u'title'])
|
||||||
label.setPixmap(QtGui.QPixmap.fromImage(image))
|
label.setPixmap(QtGui.QPixmap.fromImage(image))
|
||||||
self.previewListWidget.setCellWidget(framenumber, 0, label)
|
self.previewListWidget.setCellWidget(framenumber, 0, label)
|
||||||
slideHeight = width * self.parent.renderManager.screen_ratio
|
slideHeight = width * self.parent.renderer.screen_ratio
|
||||||
row += 1
|
row += 1
|
||||||
text.append(unicode(row))
|
text.append(unicode(row))
|
||||||
self.previewListWidget.setItem(framenumber, 0, item)
|
self.previewListWidget.setItem(framenumber, 0, item)
|
||||||
@ -992,6 +1011,15 @@ class SlideController(QtGui.QWidget):
|
|||||||
self.previewListWidget.rowCount() - 1)
|
self.previewListWidget.rowCount() - 1)
|
||||||
self.slideSelected()
|
self.slideSelected()
|
||||||
|
|
||||||
|
def onToggleLoop(self, toggled):
|
||||||
|
"""
|
||||||
|
Toggles the loop state.
|
||||||
|
"""
|
||||||
|
if self.toolbar.actions[u'Start Loop'].isVisible():
|
||||||
|
self.onStartLoop()
|
||||||
|
else:
|
||||||
|
self.onStopLoop()
|
||||||
|
|
||||||
def onStartLoop(self):
|
def onStartLoop(self):
|
||||||
"""
|
"""
|
||||||
Start the timer loop running and store the timer id
|
Start the timer loop running and store the timer id
|
||||||
@ -1150,4 +1178,4 @@ class SlideController(QtGui.QWidget):
|
|||||||
elif self.desktopScreen.isChecked():
|
elif self.desktopScreen.isChecked():
|
||||||
return HideMode.Screen
|
return HideMode.Screen
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
@ -660,7 +660,7 @@ class ThemeManager(QtGui.QWidget):
|
|||||||
|
|
||||||
def generateImage(self, themeData, forcePage=False):
|
def generateImage(self, themeData, forcePage=False):
|
||||||
"""
|
"""
|
||||||
Call the RenderManager to build a Sample Image
|
Call the renderer to build a Sample Image
|
||||||
|
|
||||||
``themeData``
|
``themeData``
|
||||||
The theme to generated a preview for.
|
The theme to generated a preview for.
|
||||||
@ -669,7 +669,7 @@ class ThemeManager(QtGui.QWidget):
|
|||||||
Flag to tell message lines per page need to be generated.
|
Flag to tell message lines per page need to be generated.
|
||||||
"""
|
"""
|
||||||
log.debug(u'generateImage \n%s ', themeData)
|
log.debug(u'generateImage \n%s ', themeData)
|
||||||
return self.mainwindow.renderManager.generate_preview(
|
return self.mainwindow.renderer.generate_preview(
|
||||||
themeData, forcePage)
|
themeData, forcePage)
|
||||||
|
|
||||||
def getPreviewImage(self, theme):
|
def getPreviewImage(self, theme):
|
||||||
|
@ -149,7 +149,7 @@ class ThemesTab(SettingsTab):
|
|||||||
settings.setValue(u'global theme',
|
settings.setValue(u'global theme',
|
||||||
QtCore.QVariant(self.global_theme))
|
QtCore.QVariant(self.global_theme))
|
||||||
settings.endGroup()
|
settings.endGroup()
|
||||||
self.mainwindow.renderManager.set_global_theme(
|
self.mainwindow.renderer.set_global_theme(
|
||||||
self.global_theme, self.theme_level)
|
self.global_theme, self.theme_level)
|
||||||
Receiver.send_message(u'theme_update_global', self.global_theme)
|
Receiver.send_message(u'theme_update_global', self.global_theme)
|
||||||
|
|
||||||
@ -167,7 +167,7 @@ class ThemesTab(SettingsTab):
|
|||||||
|
|
||||||
def onDefaultComboBoxChanged(self, value):
|
def onDefaultComboBoxChanged(self, value):
|
||||||
self.global_theme = unicode(self.DefaultComboBox.currentText())
|
self.global_theme = unicode(self.DefaultComboBox.currentText())
|
||||||
self.mainwindow.renderManager.set_global_theme(
|
self.mainwindow.renderer.set_global_theme(
|
||||||
self.global_theme, self.theme_level)
|
self.global_theme, self.theme_level)
|
||||||
self.__previewGlobalTheme()
|
self.__previewGlobalTheme()
|
||||||
|
|
||||||
@ -188,7 +188,7 @@ class ThemesTab(SettingsTab):
|
|||||||
for theme in theme_list:
|
for theme in theme_list:
|
||||||
self.DefaultComboBox.addItem(theme)
|
self.DefaultComboBox.addItem(theme)
|
||||||
find_and_set_in_combo_box(self.DefaultComboBox, self.global_theme)
|
find_and_set_in_combo_box(self.DefaultComboBox, self.global_theme)
|
||||||
self.mainwindow.renderManager.set_global_theme(
|
self.mainwindow.renderer.set_global_theme(
|
||||||
self.global_theme, self.theme_level)
|
self.global_theme, self.theme_level)
|
||||||
if self.global_theme is not u'':
|
if self.global_theme is not u'':
|
||||||
self.__previewGlobalTheme()
|
self.__previewGlobalTheme()
|
||||||
@ -203,4 +203,4 @@ class ThemesTab(SettingsTab):
|
|||||||
if not preview.isNull():
|
if not preview.isNull():
|
||||||
preview = preview.scaled(300, 255, QtCore.Qt.KeepAspectRatio,
|
preview = preview.scaled(300, 255, QtCore.Qt.KeepAspectRatio,
|
||||||
QtCore.Qt.SmoothTransformation)
|
QtCore.Qt.SmoothTransformation)
|
||||||
self.DefaultListView.setPixmap(preview)
|
self.DefaultListView.setPixmap(preview)
|
||||||
|
@ -101,6 +101,20 @@ class VersionThread(QtCore.QThread):
|
|||||||
Receiver.send_message(u'openlp_version_check', u'%s' % version)
|
Receiver.send_message(u'openlp_version_check', u'%s' % version)
|
||||||
|
|
||||||
|
|
||||||
|
class DelayStartThread(QtCore.QThread):
|
||||||
|
"""
|
||||||
|
A special Qt thread class to build things after OpenLP has started
|
||||||
|
"""
|
||||||
|
def __init__(self, parent):
|
||||||
|
QtCore.QThread.__init__(self, parent)
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
"""
|
||||||
|
Run the thread.
|
||||||
|
"""
|
||||||
|
Receiver.send_message(u'openlp_phonon_creation')
|
||||||
|
|
||||||
|
|
||||||
class AppLocation(object):
|
class AppLocation(object):
|
||||||
"""
|
"""
|
||||||
The :class:`AppLocation` class is a static class which retrieves a
|
The :class:`AppLocation` class is a static class which retrieves a
|
||||||
|
@ -723,6 +723,7 @@ class BibleMediaItem(MediaManagerItem):
|
|||||||
service_item.add_capability(ItemCapabilities.NoLineBreaks)
|
service_item.add_capability(ItemCapabilities.NoLineBreaks)
|
||||||
service_item.add_capability(ItemCapabilities.AllowsPreview)
|
service_item.add_capability(ItemCapabilities.AllowsPreview)
|
||||||
service_item.add_capability(ItemCapabilities.AllowsLoop)
|
service_item.add_capability(ItemCapabilities.AllowsLoop)
|
||||||
|
service_item.add_capability(ItemCapabilities.AllowsWordSplit)
|
||||||
# Service Item: Title
|
# Service Item: Title
|
||||||
service_item.title = u', '.join(raw_title)
|
service_item.title = u', '.join(raw_title)
|
||||||
# Service Item: Theme
|
# Service Item: Theme
|
||||||
@ -849,4 +850,4 @@ class BibleMediaItem(MediaManagerItem):
|
|||||||
self.settings.layout_style)
|
self.settings.layout_style)
|
||||||
QtCore.QSettings().setValue(
|
QtCore.QSettings().setValue(
|
||||||
self.settingsSection + u'/verse layout style',
|
self.settingsSection + u'/verse layout style',
|
||||||
QtCore.QVariant(self.settings.layout_style))
|
QtCore.QVariant(self.settings.layout_style))
|
||||||
|
@ -37,6 +37,9 @@ from openlp.plugins.bibles.lib.db import BibleDB
|
|||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
def replacement(match):
|
||||||
|
return match.group(2).upper()
|
||||||
|
|
||||||
class OSISBible(BibleDB):
|
class OSISBible(BibleDB):
|
||||||
"""
|
"""
|
||||||
`OSIS <http://www.bibletechnologies.net/>`_ Bible format importer class.
|
`OSIS <http://www.bibletechnologies.net/>`_ Bible format importer class.
|
||||||
@ -60,6 +63,7 @@ class OSISBible(BibleDB):
|
|||||||
self.lg_regex = re.compile(r'<lg(.*?)>')
|
self.lg_regex = re.compile(r'<lg(.*?)>')
|
||||||
self.l_regex = re.compile(r'<l (.*?)>')
|
self.l_regex = re.compile(r'<l (.*?)>')
|
||||||
self.w_regex = re.compile(r'<w (.*?)>')
|
self.w_regex = re.compile(r'<w (.*?)>')
|
||||||
|
self.q_regex = re.compile(r'<q(.*?)>')
|
||||||
self.q1_regex = re.compile(r'<q(.*?)level="1"(.*?)>')
|
self.q1_regex = re.compile(r'<q(.*?)level="1"(.*?)>')
|
||||||
self.q2_regex = re.compile(r'<q(.*?)level="2"(.*?)>')
|
self.q2_regex = re.compile(r'<q(.*?)level="2"(.*?)>')
|
||||||
self.trans_regex = re.compile(r'<transChange(.*?)>(.*?)</transChange>')
|
self.trans_regex = re.compile(r'<transChange(.*?)>(.*?)</transChange>')
|
||||||
@ -106,6 +110,7 @@ class OSISBible(BibleDB):
|
|||||||
detect_file.close()
|
detect_file.close()
|
||||||
try:
|
try:
|
||||||
osis = codecs.open(self.filename, u'r', details['encoding'])
|
osis = codecs.open(self.filename, u'r', details['encoding'])
|
||||||
|
repl = replacement
|
||||||
for file_record in osis:
|
for file_record in osis:
|
||||||
if self.stop_import_flag:
|
if self.stop_import_flag:
|
||||||
break
|
break
|
||||||
@ -148,12 +153,13 @@ class OSISBible(BibleDB):
|
|||||||
verse_text = self.rf_regex.sub(u'', verse_text)
|
verse_text = self.rf_regex.sub(u'', verse_text)
|
||||||
verse_text = self.lb_regex.sub(u' ', verse_text)
|
verse_text = self.lb_regex.sub(u' ', verse_text)
|
||||||
verse_text = self.lg_regex.sub(u'', verse_text)
|
verse_text = self.lg_regex.sub(u'', verse_text)
|
||||||
verse_text = self.l_regex.sub(u'', verse_text)
|
verse_text = self.l_regex.sub(u' ', verse_text)
|
||||||
verse_text = self.w_regex.sub(u'', verse_text)
|
verse_text = self.w_regex.sub(u'', verse_text)
|
||||||
verse_text = self.q1_regex.sub(u'"', verse_text)
|
verse_text = self.q1_regex.sub(u'"', verse_text)
|
||||||
verse_text = self.q2_regex.sub(u'\'', verse_text)
|
verse_text = self.q2_regex.sub(u'\'', verse_text)
|
||||||
|
verse_text = self.q_regex.sub(u'', verse_text)
|
||||||
|
verse_text = self.divine_name_regex.sub(repl, verse_text)
|
||||||
verse_text = self.trans_regex.sub(u'', verse_text)
|
verse_text = self.trans_regex.sub(u'', verse_text)
|
||||||
verse_text = self.divine_name_regex.sub(u'', verse_text)
|
|
||||||
verse_text = verse_text.replace(u'</lb>', u'')\
|
verse_text = verse_text.replace(u'</lb>', u'')\
|
||||||
.replace(u'</l>', u'').replace(u'<lg>', u'')\
|
.replace(u'</l>', u'').replace(u'<lg>', u'')\
|
||||||
.replace(u'</lg>', u'').replace(u'</q>', u'')\
|
.replace(u'</lg>', u'').replace(u'</q>', u'')\
|
||||||
|
@ -169,7 +169,7 @@ class EditCustomForm(QtGui.QDialog, Ui_CustomEditDialog):
|
|||||||
item = self.slideListView.item(row)
|
item = self.slideListView.item(row)
|
||||||
slide_list += item.text()
|
slide_list += item.text()
|
||||||
if row != self.slideListView.count() - 1:
|
if row != self.slideListView.count() - 1:
|
||||||
slide_list += u'\n[---]\n'
|
slide_list += u'\n[===]\n'
|
||||||
self.editSlideForm.setText(slide_list)
|
self.editSlideForm.setText(slide_list)
|
||||||
if self.editSlideForm.exec_():
|
if self.editSlideForm.exec_():
|
||||||
self.updateSlideList(self.editSlideForm.getText(), True)
|
self.updateSlideList(self.editSlideForm.getText(), True)
|
||||||
|
@ -63,7 +63,7 @@ class EditCustomSlideForm(QtGui.QDialog, Ui_CustomSlideEditDialog):
|
|||||||
"""
|
"""
|
||||||
Returns a list with all slides.
|
Returns a list with all slides.
|
||||||
"""
|
"""
|
||||||
return self.slideTextEdit.toPlainText().split(u'\n[---]\n')
|
return self.slideTextEdit.toPlainText().split(u'\n[===]\n')
|
||||||
|
|
||||||
def onSplitButtonPressed(self):
|
def onSplitButtonPressed(self):
|
||||||
"""
|
"""
|
||||||
@ -71,5 +71,5 @@ class EditCustomSlideForm(QtGui.QDialog, Ui_CustomSlideEditDialog):
|
|||||||
"""
|
"""
|
||||||
if self.slideTextEdit.textCursor().columnNumber() != 0:
|
if self.slideTextEdit.textCursor().columnNumber() != 0:
|
||||||
self.slideTextEdit.insertPlainText(u'\n')
|
self.slideTextEdit.insertPlainText(u'\n')
|
||||||
self.slideTextEdit.insertPlainText(u'[---]\n')
|
self.slideTextEdit.insertPlainText(u'[===]\n')
|
||||||
self.slideTextEdit.setFocus()
|
self.slideTextEdit.setFocus()
|
||||||
|
@ -140,6 +140,7 @@ class CustomMediaItem(MediaManagerItem):
|
|||||||
service_item.add_capability(ItemCapabilities.AllowsEdit)
|
service_item.add_capability(ItemCapabilities.AllowsEdit)
|
||||||
service_item.add_capability(ItemCapabilities.AllowsPreview)
|
service_item.add_capability(ItemCapabilities.AllowsPreview)
|
||||||
service_item.add_capability(ItemCapabilities.AllowsLoop)
|
service_item.add_capability(ItemCapabilities.AllowsLoop)
|
||||||
|
service_item.add_capability(ItemCapabilities.AllowsVirtualSplit)
|
||||||
customSlide = self.parent.manager.get_object(CustomSlide, item_id)
|
customSlide = self.parent.manager.get_object(CustomSlide, item_id)
|
||||||
title = customSlide.title
|
title = customSlide.title
|
||||||
credit = customSlide.credits
|
credit = customSlide.credits
|
||||||
|
@ -77,7 +77,7 @@ class ImageMediaItem(MediaManagerItem):
|
|||||||
u'thumbnails')
|
u'thumbnails')
|
||||||
check_directory_exists(self.servicePath)
|
check_directory_exists(self.servicePath)
|
||||||
self.loadList(SettingsManager.load_list(
|
self.loadList(SettingsManager.load_list(
|
||||||
self.settingsSection, self.settingsSection))
|
self.settingsSection, self.settingsSection), True)
|
||||||
|
|
||||||
def addListViewToToolBar(self):
|
def addListViewToToolBar(self):
|
||||||
MediaManagerItem.addListViewToToolBar(self)
|
MediaManagerItem.addListViewToToolBar(self)
|
||||||
@ -107,8 +107,13 @@ class ImageMediaItem(MediaManagerItem):
|
|||||||
SettingsManager.set_list(self.settingsSection,
|
SettingsManager.set_list(self.settingsSection,
|
||||||
self.settingsSection, self.getFileList())
|
self.settingsSection, self.getFileList())
|
||||||
|
|
||||||
def loadList(self, list):
|
def loadList(self, list, initialLoad=False):
|
||||||
|
Receiver.send_message(u'cursor_busy')
|
||||||
|
if not initialLoad:
|
||||||
|
self.parent.formparent.displayProgressBar(len(list))
|
||||||
for imageFile in list:
|
for imageFile in list:
|
||||||
|
if not initialLoad:
|
||||||
|
self.parent.formparent.incrementProgressBar()
|
||||||
filename = os.path.split(unicode(imageFile))[1]
|
filename = os.path.split(unicode(imageFile))[1]
|
||||||
thumb = os.path.join(self.servicePath, filename)
|
thumb = os.path.join(self.servicePath, filename)
|
||||||
if os.path.exists(thumb):
|
if os.path.exists(thumb):
|
||||||
@ -122,6 +127,9 @@ class ImageMediaItem(MediaManagerItem):
|
|||||||
item_name.setIcon(icon)
|
item_name.setIcon(icon)
|
||||||
item_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(imageFile))
|
item_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(imageFile))
|
||||||
self.listView.addItem(item_name)
|
self.listView.addItem(item_name)
|
||||||
|
Receiver.send_message(u'cursor_normal')
|
||||||
|
if not initialLoad:
|
||||||
|
self.parent.formparent.finishedProgressBar()
|
||||||
|
|
||||||
def generateSlideData(self, service_item, item=None, xmlVersion=False):
|
def generateSlideData(self, service_item, item=None, xmlVersion=False):
|
||||||
items = self.listView.selectedIndexes()
|
items = self.listView.selectedIndexes()
|
||||||
@ -201,4 +209,4 @@ class ImageMediaItem(MediaManagerItem):
|
|||||||
critical_error_message_box(UiStrings().LiveBGError,
|
critical_error_message_box(UiStrings().LiveBGError,
|
||||||
unicode(translate('ImagePlugin.MediaItem',
|
unicode(translate('ImagePlugin.MediaItem',
|
||||||
'There was a problem replacing your background, '
|
'There was a problem replacing your background, '
|
||||||
'the image file "%s" no longer exists.')) % filename)
|
'the image file "%s" no longer exists.')) % filename)
|
||||||
|
@ -50,10 +50,13 @@ class MediaMediaItem(MediaManagerItem):
|
|||||||
u':/media/media_video.png').toImage()
|
u':/media/media_video.png').toImage()
|
||||||
MediaManagerItem.__init__(self, parent, self, icon)
|
MediaManagerItem.__init__(self, parent, self, icon)
|
||||||
self.singleServiceItem = False
|
self.singleServiceItem = False
|
||||||
self.mediaObject = Phonon.MediaObject(self)
|
self.mediaObject = None
|
||||||
QtCore.QObject.connect(Receiver.get_receiver(),
|
QtCore.QObject.connect(Receiver.get_receiver(),
|
||||||
QtCore.SIGNAL(u'video_background_replaced'),
|
QtCore.SIGNAL(u'video_background_replaced'),
|
||||||
self.videobackgroundReplaced)
|
self.videobackgroundReplaced)
|
||||||
|
QtCore.QObject.connect(Receiver.get_receiver(),
|
||||||
|
QtCore.SIGNAL(u'openlp_phonon_creation'),
|
||||||
|
self.createPhonon)
|
||||||
|
|
||||||
def retranslateUi(self):
|
def retranslateUi(self):
|
||||||
self.onNewPrompt = translate('MediaPlugin.MediaItem', 'Select Media')
|
self.onNewPrompt = translate('MediaPlugin.MediaItem', 'Select Media')
|
||||||
@ -209,4 +212,9 @@ class MediaMediaItem(MediaManagerItem):
|
|||||||
img = QtGui.QPixmap(u':/media/media_video.png').toImage()
|
img = QtGui.QPixmap(u':/media/media_video.png').toImage()
|
||||||
item_name.setIcon(build_icon(img))
|
item_name.setIcon(build_icon(img))
|
||||||
item_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(file))
|
item_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(file))
|
||||||
self.listView.addItem(item_name)
|
self.listView.addItem(item_name)
|
||||||
|
|
||||||
|
def createPhonon(self):
|
||||||
|
log.debug(u'CreatePhonon')
|
||||||
|
if not self.mediaObject:
|
||||||
|
self.mediaObject = Phonon.MediaObject(self)
|
||||||
|
@ -219,7 +219,6 @@ class ImpressDocument(PresentationDocument):
|
|||||||
The file name of the presentatios to the run.
|
The file name of the presentatios to the run.
|
||||||
"""
|
"""
|
||||||
log.debug(u'Load Presentation OpenOffice')
|
log.debug(u'Load Presentation OpenOffice')
|
||||||
#print "s.dsk1 ", self.desktop
|
|
||||||
if os.name == u'nt':
|
if os.name == u'nt':
|
||||||
desktop = self.controller.get_com_desktop()
|
desktop = self.controller.get_com_desktop()
|
||||||
if desktop is None:
|
if desktop is None:
|
||||||
@ -234,7 +233,10 @@ class ImpressDocument(PresentationDocument):
|
|||||||
return False
|
return False
|
||||||
self.desktop = desktop
|
self.desktop = desktop
|
||||||
properties = []
|
properties = []
|
||||||
properties.append(self.create_property(u'Minimized', True))
|
if os.name != u'nt':
|
||||||
|
# Recent versions of Impress on Windows won't start the presentation
|
||||||
|
# if it starts as minimized. It seems OK on Linux though.
|
||||||
|
properties.append(self.create_property(u'Minimized', True))
|
||||||
properties = tuple(properties)
|
properties = tuple(properties)
|
||||||
try:
|
try:
|
||||||
self.document = desktop.loadComponentFromURL(url, u'_blank',
|
self.document = desktop.loadComponentFromURL(url, u'_blank',
|
||||||
@ -242,9 +244,15 @@ class ImpressDocument(PresentationDocument):
|
|||||||
except:
|
except:
|
||||||
log.exception(u'Failed to load presentation %s' % url)
|
log.exception(u'Failed to load presentation %s' % url)
|
||||||
return False
|
return False
|
||||||
|
if os.name == u'nt':
|
||||||
|
# As we can't start minimized the Impress window gets in the way.
|
||||||
|
# Either window.setPosSize(0, 0, 200, 400, 12) or .setVisible(False)
|
||||||
|
window = self.document.getCurrentController().getFrame() \
|
||||||
|
.getContainerWindow()
|
||||||
|
window.setVisible(False)
|
||||||
self.presentation = self.document.getPresentation()
|
self.presentation = self.document.getPresentation()
|
||||||
self.presentation.Display = \
|
self.presentation.Display = \
|
||||||
self.controller.plugin.renderManager.screens.current_display + 1
|
self.controller.plugin.renderer.screens.current_display + 1
|
||||||
self.control = None
|
self.control = None
|
||||||
self.create_thumbnails()
|
self.create_thumbnails()
|
||||||
return True
|
return True
|
||||||
@ -387,14 +395,14 @@ class ImpressDocument(PresentationDocument):
|
|||||||
log.debug(u'start presentation OpenOffice')
|
log.debug(u'start presentation OpenOffice')
|
||||||
if self.control is None or not self.control.isRunning():
|
if self.control is None or not self.control.isRunning():
|
||||||
self.presentation.start()
|
self.presentation.start()
|
||||||
# start() returns before the getCurrentComponent is ready.
|
self.control = self.presentation.getController()
|
||||||
# Try for 5 seconds
|
# start() returns before the Component is ready.
|
||||||
|
# Try for 15 seconds
|
||||||
i = 1
|
i = 1
|
||||||
while self.desktop.getCurrentComponent() is None and i < 50:
|
while not self.control and i < 150:
|
||||||
time.sleep(0.1)
|
time.sleep(0.1)
|
||||||
i = i + 1
|
i = i + 1
|
||||||
self.control = \
|
self.control = self.presentation.getController()
|
||||||
self.desktop.getCurrentComponent().Presentation.getController()
|
|
||||||
else:
|
else:
|
||||||
self.control.activate()
|
self.control.activate()
|
||||||
self.goto_slide(1)
|
self.goto_slide(1)
|
||||||
|
@ -158,7 +158,12 @@ class PresentationMediaItem(MediaManagerItem):
|
|||||||
titles = []
|
titles = []
|
||||||
for file in currlist:
|
for file in currlist:
|
||||||
titles.append(os.path.split(file)[1])
|
titles.append(os.path.split(file)[1])
|
||||||
|
Receiver.send_message(u'cursor_busy')
|
||||||
|
if not initialLoad:
|
||||||
|
self.parent.formparent.displayProgressBar(len(list))
|
||||||
for file in list:
|
for file in list:
|
||||||
|
if not initialLoad:
|
||||||
|
self.parent.formparent.incrementProgressBar()
|
||||||
if currlist.count(file) > 0:
|
if currlist.count(file) > 0:
|
||||||
continue
|
continue
|
||||||
filename = os.path.split(unicode(file))[1]
|
filename = os.path.split(unicode(file))[1]
|
||||||
@ -198,6 +203,9 @@ class PresentationMediaItem(MediaManagerItem):
|
|||||||
item_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(file))
|
item_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(file))
|
||||||
item_name.setIcon(icon)
|
item_name.setIcon(icon)
|
||||||
self.listView.addItem(item_name)
|
self.listView.addItem(item_name)
|
||||||
|
Receiver.send_message(u'cursor_normal')
|
||||||
|
if not initialLoad:
|
||||||
|
self.parent.formparent.finishedProgressBar()
|
||||||
|
|
||||||
def onDeleteClick(self):
|
def onDeleteClick(self):
|
||||||
"""
|
"""
|
||||||
@ -285,7 +293,7 @@ class PresentationMediaItem(MediaManagerItem):
|
|||||||
"supports" the extension. If none found, then look for a controller
|
"supports" the extension. If none found, then look for a controller
|
||||||
which "also supports" it instead.
|
which "also supports" it instead.
|
||||||
"""
|
"""
|
||||||
filetype = filename.split(u'.')[1]
|
filetype = os.path.splitext(filename)[1]
|
||||||
if not filetype:
|
if not filetype:
|
||||||
return None
|
return None
|
||||||
for controller in self.controllers:
|
for controller in self.controllers:
|
||||||
@ -296,4 +304,4 @@ class PresentationMediaItem(MediaManagerItem):
|
|||||||
if self.controllers[controller].enabled():
|
if self.controllers[controller].enabled():
|
||||||
if filetype in self.controllers[controller].alsosupports:
|
if filetype in self.controllers[controller].alsosupports:
|
||||||
return controller
|
return controller
|
||||||
return None
|
return None
|
||||||
|
@ -251,14 +251,15 @@ class PowerpointDocument(PresentationDocument):
|
|||||||
win32ui.GetForegroundWindow().GetDC().GetDeviceCaps(88)
|
win32ui.GetForegroundWindow().GetDC().GetDeviceCaps(88)
|
||||||
except win32ui.error:
|
except win32ui.error:
|
||||||
dpi = 96
|
dpi = 96
|
||||||
rendermanager = self.controller.plugin.renderManager
|
renderer = self.controller.plugin.renderer
|
||||||
rect = rendermanager.screens.current[u'size']
|
rect = renderer.screens.current[u'size']
|
||||||
ppt_window = self.presentation.SlideShowSettings.Run()
|
ppt_window = self.presentation.SlideShowSettings.Run()
|
||||||
ppt_window.Top = rect.y() * 72 / dpi
|
ppt_window.Top = rect.y() * 72 / dpi
|
||||||
ppt_window.Height = rect.height() * 72 / dpi
|
ppt_window.Height = rect.height() * 72 / dpi
|
||||||
ppt_window.Left = rect.x() * 72 / dpi
|
ppt_window.Left = rect.x() * 72 / dpi
|
||||||
ppt_window.Width = rect.width() * 72 / dpi
|
ppt_window.Width = rect.width() * 72 / dpi
|
||||||
|
|
||||||
|
|
||||||
def get_slide_number(self):
|
def get_slide_number(self):
|
||||||
"""
|
"""
|
||||||
Returns the current slide number.
|
Returns the current slide number.
|
||||||
|
@ -121,8 +121,8 @@ class PptviewDocument(PresentationDocument):
|
|||||||
The file name of the presentations to run.
|
The file name of the presentations to run.
|
||||||
"""
|
"""
|
||||||
log.debug(u'LoadPresentation')
|
log.debug(u'LoadPresentation')
|
||||||
rendermanager = self.controller.plugin.renderManager
|
renderer = self.controller.plugin.renderer
|
||||||
rect = rendermanager.screens.current[u'size']
|
rect = renderer.screens.current[u'size']
|
||||||
rect = RECT(rect.x(), rect.y(), rect.right(), rect.bottom())
|
rect = RECT(rect.x(), rect.y(), rect.right(), rect.bottom())
|
||||||
filepath = str(self.filepath.replace(u'/', u'\\'))
|
filepath = str(self.filepath.replace(u'/', u'\\'))
|
||||||
if not os.path.isdir(self.get_temp_folder()):
|
if not os.path.isdir(self.get_temp_folder()):
|
||||||
@ -244,4 +244,4 @@ class PptviewDocument(PresentationDocument):
|
|||||||
"""
|
"""
|
||||||
Triggers the previous slide on the running presentation
|
Triggers the previous slide on the running presentation
|
||||||
"""
|
"""
|
||||||
self.controller.process.PrevStep(self.pptid)
|
self.controller.process.PrevStep(self.pptid)
|
@ -89,7 +89,7 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
|
|||||||
self.onVerseListViewPressed)
|
self.onVerseListViewPressed)
|
||||||
QtCore.QObject.connect(self.themeAddButton,
|
QtCore.QObject.connect(self.themeAddButton,
|
||||||
QtCore.SIGNAL(u'clicked()'),
|
QtCore.SIGNAL(u'clicked()'),
|
||||||
self.parent.parent.renderManager.theme_manager.onAddTheme)
|
self.parent.parent.renderer.theme_manager.onAddTheme)
|
||||||
QtCore.QObject.connect(self.maintenanceButton,
|
QtCore.QObject.connect(self.maintenanceButton,
|
||||||
QtCore.SIGNAL(u'clicked()'), self.onMaintenanceButtonClicked)
|
QtCore.SIGNAL(u'clicked()'), self.onMaintenanceButtonClicked)
|
||||||
QtCore.QObject.connect(Receiver.get_receiver(),
|
QtCore.QObject.connect(Receiver.get_receiver(),
|
||||||
@ -576,11 +576,13 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
|
|||||||
if verse_index is not None:
|
if verse_index is not None:
|
||||||
order.append(VerseType.Tags[verse_index] + u'1')
|
order.append(VerseType.Tags[verse_index] + u'1')
|
||||||
else:
|
else:
|
||||||
order.append(u'') # it matches no verses anyway
|
# it matches no verses anyway
|
||||||
|
order.append(u'')
|
||||||
else:
|
else:
|
||||||
verse_index = VerseType.from_translated_tag(item[0])
|
verse_index = VerseType.from_translated_tag(item[0])
|
||||||
if verse_index is None:
|
if verse_index is None:
|
||||||
order.append(u'') # same as above
|
# it matches no verses anyway
|
||||||
|
order.append(u'')
|
||||||
else:
|
else:
|
||||||
verse_tag = VerseType.Tags[verse_index]
|
verse_tag = VerseType.Tags[verse_index]
|
||||||
verse_num = item[1:].lower()
|
verse_num = item[1:].lower()
|
||||||
@ -779,4 +781,4 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
|
|||||||
self.song.verse_order)
|
self.song.verse_order)
|
||||||
except:
|
except:
|
||||||
log.exception(u'Problem processing song Lyrics \n%s',
|
log.exception(u'Problem processing song Lyrics \n%s',
|
||||||
sxml.dump_xml())
|
sxml.dump_xml())
|
||||||
|
@ -257,7 +257,7 @@ def clean_song(manager, song):
|
|||||||
``song``
|
``song``
|
||||||
The song object.
|
The song object.
|
||||||
"""
|
"""
|
||||||
song.title = song.title.strip() if song.title else u''
|
song.title = song.title.rstrip() if song.title else u''
|
||||||
if song.alternate_title is None:
|
if song.alternate_title is None:
|
||||||
song.alternate_title = u''
|
song.alternate_title = u''
|
||||||
song.alternate_title = song.alternate_title.strip()
|
song.alternate_title = song.alternate_title.strip()
|
||||||
@ -293,7 +293,10 @@ def clean_song(manager, song):
|
|||||||
song.lyrics = unicode(sxml.extract_xml(), u'utf-8')
|
song.lyrics = unicode(sxml.extract_xml(), u'utf-8')
|
||||||
# Rebuild the verse order, to convert translated verse tags, which might
|
# Rebuild the verse order, to convert translated verse tags, which might
|
||||||
# have been added prior to 1.9.5.
|
# have been added prior to 1.9.5.
|
||||||
order = song.verse_order.strip().split()
|
if song.verse_order:
|
||||||
|
order = song.verse_order.strip().split()
|
||||||
|
else:
|
||||||
|
order = []
|
||||||
new_order = []
|
new_order = []
|
||||||
for verse_def in order:
|
for verse_def in order:
|
||||||
verse_type = VerseType.Tags[VerseType.from_loose_input(verse_def[0])]
|
verse_type = VerseType.Tags[VerseType.from_loose_input(verse_def[0])]
|
||||||
|
@ -347,6 +347,7 @@ class SongMediaItem(MediaManagerItem):
|
|||||||
service_item.add_capability(ItemCapabilities.AllowsLoop)
|
service_item.add_capability(ItemCapabilities.AllowsLoop)
|
||||||
service_item.add_capability(ItemCapabilities.OnLoadUpdate)
|
service_item.add_capability(ItemCapabilities.OnLoadUpdate)
|
||||||
service_item.add_capability(ItemCapabilities.AddIfNewItem)
|
service_item.add_capability(ItemCapabilities.AddIfNewItem)
|
||||||
|
service_item.add_capability(ItemCapabilities.AllowsVirtualSplit)
|
||||||
song = self.parent.manager.get_object(Song, item_id)
|
song = self.parent.manager.get_object(Song, item_id)
|
||||||
service_item.theme = song.theme_name
|
service_item.theme = song.theme_name
|
||||||
service_item.edit_id = item_id
|
service_item.edit_id = item_id
|
||||||
@ -472,4 +473,4 @@ class SongMediaItem(MediaManagerItem):
|
|||||||
Locale aware collation of song titles
|
Locale aware collation of song titles
|
||||||
"""
|
"""
|
||||||
return locale.strcoll(unicode(song_1.title.lower()),
|
return locale.strcoll(unicode(song_1.title.lower()),
|
||||||
unicode(song_2.title.lower()))
|
unicode(song_2.title.lower()))
|
||||||
|
@ -32,7 +32,7 @@ The basic XML for storing the lyrics in the song database looks like this::
|
|||||||
<song version="1.0">
|
<song version="1.0">
|
||||||
<lyrics>
|
<lyrics>
|
||||||
<verse type="c" label="1" lang="en">
|
<verse type="c" label="1" lang="en">
|
||||||
<![CDATA[ ... ]]>
|
<![CDATA[Chorus virtual slide 1[---]Chorus virtual slide 2]]>
|
||||||
</verse>
|
</verse>
|
||||||
</lyrics>
|
</lyrics>
|
||||||
</song>
|
</song>
|
||||||
@ -129,18 +129,31 @@ class SongXML(object):
|
|||||||
|
|
||||||
The returned list has the following format::
|
The returned list has the following format::
|
||||||
|
|
||||||
[[{'lang': 'en', 'type': 'v', 'label': '1'}, u"English verse"],
|
[[{'type': 'v', 'label': '1'},
|
||||||
|
u"virtual slide 1[---]virtual slide 2"],
|
||||||
[{'lang': 'en', 'type': 'c', 'label': '1'}, u"English chorus"]]
|
[{'lang': 'en', 'type': 'c', 'label': '1'}, u"English chorus"]]
|
||||||
"""
|
"""
|
||||||
self.song_xml = None
|
self.song_xml = None
|
||||||
if xml[:5] == u'<?xml':
|
verse_list = []
|
||||||
|
if not xml.startswith(u'<?xml') and not xml.startswith(u'<song'):
|
||||||
|
# This is an old style song, without XML. Let's handle it correctly
|
||||||
|
# by iterating through the verses, and then recreating the internal
|
||||||
|
# xml object as well.
|
||||||
|
self.song_xml = objectify.fromstring(u'<song version="1.0" />')
|
||||||
|
self.lyrics = etree.SubElement(self.song_xml, u'lyrics')
|
||||||
|
verses = xml.split(u'\n\n')
|
||||||
|
for count, verse in enumerate(verses):
|
||||||
|
verse_list.append([{u'type': u'v', u'label': unicode(count)},
|
||||||
|
unicode(verse)])
|
||||||
|
self.add_verse_to_lyrics(u'v', unicode(count), verse)
|
||||||
|
return verse_list
|
||||||
|
elif xml.startswith(u'<?xml'):
|
||||||
xml = xml[38:]
|
xml = xml[38:]
|
||||||
try:
|
try:
|
||||||
self.song_xml = objectify.fromstring(xml)
|
self.song_xml = objectify.fromstring(xml)
|
||||||
except etree.XMLSyntaxError:
|
except etree.XMLSyntaxError:
|
||||||
log.exception(u'Invalid xml %s', xml)
|
log.exception(u'Invalid xml %s', xml)
|
||||||
xml_iter = self.song_xml.getiterator()
|
xml_iter = self.song_xml.getiterator()
|
||||||
verse_list = []
|
|
||||||
for element in xml_iter:
|
for element in xml_iter:
|
||||||
if element.tag == u'verse':
|
if element.tag == u'verse':
|
||||||
if element.text is None:
|
if element.text is None:
|
||||||
@ -226,7 +239,6 @@ class OpenLyrics(object):
|
|||||||
Convert the song to OpenLyrics Format.
|
Convert the song to OpenLyrics Format.
|
||||||
"""
|
"""
|
||||||
sxml = SongXML()
|
sxml = SongXML()
|
||||||
verse_list = sxml.get_verses(song.lyrics)
|
|
||||||
song_xml = objectify.fromstring(u'<song/>')
|
song_xml = objectify.fromstring(u'<song/>')
|
||||||
# Append the necessary meta data to the song.
|
# Append the necessary meta data to the song.
|
||||||
song_xml.set(u'xmlns', u'http://openlyrics.info/namespace/2009/song')
|
song_xml.set(u'xmlns', u'http://openlyrics.info/namespace/2009/song')
|
||||||
@ -268,17 +280,26 @@ class OpenLyrics(object):
|
|||||||
themes = etree.SubElement(properties, u'themes')
|
themes = etree.SubElement(properties, u'themes')
|
||||||
for topic in song.topics:
|
for topic in song.topics:
|
||||||
self._add_text_to_element(u'theme', themes, topic.name)
|
self._add_text_to_element(u'theme', themes, topic.name)
|
||||||
|
# Process the song's lyrics.
|
||||||
lyrics = etree.SubElement(song_xml, u'lyrics')
|
lyrics = etree.SubElement(song_xml, u'lyrics')
|
||||||
|
verse_list = sxml.get_verses(song.lyrics)
|
||||||
for verse in verse_list:
|
for verse in verse_list:
|
||||||
verse_tag = u'%s%s' % (
|
verse_tag = verse[0][u'type'][0].lower()
|
||||||
verse[0][u'type'][0].lower(), verse[0][u'label'])
|
verse_number = verse[0][u'label']
|
||||||
element = \
|
# Create a list with all "virtual" verses.
|
||||||
self._add_text_to_element(u'verse', lyrics, None, verse_tag)
|
virtual_verses = verse[1].split(u'[---]')
|
||||||
if verse[0].has_key(u'lang'):
|
for index, virtual_verse in enumerate(virtual_verses):
|
||||||
element.set(u'lang', verse[0][u'lang'])
|
verse_def = verse_tag + verse_number
|
||||||
element = self._add_text_to_element(u'lines', element)
|
# We need "v1a" because we have more than one virtual verse.
|
||||||
for line in unicode(verse[1]).split(u'\n'):
|
if len(virtual_verses) > 1:
|
||||||
self._add_text_to_element(u'line', element, line)
|
verse_def += list(u'abcdefghijklmnopqrstuvwxyz')[index]
|
||||||
|
element = \
|
||||||
|
self._add_text_to_element(u'verse', lyrics, None, verse_def)
|
||||||
|
if verse[0].has_key(u'lang'):
|
||||||
|
element.set(u'lang', verse[0][u'lang'])
|
||||||
|
element = self._add_text_to_element(u'lines', element)
|
||||||
|
for line in virtual_verse.strip(u'\n').split(u'\n'):
|
||||||
|
self._add_text_to_element(u'line', element, line)
|
||||||
return self._extract_xml(song_xml)
|
return self._extract_xml(song_xml)
|
||||||
|
|
||||||
def xml_to_song(self, xml):
|
def xml_to_song(self, xml):
|
||||||
@ -446,6 +467,8 @@ class OpenLyrics(object):
|
|||||||
The song object.
|
The song object.
|
||||||
"""
|
"""
|
||||||
sxml = SongXML()
|
sxml = SongXML()
|
||||||
|
verses = {}
|
||||||
|
verse_def_list = []
|
||||||
for verse in lyrics.verse:
|
for verse in lyrics.verse:
|
||||||
text = u''
|
text = u''
|
||||||
for lines in verse.lines:
|
for lines in verse.lines:
|
||||||
@ -465,7 +488,15 @@ class OpenLyrics(object):
|
|||||||
lang = None
|
lang = None
|
||||||
if self._get(verse, u'lang'):
|
if self._get(verse, u'lang'):
|
||||||
lang = self._get(verse, u'lang')
|
lang = self._get(verse, u'lang')
|
||||||
sxml.add_verse_to_lyrics(verse_tag, verse_number, text, lang)
|
if verses.has_key((verse_tag, verse_number, lang)):
|
||||||
|
verses[(verse_tag, verse_number, lang)] += u'\n[---]\n' + text
|
||||||
|
else:
|
||||||
|
verses[(verse_tag, verse_number, lang)] = text
|
||||||
|
verse_def_list.append((verse_tag, verse_number, lang))
|
||||||
|
# We have to use a list to keep the order, as dicts are not sorted.
|
||||||
|
for verse in verse_def_list:
|
||||||
|
sxml.add_verse_to_lyrics(
|
||||||
|
verse[0], verse[1], verses[verse], verse[2])
|
||||||
song.lyrics = unicode(sxml.extract_xml(), u'utf-8')
|
song.lyrics = unicode(sxml.extract_xml(), u'utf-8')
|
||||||
# Process verse order
|
# Process verse order
|
||||||
if hasattr(properties, u'verseOrder'):
|
if hasattr(properties, u'verseOrder'):
|
||||||
|
Loading…
Reference in New Issue
Block a user