add Starttime to phonon api and sync with trunk

This commit is contained in:
rimach crichter@web.de 2011-07-25 23:10:25 +02:00
commit 4cb65187e7
26 changed files with 276 additions and 250 deletions

View File

@ -34,6 +34,7 @@ from openlp.core.lib.theme import BackgroundType, BackgroundGradientType, \
log = logging.getLogger(__name__)
# FIXME: Add html5 doctype. However, do not break theme gradients.
HTMLSRC = u"""
<html>
<head>
@ -56,39 +57,39 @@ body {
height: %spx;
}
#black {
z-index:8;
z-index: 8;
background-color: black;
display: none;
}
#bgimage {
z-index:1;
z-index: 1;
}
#image {
z-index:2;
z-index: 2;
}
%s
#alert {
position: absolute;
left: 0px;
top: 0px;
z-index:10;
z-index: 10;
%s
}
#footer {
position: absolute;
z-index:6;
z-index: 6;
%s
}
/* lyric css */
%s
sup {
font-size:0.6em;
vertical-align:top;
position:relative;
top:-0.3em;
font-size: 0.6em;
vertical-align: top;
position: relative;
top: -0.3em;
}
</style>
<script language="javascript">
<script>
var timer = null;
var transition = %s;
%s
@ -229,10 +230,10 @@ sup {
%s
<div id="footer" class="footer"></div>
<div id="black" class="size"></div>
<div id="alert" style="visibility:hidden;"></div>
<div id="alert" style="visibility:hidden"></div>
</body>
</html>
"""
"""
def build_html(item, screen, alert, islive, background, plugins=None, \
image=None):
@ -373,15 +374,15 @@ def build_lyrics_css(item, webkitvers):
The version of qtwebkit we're using
"""
style = """
style = u"""
.lyricstable {
z-index:5;
z-index: 5;
position: absolute;
display: table;
%s
}
.lyricscell {
display:table-cell;
display: table-cell;
word-wrap: break-word;
%s
}
@ -485,8 +486,8 @@ def build_lyrics_format_css(theme, width, height):
left_margin = 0
lyrics = u'white-space:pre-wrap; word-wrap: break-word; ' \
'text-align: %s; vertical-align: %s; font-family: %s; ' \
'font-size: %spt; color: %s; line-height: %d%%; margin:0;' \
'padding:0; padding-left:%spx; width: %spx; height: %spx; ' % \
'font-size: %spt; color: %s; line-height: %d%%; margin: 0;' \
'padding: 0; padding-left: %spx; width: %spx; height: %spx; ' % \
(align, valign, theme.font_main_name, theme.font_main_size,
theme.font_main_color, 100 + int(theme.font_main_line_adjustment),
left_margin, width, height)
@ -535,7 +536,7 @@ def build_footer_css(item, height):
``item``
Service Item to be processed.
"""
style = """
style = u"""
left: %spx;
bottom: %spx;
width: %spx;
@ -543,7 +544,7 @@ def build_footer_css(item, height):
font-size: %spt;
color: %s;
text-align: left;
white-space:nowrap;
white-space: nowrap;
"""
theme = item.themedata
if not theme or not item.footer:
@ -561,7 +562,7 @@ def build_alert_css(alertTab, width):
``alertTab``
Details from the Alert tab for fonts etc
"""
style = """
style = u"""
width: %spx;
vertical-align: %s;
font-family: %s;

View File

@ -96,7 +96,7 @@ class MediaManagerItem(QtGui.QWidget):
self.plugin = plugin
visible_title = self.plugin.getString(StringContent.VisibleName)
self.title = unicode(visible_title[u'title'])
self.settingsSection = self.plugin.name.lower()
self.settingsSection = self.plugin.name
self.icon = None
if icon:
self.icon = build_icon(icon)
@ -113,7 +113,7 @@ class MediaManagerItem(QtGui.QWidget):
self.retranslateUi()
self.auto_select_id = -1
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'%s_service_load' % self.plugin.name.lower()),
QtCore.SIGNAL(u'%s_service_load' % self.plugin.name),
self.serviceLoad)
def requiredIcons(self):
@ -558,7 +558,7 @@ class MediaManagerItem(QtGui.QWidget):
QtGui.QMessageBox.information(self, UiStrings().NISs,
translate('OpenLP.MediaManagerItem',
'You must select an existing service item to add to.'))
elif self.plugin.name.lower() == serviceItem.name.lower():
elif self.plugin.name == serviceItem.name:
self.generateSlideData(serviceItem)
self.plugin.serviceManager.addServiceItem(serviceItem,
replace=True)

View File

@ -152,7 +152,7 @@ class Plugin(QtCore.QObject):
self.version = version
else:
self.version = get_application_version()[u'version']
self.settingsSection = self.name.lower()
self.settingsSection = self.name
self.icon = None
self.media_item_class = media_item_class
self.settings_tab_class = settings_tab_class

View File

@ -56,20 +56,20 @@ class Renderer(object):
"""
log.info(u'Renderer Loaded')
def __init__(self, image_manager, theme_manager, plugins):
def __init__(self, imageManager, themeManager, plugins):
"""
Initialise the render manager.
``image_manager``
``imageManager``
A ImageManager instance which takes care of e. g. caching and resizing
images.
``theme_manager``
``themeManager``
The ThemeManager instance, used to get the current theme details.
"""
log.debug(u'Initialisation started')
self.theme_manager = theme_manager
self.image_manager = image_manager
self.themeManager = themeManager
self.imageManager = imageManager
self.plugins = plugins
self.screens = ScreenList.get_instance()
self.service_theme = u''
@ -78,7 +78,7 @@ class Renderer(object):
self.theme_data = None
self.bg_frame = None
self.force_page = False
self.display = MainDisplay(None, self.image_manager, False, self,
self.display = MainDisplay(None, self.imageManager, False, self,
self.plugins)
self.display.setup()
@ -90,7 +90,7 @@ class Renderer(object):
self._calculate_default(self.screens.current[u'size'])
if self.display:
self.display.close()
self.display = MainDisplay(None, self.image_manager, False, self,
self.display = MainDisplay(None, self.imageManager, False, self,
self.plugins)
self.display.setup()
self.bg_frame = None
@ -104,14 +104,14 @@ class Renderer(object):
The global-level theme to be set.
``theme_level``
Defaults to *``ThemeLevel.Global``*. The theme level, can be
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.themeManager.getThemeData(self.global_theme)
self.theme_data = None
def set_service_theme(self, service_theme):
@ -165,12 +165,12 @@ class Renderer(object):
if override_levels:
self.theme_data = override_theme
else:
self.theme_data = self.theme_manager.getThemeData(theme)
self.theme_data = self.themeManager.getThemeData(theme)
self._calculate_default(self.screens.current[u'size'])
self._build_text_rectangle(self.theme_data)
# if No file do not update cache
if self.theme_data.background_filename:
self.image_manager.add_image(self.theme_data.theme_name,
self.imageManager.add_image(self.theme_data.theme_name,
self.theme_data.background_filename)
return self._rect, self._rect_footer
@ -196,7 +196,7 @@ class Renderer(object):
# make big page for theme edit dialog to get line count
serviceItem.add_from_text(u'', VERSE + VERSE + VERSE)
else:
self.image_manager.del_image(theme_data.theme_name)
self.imageManager.del_image(theme_data.theme_name)
serviceItem.add_from_text(u'', VERSE)
serviceItem.renderer = self
serviceItem.raw_footer = FOOTER
@ -208,43 +208,52 @@ class Renderer(object):
# Reset the real screen size for subsequent render requests
self._calculate_default(self.screens.current[u'size'])
return preview
self.force_page = False
def format_slide(self, text, line_break, item):
def format_slide(self, text, 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.
``item``
The :class:`~openlp.core.lib.serviceitem.ServiceItem` item object.
"""
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
# Add line endings after each line of text used for bibles.
line_end = u'<br>'
if item.is_capable(ItemCapabilities.NoLineBreaks):
line_end = u' '
# Bibles
if item.is_capable(ItemCapabilities.AllowsWordSplit):
pages = self._paginate_slide_words(text, line_end)
else:
# Clean up line endings.
lines = self._lines_split(text)
pages = self._paginate_slide(lines, line_end)
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')
pages.extend(self._paginate_slide(lines, line_end))
new_pages = []
for page in pages:
while page.endswith(u'<br>'):
page = page[:-4]
new_pages.append(page)
return new_pages
def _calculate_default(self, screen):
"""
Calculate the default dimentions of the screen.
``screen``
The QSize of the screen.
The screen to calculate the default of.
"""
log.debug(u'_calculate default %s', screen)
self.width = screen.width()
@ -304,61 +313,44 @@ class Renderer(object):
self.web.resize(self.page_width, self.page_height)
self.web_frame = self.web.page().mainFrame()
# Adjust width and height to account for shadow. outline done in css
self.page_shell = u'<html><head><style>' \
u'*{margin: 0; padding: 0; border: 0;} '\
self.page_shell = u'<!DOCTYPE html><html><head><style>' \
u'*{margin:0; padding:0; border:0;} '\
u'#main {position:absolute; top:0px; %s %s}</style></head><body>' \
u'<div id="main">' % \
(build_lyrics_format_css(self.theme_data, self.page_width,
self.page_height), build_lyrics_outline_css(self.theme_data))
def _paginate_slide(self, lines, line_break, force_page=False):
def _paginate_slide(self, lines, line_end):
"""
Figure out how much text can appear on a slide, using the current
theme settings.
``lines``
The words to be fitted on the slide split into lines.
``line_break``
Add line endings after each line of text (used for bibles).
``force_page``
Flag to tell message lines in page.
The text to be fitted on the slide split into lines.
``line_end``
The text added after each line. Either ``u' '`` or ``u'<br>``.
"""
log.debug(u'_paginate_slide - Start')
line_end = u''
if line_break:
line_end = u'<br>'
formatted = []
html_text = u''
styled_text = u''
line_count = 0
for line in lines:
if line_count != -1:
line_count += 1
styled_line = expand_tags(line) + line_end
styled_text += styled_line
html = self.page_shell + styled_text + HTML_END
self.web.setHtml(html)
# Text too long so go to next page.
if self.web_frame.contentsSize().height() > self.page_height:
if force_page and line_count > 0:
Receiver.send_message(u'theme_line_count', line_count - 1)
line_count = -1
while html_text.endswith(u'<br>'):
html_text = html_text[:-4]
formatted.append(html_text)
html_text = u''
styled_text = styled_line
html_text += line + line_end
while html_text.endswith(u'<br>'):
html_text = html_text[:-4]
formatted.append(html_text)
previous_html = u''
previous_raw = u''
separator = u'<br>'
html_lines = map(expand_tags, lines)
html = self.page_shell + separator.join(html_lines) + HTML_END
self.web.setHtml(html)
# Text too long so go to next page.
if self.web_frame.contentsSize().height() > self.page_height:
html_text, previous_raw = self._binary_chop(formatted,
previous_html, previous_raw, html_lines, lines, separator, u'')
else:
previous_raw = separator.join(lines)
if previous_raw:
formatted.append(previous_raw)
log.debug(u'_paginate_slide - End')
return formatted
def _paginate_slide_words(self, text, line_break):
def _paginate_slide_words(self, text, line_end):
"""
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
@ -367,22 +359,19 @@ class Renderer(object):
``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.
``line_end``
The text added after each line. Either ``u' '`` or ``u'<br>``.
This is needed 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:
line = line.strip()
styled_line = expand_tags(line)
html = self.page_shell + previous_html + styled_line + HTML_END
html_line = expand_tags(line)
html = self.page_shell + previous_html + html_line + HTML_END
self.web.setHtml(html)
# Text too long so go to next page.
if self.web_frame.contentsSize().height() > self.page_height:
@ -393,88 +382,123 @@ class Renderer(object):
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
html = self.page_shell + html_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_html = html_line + line_end
previous_raw = line + line_end
continue
# Figure out how many words of the line will fit on screen by
# using the algorithm known as "binary chop".
# Figure out how many words of the line will fit on screen as
# the line will not fit as a whole.
raw_words = self._words_split(line)
html_words = [expand_tags(word) for word in raw_words]
smallest_index = 0
highest_index = len(html_words) - 1
index = int(highest_index / 2)
while True:
html = self.page_shell + previous_html + \
u''.join(html_words[:index + 1]).strip() + HTML_END
self.web.setHtml(html)
if self.web_frame.contentsSize().height() > \
self.page_height:
# We know that it does not fit, so change/calculate the
# new index and highest_index accordingly.
highest_index = index
index = int(index - (index - smallest_index) / 2)
else:
smallest_index = index
index = int(index + (highest_index - index) / 2)
# We found the number of words which will fit.
if smallest_index == index or highest_index == index:
index = smallest_index
formatted.append(previous_raw.rstrip(u'<br>') +
u''.join(raw_words[:index + 1]))
previous_html = u''
previous_raw = u''
else:
continue
# Check if the rest of the line fits on the slide. If it
# does we do not have to do the much more intensive "word by
# word" checking.
html = self.page_shell + \
u''.join(html_words[index + 1:]).strip() + HTML_END
self.web.setHtml(html)
if self.web_frame.contentsSize().height() <= \
self.page_height:
previous_html = \
u''.join(html_words[index + 1:]).strip() + line_end
previous_raw = \
u''.join(raw_words[index + 1:]).strip() + line_end
break
else:
# The other words do not fit, thus reset the indexes,
# create a new list and continue with "word by word".
raw_words = raw_words[index + 1:]
html_words = html_words[index + 1:]
smallest_index = 0
highest_index = len(html_words) - 1
index = int(highest_index / 2)
html_words = map(expand_tags, raw_words)
previous_html, previous_raw = self._binary_chop(
formatted, previous_html, previous_raw, html_words,
raw_words, u' ', line_end)
else:
previous_html += styled_line + line_end
previous_html += html_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 _binary_chop(self, formatted, previous_html, previous_raw, html_list,
raw_list, separator, line_end):
"""
This implements the binary chop algorithm for faster rendering. This
algorithm works line based (line by line) and word based (word by word).
It is assumed that this method is **only** called, when the lines/words
to be rendered do **not** fit as a whole.
``formatted``
The list to append any slides.
``previous_html``
The html text which is know to fit on a slide, but is not yet added
to the list of slides. (unicode string)
``previous_raw``
The raw text (with display tags) which is know to fit on a slide,
but is not yet added to the list of slides. (unicode string)
``html_list``
The elements which do not fit on a slide and needs to be processed
using the binary chop. The text contains html.
``raw_list``
The elements which do not fit on a slide and needs to be processed
using the binary chop. The elements can contain display tags.
``separator``
The separator for the elements. For lines this is ``u'<br>'`` and
for words this is ``u' '``.
``line_end``
The text added after each "element line". Either ``u' '`` or
``u'<br>``. This is needed for bibles.
"""
smallest_index = 0
highest_index = len(html_list) - 1
index = int(highest_index / 2)
while True:
html = self.page_shell + previous_html + \
separator.join(html_list[:index + 1]).strip() + HTML_END
self.web.setHtml(html)
if self.web_frame.contentsSize().height() > self.page_height:
# We know that it does not fit, so change/calculate the
# new index and highest_index accordingly.
highest_index = index
index = int(index - (index - smallest_index) / 2)
else:
smallest_index = index
index = int(index + (highest_index - index) / 2)
# We found the number of words which will fit.
if smallest_index == index or highest_index == index:
index = smallest_index
formatted.append(previous_raw.rstrip(u'<br>') +
separator.join(raw_list[:index + 1]))
previous_html = u''
previous_raw = u''
# Stop here as the theme line count was requested.
if self.force_page:
Receiver.send_message(u'theme_line_count', index + 1)
break
else:
continue
# Check if the remaining elements fit on the slide.
html = self.page_shell + \
separator.join(html_list[index + 1:]).strip() + HTML_END
self.web.setHtml(html)
if self.web_frame.contentsSize().height() <= self.page_height:
previous_html = separator.join(
html_list[index + 1:]).strip() + line_end
previous_raw = separator.join(
raw_list[index + 1:]).strip() + line_end
break
else:
# The remaining elements do not fit, thus reset the indexes,
# create a new list and continue.
raw_list = raw_list[index + 1:]
html_list = html_list[index + 1:]
smallest_index = 0
highest_index = len(html_list) - 1
index = int(highest_index / 2)
return previous_html, previous_raw
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]
return line.split(u' ')
def _lines_split(self, text):
"""
@ -482,5 +506,5 @@ class Renderer(object):
"""
# 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]
text = text.replace(u'[---]', u'')
return text.split(u'\n')

View File

@ -164,7 +164,6 @@ class ServiceItem(object):
log.debug(u'Render called')
self._display_frames = []
self.bg_image_bytes = None
line_break = not self.is_capable(ItemCapabilities.NoLineBreaks)
theme = self.theme if self.theme else None
self.main, self.footer = \
self.renderer.set_override_theme(theme, use_override)
@ -172,9 +171,8 @@ class ServiceItem(object):
if self.service_item_type == ServiceItemType.Text:
log.debug(u'Formatting slides')
for slide in self._raw_frames:
formatted = self.renderer \
.format_slide(slide[u'raw_slide'], line_break, self)
for page in formatted:
pages = self.renderer.format_slide(slide[u'raw_slide'], self)
for page in pages:
page = page.replace(u'<br>', u'{br}')
html = expand_tags(cgi.escape(page.rstrip()))
self._display_frames.append({
@ -209,7 +207,7 @@ class ServiceItem(object):
"""
self.service_item_type = ServiceItemType.Image
self._raw_frames.append({u'title': title, u'path': path})
self.renderer.image_manager.add_image(title, path)
self.renderer.imageManager.add_image(title, path)
self._new_item()
def add_from_text(self, title, raw_slide, verse_tag=None):
@ -463,7 +461,7 @@ class ServiceItem(object):
elif not start and end:
return end
else:
return u'%s <br />%s' % (start, end)
return u'%s <br>%s' % (start, end)
def update_theme(self, theme):
"""

View File

@ -61,7 +61,7 @@ from screen import ScreenList
from maindisplay import MainDisplay, Display
from servicenoteform import ServiceNoteForm
from serviceitemeditform import ServiceItemEditForm
from slidecontroller import SlideController
from slidecontroller import SlideController, Controller
from splashscreen import SplashScreen
from generaltab import GeneralTab
from themestab import ThemesTab

View File

@ -84,9 +84,9 @@ class MainDisplay(Display):
"""
This is the display screen.
"""
def __init__(self, parent, image_manager, live, controller, plugins):
def __init__(self, parent, imageManager, live, controller, plugins):
Display.__init__(self, parent, live, controller, plugins)
self.image_manager = image_manager
self.imageManager = imageManager
self.screens = ScreenList.get_instance()
self.alertTab = None
self.hideMode = None
@ -231,7 +231,7 @@ class MainDisplay(Display):
"""
API for replacement backgrounds so Images are added directly to cache
"""
self.image_manager.add_image(name, path)
self.imageManager.add_image(name, path)
if hasattr(self, u'serviceItem'):
self.override[u'image'] = name
self.override[u'theme'] = self.serviceItem.themedata.theme_name
@ -248,7 +248,7 @@ class MainDisplay(Display):
The name of the image to be displayed
"""
log.debug(u'image to display')
image = self.image_manager.get_image_bytes(name)
image = self.imageManager.get_image_bytes(name)
self.resetVideo()
self.displayImage(image)
return self.preview()
@ -353,13 +353,13 @@ class MainDisplay(Display):
self.override = {}
else:
# replace the background
background = self.image_manager. \
background = self.imageManager. \
get_image_bytes(self.override[u'image'])
if self.serviceItem.themedata.background_filename:
self.serviceItem.bg_image_bytes = self.image_manager. \
self.serviceItem.bg_image_bytes = self.imageManager. \
get_image_bytes(self.serviceItem.themedata.theme_name)
if image:
image_bytes = self.image_manager.get_image_bytes(image)
image_bytes = self.imageManager.get_image_bytes(image)
else:
image_bytes = None
html = build_html(self.serviceItem, self.screen, self.alertTab,

View File

@ -268,14 +268,16 @@ class MediaManager(object):
controller.media_info.file_info = QtCore.QFileInfo(file)
controller.media_info.is_background = isBackground
if controller.isLive:
if self.withLivePreview:
if self.withLivePreview and controller.previewDisplay:
display = controller.previewDisplay
isValid = self.check_file_type(controller, display)
display = controller.display
isValid = self.check_file_type(controller, display)
display.override[u'theme'] = u''
display.override[u'video'] = True
else:
controller.media_info.start_time = display.serviceItem.start_time
controller.media_info.end_time = display.serviceItem.end_time
elif controller.previewDisplay:
display = controller.previewDisplay
isValid = self.check_file_type(controller, display)
if not isValid:

View File

@ -155,12 +155,22 @@ class PhononAPI(MediaAPI):
display.phononWidget.resize(display.size())
def play(self, display):
self.set_visible(display, True)
controller = display.controller
start_time = 0
vol = float(controller.media_info.volume) / float(10)
display.audio.setVolume(vol)
if display.mediaObject.state() != Phonon.PausedState and \
controller.media_info.start_time > 0:
start_time = controller.media_info.start_time
display.mediaObject.play()
self.state = MediaState.Playing
if self.mediaStateWait(display, Phonon.PlayingState):
if start_time > 0:
self.seek(display, controller.media_info.start_time*1000)
display.audio.setVolume(vol)
controller.media_info.length = \
int(display.mediaObject.totalTime()/1000)
controller.seekSlider.setMaximum(controller.media_info.length*1000)
self.state = MediaState.Playing
self.set_visible(display, True)
def pause(self, display):
display.mediaObject.pause()
@ -193,15 +203,9 @@ class PhononAPI(MediaAPI):
def update_ui(self, display):
controller = display.controller
controller.media_info.length = display.mediaObject.totalTime()
controller.seekSlider.setMaximum(controller.media_info.length)
if controller.media_info.start_time > 0:
if display.mediaObject.currentTime() < \
controller.media_info.start_time:
self.seek(display, controller.media_info.start_time)
if controller.media_info.end_time > 0:
if display.mediaObject.currentTime() > \
controller.media_info.end_time:
controller.media_info.end_time*1000:
self.stop(display)
self.set_visible(display, False)
if not controller.seekSlider.isSliderDown():

View File

@ -300,11 +300,14 @@ class WebkitAPI(MediaAPI):
def play(self, display):
controller = display.controller
display.webLoaded = True
length = 0
self.set_visible(display, True)
if controller.media_info.isFlash:
display.frame.evaluateJavaScript(u'show_flash("play");')
else:
display.frame.evaluateJavaScript(u'show_video("play");')
#TODO add playing check and get the correct media length
controller.media_info.length = length
self.state = MediaState.Playing
def pause(self, display):
@ -374,6 +377,7 @@ class WebkitAPI(MediaAPI):
if ok and length == length:
length = int(length*1000)
if currentTime > 0:
controller.media_info.length = length
controller.seekSlider.setMaximum(length)
if not controller.seekSlider.isSliderDown():
controller.seekSlider.setSliderPosition(currentTime)

View File

@ -66,7 +66,7 @@ class MediaDockManager(object):
match = False
for dock_index in range(0, self.media_dock.count()):
if self.media_dock.widget(dock_index).settingsSection == \
media_item.plugin.name.lower():
media_item.plugin.name:
match = True
break
if not match:
@ -84,6 +84,6 @@ class MediaDockManager(object):
for dock_index in range(0, self.media_dock.count()):
if self.media_dock.widget(dock_index):
if self.media_dock.widget(dock_index).settingsSection == \
media_item.plugin.name.lower():
media_item.plugin.name:
self.media_dock.widget(dock_index).setVisible(False)
self.media_dock.removeItem(dock_index)

View File

@ -240,7 +240,7 @@ class PrintServiceForm(QtGui.QDialog, Ui_PrintServiceDialog):
translate('OpenLP.ServiceManager', 'Notes: '), p,
classId=u'itemNotesTitle')
notes = self._addElement(u'span',
item.notes.replace(u'\n', u'<br />'), p,
item.notes.replace(u'\n', u'<br>'), p,
classId=u'itemNotesText')
# Add play length of media files.
if item.is_media() and self.metaDataCheckBox.isChecked():

View File

@ -781,48 +781,25 @@ class ServiceManager(QtGui.QWidget):
def onMoveSelectionUp(self):
"""
Moves the selection up the window. Called by the up arrow.
Moves the cursor selection up the window.
Called by the up arrow.
"""
serviceIterator = QtGui.QTreeWidgetItemIterator(self.serviceManagerList)
tempItem = None
setLastItem = False
while serviceIterator.value():
if serviceIterator.value().isSelected() and tempItem is None:
setLastItem = True
serviceIterator.value().setSelected(False)
if serviceIterator.value().isSelected():
# We are on the first record
if tempItem:
tempItem.setSelected(True)
serviceIterator.value().setSelected(False)
else:
tempItem = serviceIterator.value()
lastItem = serviceIterator.value()
serviceIterator += 1
# Top Item was selected so set the last one
if setLastItem:
lastItem.setSelected(True)
item = self.serviceManagerList.currentItem()
itemBefore = self.serviceManagerList.itemAbove(item)
if itemBefore is None:
return
self.serviceManagerList.setCurrentItem(itemBefore)
def onMoveSelectionDown(self):
"""
Moves the selection down the window. Called by the down arrow.
Moves the cursor selection down the window.
Called by the down arrow.
"""
serviceIterator = QtGui.QTreeWidgetItemIterator(self.serviceManagerList)
firstItem = None
setSelected = False
while serviceIterator.value():
if not firstItem:
firstItem = serviceIterator.value()
if setSelected:
setSelected = False
serviceIterator.value().setSelected(True)
elif serviceIterator.value() and \
serviceIterator.value().isSelected():
serviceIterator.value().setSelected(False)
setSelected = True
serviceIterator += 1
if setSelected:
firstItem.setSelected(True)
item = self.serviceManagerList.currentItem()
itemAfter = self.serviceManagerList.itemBelow(item)
if itemAfter is None:
return
self.serviceManagerList.setCurrentItem(itemAfter)
def onCollapseAll(self):
"""
@ -966,7 +943,7 @@ class ServiceManager(QtGui.QWidget):
if item[u'service_item'] \
.is_capable(ItemCapabilities.AllowsVariableStartTime):
tips.append(item[u'service_item'].get_media_time())
treewidgetitem.setToolTip(0, u'<br />'.join(tips))
treewidgetitem.setToolTip(0, u'<br>'.join(tips))
treewidgetitem.setData(0, QtCore.Qt.UserRole,
QtCore.QVariant(item[u'order']))
treewidgetitem.setSelected(item[u'selected'])

View File

@ -494,6 +494,11 @@ class SlideController(Controller):
self.mediabar.setVisible(False)
self.toolbar.makeWidgetsInvisible([u'Song Menu'])
self.toolbar.makeWidgetsInvisible(self.loopList)
# Reset the button
self.playSlidesOnce.setChecked(False)
self.playSlidesOnce.setIcon(build_icon(u':/media/media_time.png'))
self.playSlidesLoop.setChecked(False)
self.playSlidesLoop.setIcon(build_icon(u':/media/media_time.png'))
if item.is_text():
if QtCore.QSettings().value(
self.parent().songsSettingsSection + u'/display songbar',

View File

@ -43,7 +43,7 @@ class AlertsPlugin(Plugin):
log.info(u'Alerts Plugin loaded')
def __init__(self, plugin_helpers):
Plugin.__init__(self, u'Alerts', plugin_helpers,
Plugin.__init__(self, u'alerts', plugin_helpers,
settings_tab_class=AlertsTab)
self.weight = -3
self.icon_path = u':/plugins/plugin_alerts.png'

View File

@ -41,7 +41,7 @@ class BiblePlugin(Plugin):
log.info(u'Bible Plugin loaded')
def __init__(self, plugin_helpers):
Plugin.__init__(self, u'Bibles', plugin_helpers,
Plugin.__init__(self, u'bibles', plugin_helpers,
BibleMediaItem, BiblesTab)
self.weight = -9
self.icon_path = u':/plugins/plugin_bibles.png'

View File

@ -46,7 +46,7 @@ class CustomPlugin(Plugin):
log.info(u'Custom Plugin loaded')
def __init__(self, plugin_helpers):
Plugin.__init__(self, u'Custom', plugin_helpers,
Plugin.__init__(self, u'custom', plugin_helpers,
CustomMediaItem, CustomTab)
self.weight = -5
self.manager = Manager(u'custom', init_schema)

View File

@ -36,7 +36,7 @@ class ImagePlugin(Plugin):
log.info(u'Image Plugin loaded')
def __init__(self, plugin_helpers):
Plugin.__init__(self, u'Images', plugin_helpers, ImageMediaItem)
Plugin.__init__(self, u'images', plugin_helpers, ImageMediaItem)
self.weight = -7
self.icon_path = u':/plugins/plugin_images.png'
self.icon = build_icon(self.icon_path)

View File

@ -34,6 +34,7 @@ from PyQt4 import QtCore, QtGui
from openlp.core.lib import MediaManagerItem, build_icon, ItemCapabilities, \
SettingsManager, translate, check_item_selected, Receiver
from openlp.core.lib.ui import UiStrings, critical_error_message_box
from openlp.core.ui import Controller, Display
log = logging.getLogger(__name__)
@ -52,6 +53,15 @@ class MediaMediaItem(MediaManagerItem):
self.singleServiceItem = False
self.hasSearch = True
self.mediaObject = None
self.mediaController = Controller(parent)
self.mediaController.controllerLayout = QtGui.QVBoxLayout()
self.plugin.mediaManager.addControllerItems(self.mediaController, self.mediaController.controllerLayout)
self.plugin.mediaManager.set_controls_visible(self.mediaController, False)
self.mediaController.previewDisplay = Display(self.mediaController, False, self.mediaController, self.plugin.pluginManager.plugins)
self.mediaController.previewDisplay.setup()
self.plugin.mediaManager.setup_display(self.mediaController.previewDisplay)
self.mediaController.previewDisplay.hide()
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'video_background_replaced'),
self.videobackgroundReplaced)
@ -137,10 +147,16 @@ class MediaMediaItem(MediaManagerItem):
'The file %s no longer exists.')) % filename)
return False
self.mediaLength = 0
if self.plugin.mediaManager.video( \
self.mediaController, filename, False, False):
self.mediaLength = self.mediaController.media_info.length
service_item.media_length = self.mediaLength
self.plugin.mediaManager.video_reset(self.mediaController)
if self.mediaLength > 0:
service_item.add_capability(
ItemCapabilities.AllowsVariableStartTime)
print self.mediaLength
service_item.media_length = self.mediaLength
#TODO
#service_item.add_capability(
# ItemCapabilities.AllowsVariableStartTime)
service_item.title = unicode(self.plugin.nameStrings[u'singular'])
service_item.add_capability(ItemCapabilities.RequiresMedia)
# force a non-existent theme

View File

@ -37,7 +37,7 @@ class MediaPlugin(Plugin):
log.info(u'%s MediaPlugin loaded', __name__)
def __init__(self, plugin_helpers):
Plugin.__init__(self, u'Media', plugin_helpers,
Plugin.__init__(self, u'media', plugin_helpers,
MediaMediaItem)
self.weight = -6
self.icon_path = u':/plugins/plugin_media.png'

View File

@ -52,7 +52,7 @@ class PresentationPlugin(Plugin):
"""
log.debug(u'Initialised')
self.controllers = {}
Plugin.__init__(self, u'Presentations', plugin_helpers)
Plugin.__init__(self, u'presentations', plugin_helpers)
self.weight = -8
self.icon_path = u':/plugins/plugin_presentations.png'
self.icon = build_icon(self.icon_path)

View File

@ -39,7 +39,7 @@ class RemotesPlugin(Plugin):
"""
remotes constructor
"""
Plugin.__init__(self, u'Remotes', plugin_helpers,
Plugin.__init__(self, u'remotes', plugin_helpers,
settings_tab_class=RemoteTab)
self.icon_path = u':/plugins/plugin_remote.png'
self.icon = build_icon(self.icon_path)

View File

@ -90,7 +90,7 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
self.onVerseListViewPressed)
QtCore.QObject.connect(self.themeAddButton,
QtCore.SIGNAL(u'clicked()'),
self.mediaitem.plugin.renderer.theme_manager.onAddTheme)
self.mediaitem.plugin.renderer.themeManager.onAddTheme)
QtCore.QObject.connect(self.maintenanceButton,
QtCore.SIGNAL(u'clicked()'), self.onMaintenanceButtonClicked)
QtCore.QObject.connect(Receiver.get_receiver(),

View File

@ -57,7 +57,7 @@ class SongsPlugin(Plugin):
"""
Create and set up the Songs plugin.
"""
Plugin.__init__(self, u'Songs', plugin_helpers, SongMediaItem, SongsTab)
Plugin.__init__(self, u'songs', plugin_helpers, SongMediaItem, SongsTab)
self.weight = -10
self.manager = Manager(u'songs', init_schema)
self.icon_path = u':/plugins/plugin_songs.png'

View File

@ -45,7 +45,7 @@ class SongUsagePlugin(Plugin):
log.info(u'SongUsage Plugin loaded')
def __init__(self, plugin_helpers):
Plugin.__init__(self, u'SongUsage', plugin_helpers)
Plugin.__init__(self, u'songusage', plugin_helpers)
self.weight = -4
self.icon = build_icon(u':/plugins/plugin_songusage.png')
self.activeIcon = build_icon(u':/songusage/song_usage_active.png')

View File

@ -46,12 +46,6 @@ PyEnchant
Inno Setup 5
Inno Setup should be installed into "C:\%PROGRAMFILES%\Inno Setup 5"
UPX
This is used to compress DLLs and EXEs so that they take up less space, but
still function exactly the same. To install UPX, download it from
http://upx.sourceforge.net/, extract it into C:\%PROGRAMFILES%\UPX, and then
add that directory to your PATH environment variable.
Sphinx
This is used to build the documentation. The documentation trunk must be at
the same directory level as Openlp trunk and named "documentation"
@ -179,6 +173,7 @@ def run_pyinstaller():
pyinstaller = Popen((python_exe, pyi_build,
u'--noconfirm',
u'--windowed',
u'--noupx',
u'-o', branch_path,
u'-i', win32_icon,
u'-p', branch_path,