head + conflicts

This commit is contained in:
Andreas Preikschat 2013-07-03 22:20:12 +02:00
commit 15c1c6d907
41 changed files with 576 additions and 529 deletions

View File

@ -29,7 +29,7 @@
""" """
Provide HTML Tag management and Formatting Tag access class Provide HTML Tag management and Formatting Tag access class
""" """
import cPickle import json
from openlp.core.lib import Settings, translate from openlp.core.lib import Settings, translate
@ -66,7 +66,7 @@ class FormattingTags(object):
if isinstance(tag[element], unicode): if isinstance(tag[element], unicode):
tag[element] = tag[element].encode('utf8') tag[element] = tag[element].encode('utf8')
# Formatting Tags were also known as display tags. # Formatting Tags were also known as display tags.
Settings().setValue(u'displayTags/html_tags', cPickle.dumps(tags) if tags else u'') Settings().setValue(u'formattingTags/html_tags', json.dumps(tags) if tags else u'')
@staticmethod @staticmethod
def load_tags(): def load_tags():
@ -156,13 +156,10 @@ class FormattingTags(object):
u'end html': u'', u'protected': True, u'temporary': False}) u'end html': u'', u'protected': True, u'temporary': False})
FormattingTags.add_html_tags(base_tags) FormattingTags.add_html_tags(base_tags)
FormattingTags.add_html_tags(temporary_tags) FormattingTags.add_html_tags(temporary_tags)
# Formatting Tags were also known as display tags. # Formatting Tags were also known as display tags.
user_expands = Settings().value(u'displayTags/html_tags') user_expands_string = str(Settings().value(u'formattingTags/html_tags'))
# cPickle only accepts str not unicode strings
user_expands_string = str(user_expands)
if user_expands_string: if user_expands_string:
user_tags = cPickle.loads(user_expands_string) user_tags = json.loads(user_expands_string)
for tag in user_tags: for tag in user_tags:
for element in tag: for element in tag:
if isinstance(tag[element], str): if isinstance(tag[element], str):

View File

@ -1,3 +1,4 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4 # vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4

View File

@ -728,10 +728,14 @@ class MediaManagerItem(QtGui.QWidget):
def _get_application(self): def _get_application(self):
""" """
Adds the openlp to the class dynamically Adds the openlp to the class dynamically.
Windows needs to access the application in a dynamic manner.
""" """
if not hasattr(self, u'_application'): if os.name == u'nt':
self._application = Registry().get(u'application') return Registry().get(u'application')
return self._application else:
if not hasattr(self, u'_application'):
self._application = Registry().get(u'application')
return self._application
application = property(_get_application) application = property(_get_application)

View File

@ -30,6 +30,7 @@
Provide the generic plugin functionality for OpenLP plugins. Provide the generic plugin functionality for OpenLP plugins.
""" """
import logging import logging
import os
from PyQt4 import QtCore from PyQt4 import QtCore
@ -424,8 +425,11 @@ class Plugin(QtCore.QObject):
""" """
Adds the openlp to the class dynamically Adds the openlp to the class dynamically
""" """
if not hasattr(self, u'_application'): if os.name == u'nt':
self._application = Registry().get(u'application') return Registry().get(u'application')
return self._application else:
if not hasattr(self, u'_application'):
self._application = Registry().get(u'application')
return self._application
application = property(_get_application) application = property(_get_application)

View File

@ -103,9 +103,6 @@ class Registry(object):
``key`` ``key``
The service to be deleted. The service to be deleted.
""" """
if self.running_under_test is False:
log.error(u'Invalid Method call for key %s' % key)
raise KeyError(u'Invalid Method call for key %s' % key)
if key in self.service_list: if key in self.service_list:
del self.service_list[key] del self.service_list[key]

View File

@ -485,6 +485,12 @@ class ServiceItem(object):
""" """
return self.unique_identifier != other.unique_identifier return self.unique_identifier != other.unique_identifier
def __hash__(self):
"""
Return the hash for the service item.
"""
return self.unique_identifier
def is_media(self): def is_media(self):
""" """
Confirms if the ServiceItem is media Confirms if the ServiceItem is media

View File

@ -115,7 +115,7 @@ class Settings(QtCore.QSettings):
u'advanced/single click preview': False, u'advanced/single click preview': False,
u'advanced/x11 bypass wm': X11_BYPASS_DEFAULT, u'advanced/x11 bypass wm': X11_BYPASS_DEFAULT,
u'crashreport/last directory': u'', u'crashreport/last directory': u'',
u'displayTags/html_tags': u'', u'formattingTags/html_tags': u'',
u'core/audio repeat list': False, u'core/audio repeat list': False,
u'core/auto open': False, u'core/auto open': False,
u'core/auto preview': False, u'core/auto preview': False,

View File

@ -34,8 +34,8 @@ import re
import os import os
import platform import platform
import bs4
import sqlalchemy import sqlalchemy
from bs4 import BeautifulSoup
from lxml import etree from lxml import etree
from PyQt4 import Qt, QtCore, QtGui, QtWebKit from PyQt4 import Qt, QtCore, QtGui, QtWebKit
@ -145,7 +145,7 @@ class ExceptionForm(QtGui.QDialog, Ui_ExceptionDialog):
u'QtWebkit: %s\n' % WEBKIT_VERSION + \ u'QtWebkit: %s\n' % WEBKIT_VERSION + \
u'SQLAlchemy: %s\n' % sqlalchemy.__version__ + \ u'SQLAlchemy: %s\n' % sqlalchemy.__version__ + \
u'SQLAlchemy Migrate: %s\n' % MIGRATE_VERSION + \ u'SQLAlchemy Migrate: %s\n' % MIGRATE_VERSION + \
u'BeautifulSoup: %s\n' % BeautifulSoup.__version__ + \ u'BeautifulSoup: %s\n' % bs4.__version__ + \
u'lxml: %s\n' % etree.__version__ + \ u'lxml: %s\n' % etree.__version__ + \
u'Chardet: %s\n' % CHARDET_VERSION + \ u'Chardet: %s\n' % CHARDET_VERSION + \
u'PyEnchant: %s\n' % ENCHANT_VERSION + \ u'PyEnchant: %s\n' % ENCHANT_VERSION + \

View File

@ -485,10 +485,14 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
def _get_application(self): def _get_application(self):
""" """
Adds the openlp to the class dynamically Adds the openlp to the class dynamically.
Windows needs to access the application in a dynamic manner.
""" """
if not hasattr(self, u'_application'): if os.name == u'nt':
self._application = Registry().get(u'application') return Registry().get(u'application')
return self._application else:
if not hasattr(self, u'_application'):
self._application = Registry().get(u'application')
return self._application
application = property(_get_application) application = property(_get_application)

View File

@ -30,7 +30,7 @@
The :mod:`listpreviewwidget` is a widget that lists the slides in the slide controller. The :mod:`listpreviewwidget` is a widget that lists the slides in the slide controller.
It is based on a QTableWidget but represents its contents in list form. It is based on a QTableWidget but represents its contents in list form.
""" """
from __future__ import division
from PyQt4 import QtCore, QtGui from PyQt4 import QtCore, QtGui
from openlp.core.lib import ImageSource, Registry, ServiceItem from openlp.core.lib import ImageSource, Registry, ServiceItem
@ -76,7 +76,7 @@ class ListPreviewWidget(QtGui.QTableWidget):
else: else:
# Sort out image heights. # Sort out image heights.
for framenumber in range(len(self.service_item.get_frames())): for framenumber in range(len(self.service_item.get_frames())):
height = self.viewport().width() / self.screen_ratio height = self.viewport().width() // self.screen_ratio
self.setRowHeight(framenumber, height) self.setRowHeight(framenumber, height)
def screen_size_changed(self, screen_ratio): def screen_size_changed(self, screen_ratio):
@ -101,7 +101,7 @@ class ListPreviewWidget(QtGui.QTableWidget):
for framenumber, frame in enumerate(self.service_item.get_frames()): for framenumber, frame in enumerate(self.service_item.get_frames()):
self.setRowCount(self.slide_count() + 1) self.setRowCount(self.slide_count() + 1)
item = QtGui.QTableWidgetItem() item = QtGui.QTableWidgetItem()
slideHeight = 0 slide_height = 0
if self.service_item.is_text(): if self.service_item.is_text():
if frame[u'verseTag']: if frame[u'verseTag']:
# These tags are already translated. # These tags are already translated.
@ -125,12 +125,12 @@ class ListPreviewWidget(QtGui.QTableWidget):
image = self.image_manager.get_image(frame[u'path'], ImageSource.ImagePlugin) image = self.image_manager.get_image(frame[u'path'], ImageSource.ImagePlugin)
label.setPixmap(QtGui.QPixmap.fromImage(image)) label.setPixmap(QtGui.QPixmap.fromImage(image))
self.setCellWidget(framenumber, 0, label) self.setCellWidget(framenumber, 0, label)
slideHeight = width / self.screen_ratio slide_height = width // self.screen_ratio
row += 1 row += 1
text.append(unicode(row)) text.append(unicode(row))
self.setItem(framenumber, 0, item) self.setItem(framenumber, 0, item)
if slideHeight: if slide_height:
self.setRowHeight(framenumber, slideHeight) self.setRowHeight(framenumber, slide_height)
self.setVerticalHeaderLabels(text) self.setVerticalHeaderLabels(text)
if self.service_item.is_text(): if self.service_item.is_text():
self.resizeRowsToContents() self.resizeRowsToContents()

View File

@ -38,6 +38,7 @@ Some of the code for this form is based on the examples at:
from __future__ import division from __future__ import division
import cgi import cgi
import logging import logging
import os
import sys import sys
from PyQt4 import QtCore, QtGui, QtWebKit, QtOpenGL from PyQt4 import QtCore, QtGui, QtWebKit, QtOpenGL
@ -288,7 +289,7 @@ class MainDisplay(Display):
self.image(path) self.image(path)
# Update the preview frame. # Update the preview frame.
if self.is_live: if self.is_live:
self.live_controller.updatePreview() self.live_controller.update_preview()
return True return True
def image(self, path): def image(self, path):
@ -494,11 +495,15 @@ class MainDisplay(Display):
def _get_application(self): def _get_application(self):
""" """
Adds the openlp to the class dynamically Adds the openlp to the class dynamically.
Windows needs to access the application in a dynamic manner.
""" """
if not hasattr(self, u'_application'): if os.name == u'nt':
self._application = Registry().get(u'application') return Registry().get(u'application')
return self._application else:
if not hasattr(self, u'_application'):
self._application = Registry().get(u'application')
return self._application
application = property(_get_application) application = property(_get_application)

View File

@ -683,7 +683,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
Check and display message if screen blank on setup. Check and display message if screen blank on setup.
""" """
settings = Settings() settings = Settings()
self.live_controller.mainDisplaySetBackground() self.live_controller.main_display_set_background()
if settings.value(u'%s/screen blank' % self.general_settings_section): if settings.value(u'%s/screen blank' % self.general_settings_section):
if settings.value(u'%s/blank warning' % self.general_settings_section): if settings.value(u'%s/blank warning' % self.general_settings_section):
QtGui.QMessageBox.question(self, translate('OpenLP.MainWindow', 'OpenLP Main Display Blanked'), QtGui.QMessageBox.question(self, translate('OpenLP.MainWindow', 'OpenLP Main Display Blanked'),
@ -1076,6 +1076,9 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
if self.live_controller.display: if self.live_controller.display:
self.live_controller.display.close() self.live_controller.display.close()
self.live_controller.display = None self.live_controller.display = None
if os.name == u'nt':
# Needed for Windows to stop crashes on exit
Registry().remove(u'application')
def set_service_modified(self, modified, file_name): def set_service_modified(self, modified, file_name):
""" """
@ -1360,10 +1363,14 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
def _get_application(self): def _get_application(self):
""" """
Adds the openlp to the class dynamically Adds the openlp to the class dynamically.
Windows needs to access the application in a dynamic manner.
""" """
if not hasattr(self, u'_application'): if os.name == u'nt':
self._application = Registry().get(u'application') return Registry().get(u'application')
return self._application else:
if not hasattr(self, u'_application'):
self._application = Registry().get(u'application')
return self._application
application = property(_get_application) application = property(_get_application)

View File

@ -29,6 +29,8 @@
""" """
The :mod:`~openlp.core.ui.media.mediaplayer` module contains the MediaPlayer class. The :mod:`~openlp.core.ui.media.mediaplayer` module contains the MediaPlayer class.
""" """
import os
from openlp.core.lib import Registry from openlp.core.lib import Registry
from openlp.core.ui.media import MediaState from openlp.core.ui.media import MediaState
@ -153,10 +155,14 @@ class MediaPlayer(object):
def _get_application(self): def _get_application(self):
""" """
Adds the openlp to the class dynamically Adds the openlp to the class dynamically.
Windows needs to access the application in a dynamic manner.
""" """
if not hasattr(self, u'_application'): if os.name == u'nt':
self._application = Registry().get(u'application') return Registry().get(u'application')
return self._application else:
if not hasattr(self, u'_application'):
self._application = Registry().get(u'application')
return self._application
application = property(_get_application) application = property(_get_application)

View File

@ -44,113 +44,57 @@ VIDEO_CSS = u"""
z-index:3; z-index:3;
background-color: %(bgcolor)s; background-color: %(bgcolor)s;
} }
#video1 { #video {
background-color: %(bgcolor)s;
z-index:4;
}
#video2 {
background-color: %(bgcolor)s; background-color: %(bgcolor)s;
z-index:4; z-index:4;
} }
""" """
VIDEO_JS = u""" VIDEO_JS = u"""
var video_timer = null; function show_video(state, path, volume, loop, variable_value){
var current_video = '1'; // Sometimes video.currentTime stops slightly short of video.duration and video.ended is intermittent!
function show_video(state, path, volume, loop, varVal){ var video = document.getElementById('video');
// Note, the preferred method for looping would be to use the
// video tag loop attribute.
// But QtWebKit doesn't support this. Neither does it support the
// onended event, hence the setInterval()
// In addition, setting the currentTime attribute to zero to restart
// the video raises an INDEX_SIZE_ERROR: DOM Exception 1
// To complicate it further, sometimes vid.currentTime stops
// slightly short of vid.duration and vid.ended is intermittent!
//
// Note, currently the background may go black between loops. Not
// desirable. Need to investigate using two <video>'s, and hiding/
// preloading one, and toggle between the two when looping.
if(current_video=='1'){
var vid = document.getElementById('video1');
var vid2 = document.getElementById('video2');
} else {
var vid = document.getElementById('video2');
var vid2 = document.getElementById('video1');
}
if(volume != null){ if(volume != null){
vid.volume = volume; video.volume = volume;
vid2.volume = volume;
} }
switch(state){ switch(state){
case 'init':
vid.src = 'file:///' + path;
vid2.src = 'file:///' + path;
if(loop == null) loop = false;
vid.looping = loop;
vid2.looping = loop;
vid.load();
break;
case 'load': case 'load':
vid2.style.visibility = 'hidden'; video.src = 'file:///' + path;
vid2.load(); if(loop == true) {
video.loop = true;
}
video.load();
break; break;
case 'play': case 'play':
vid.play(); video.play();
if(vid.looping){
video_timer = setInterval(
function() {
show_video('poll');
}, 200);
}
break; break;
case 'pause': case 'pause':
if(video_timer!=null){ video.pause();
clearInterval(video_timer);
video_timer = null;
}
vid.pause();
break; break;
case 'stop': case 'stop':
show_video('pause'); show_video('pause');
vid.currentTime = 0; video.currentTime = 0;
break;
case 'poll':
if(vid.ended||vid.currentTime+0.2>vid.duration)
show_video('swap');
break;
case 'swap':
show_video('pause');
if(current_video=='1')
current_video = '2';
else
current_video = '1';
show_video('load');
show_video('play');
show_video('setVisible',null,null,null,'visible');
break; break;
case 'close': case 'close':
show_video('stop'); show_video('stop');
vid.src = ''; video.src = '';
vid2.src = '';
break; break;
case 'length': case 'length':
return vid.duration; return video.duration;
case 'currentTime': case 'current_time':
return vid.currentTime; return video.currentTime;
case 'seek': case 'seek':
// doesnt work currently video.currentTime = variable_value;
vid.currentTime = varVal;
break; break;
case 'isEnded': case 'isEnded':
return vid.ended; return video.ended;
case 'setVisible': case 'setVisible':
vid.style.visibility = varVal; video.style.visibility = variable_value;
break; break;
case 'setBackBoard': case 'setBackBoard':
var back = document.getElementById('videobackboard'); var back = document.getElementById('videobackboard');
back.style.visibility = varVal; back.style.visibility = variable_value;
break; break;
} }
} }
@ -158,10 +102,7 @@ VIDEO_JS = u"""
VIDEO_HTML = u""" VIDEO_HTML = u"""
<div id="videobackboard" class="size" style="visibility:hidden"></div> <div id="videobackboard" class="size" style="visibility:hidden"></div>
<video id="video1" class="size" style="visibility:hidden" autobuffer preload> <video id="video" class="size" style="visibility:hidden" autobuffer preload></video>
</video>
<video id="video2" class="size" style="visibility:hidden" autobuffer preload>
</video>
""" """
FLASH_CSS = u""" FLASH_CSS = u"""
@ -173,25 +114,21 @@ FLASH_CSS = u"""
FLASH_JS = u""" FLASH_JS = u"""
function getFlashMovieObject(movieName) function getFlashMovieObject(movieName)
{ {
if (window.document[movieName]) if (window.document[movieName]){
{
return window.document[movieName]; return window.document[movieName];
} }
if (document.embeds && document.embeds[movieName]) if (document.embeds && document.embeds[movieName]){
return document.embeds[movieName]; return document.embeds[movieName];
}
} }
function show_flash(state, path, volume, varVal){ function show_flash(state, path, volume, variable_value){
var text = document.getElementById('flash'); var text = document.getElementById('flash');
var flashMovie = getFlashMovieObject("OpenLPFlashMovie"); var flashMovie = getFlashMovieObject("OpenLPFlashMovie");
var src = "src = 'file:///" + path + "'"; var src = "src = 'file:///" + path + "'";
var view_parm = " wmode='opaque'" + var view_parm = " wmode='opaque'" + " width='100%%'" + " height='100%%'";
" width='100%%'" + var swf_parm = " name='OpenLPFlashMovie'" + " autostart='true' loop='false' play='true'" +
" height='100%%'"; " hidden='false' swliveconnect='true' allowscriptaccess='always'" + " volume='" + volume + "'";
var swf_parm = " name='OpenLPFlashMovie'" +
" autostart='true' loop='false' play='true'" +
" hidden='false' swliveconnect='true' allowscriptaccess='always'" +
" volume='" + volume + "'";
switch(state){ switch(state){
case 'load': case 'load':
@ -217,15 +154,16 @@ FLASH_JS = u"""
break; break;
case 'length': case 'length':
return flashMovie.TotalFrames(); return flashMovie.TotalFrames();
case 'currentTime': case 'current_time':
return flashMovie.CurrentFrame(); return flashMovie.CurrentFrame();
case 'seek': case 'seek':
// flashMovie.GotoFrame(varVal); // flashMovie.GotoFrame(variable_value);
break; break;
case 'isEnded': case 'isEnded':
return false;//TODO check flash end //TODO check flash end
return false;
case 'setVisible': case 'setVisible':
text.style.visibility = varVal; text.style.visibility = variable_value;
break; break;
} }
} }
@ -338,7 +276,7 @@ class WebkitPlayer(MediaPlayer):
controller.media_info.is_flash = True controller.media_info.is_flash = True
js = u'show_flash("load","%s");' % (path.replace(u'\\', u'\\\\')) js = u'show_flash("load","%s");' % (path.replace(u'\\', u'\\\\'))
else: else:
js = u'show_video("init", "%s", %s, %s);' % (path.replace(u'\\', u'\\\\'), str(vol), loop) js = u'show_video("load", "%s", %s, %s);' % (path.replace(u'\\', u'\\\\'), str(vol), loop)
display.frame.evaluateJavaScript(js) display.frame.evaluateJavaScript(js)
return True return True
@ -447,25 +385,25 @@ class WebkitPlayer(MediaPlayer):
""" """
controller = display.controller controller = display.controller
if controller.media_info.is_flash: if controller.media_info.is_flash:
currentTime = display.frame.evaluateJavaScript(u'show_flash("currentTime");') current_time = display.frame.evaluateJavaScript(u'show_flash("current_time");')
length = display.frame.evaluateJavaScript(u'show_flash("length");') length = display.frame.evaluateJavaScript(u'show_flash("length");')
else: else:
if display.frame.evaluateJavaScript(u'show_video("isEnded");'): if display.frame.evaluateJavaScript(u'show_video("isEnded");'):
self.stop(display) self.stop(display)
currentTime = display.frame.evaluateJavaScript(u'show_video("currentTime");') current_time = display.frame.evaluateJavaScript(u'show_video("current_time");')
# check if conversion was ok and value is not 'NaN' # check if conversion was ok and value is not 'NaN'
if currentTime and currentTime != float('inf'): if current_time and current_time != float('inf'):
currentTime = int(currentTime * 1000) current_time = int(current_time * 1000)
length = display.frame.evaluateJavaScript(u'show_video("length");') length = display.frame.evaluateJavaScript(u'show_video("length");')
# check if conversion was ok and value is not 'NaN' # check if conversion was ok and value is not 'NaN'
if length and length != float('inf'): if length and length != float('inf'):
length = int(length * 1000) length = int(length * 1000)
if currentTime > 0: if current_time:
controller.media_info.length = length controller.media_info.length = length
controller.seek_slider.setMaximum(length) controller.seek_slider.setMaximum(length)
if not controller.seek_slider.isSliderDown(): if not controller.seek_slider.isSliderDown():
controller.seek_slider.blockSignals(True) controller.seek_slider.blockSignals(True)
controller.seek_slider.setSliderPosition(currentTime) controller.seek_slider.setSliderPosition(current_time)
controller.seek_slider.blockSignals(False) controller.seek_slider.blockSignals(False)
def get_info(self): def get_info(self):

View File

@ -30,8 +30,9 @@
The actual plugin view form The actual plugin view form
""" """
import logging import logging
import os
from PyQt4 import QtCore, QtGui from PyQt4 import QtGui
from openlp.core.lib import PluginStatus, Registry, translate from openlp.core.lib import PluginStatus, Registry, translate
from plugindialog import Ui_PluginViewDialog from plugindialog import Ui_PluginViewDialog
@ -166,10 +167,14 @@ class PluginForm(QtGui.QDialog, Ui_PluginViewDialog):
def _get_application(self): def _get_application(self):
""" """
Adds the openlp to the class dynamically Adds the openlp to the class dynamically.
Windows needs to access the application in a dynamic manner.
""" """
if not hasattr(self, u'_application'): if os.name == u'nt':
self._application = Registry().get(u'application') return Registry().get(u'application')
return self._application else:
if not hasattr(self, u'_application'):
self._application = Registry().get(u'application')
return self._application
application = property(_get_application) application = property(_get_application)

View File

@ -1267,7 +1267,7 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
newItem.merge(item[u'service_item']) newItem.merge(item[u'service_item'])
item[u'service_item'] = newItem item[u'service_item'] = newItem
self.repaint_service_list(item_count + 1, 0) self.repaint_service_list(item_count + 1, 0)
self.live_controller.replaceServiceManagerItem(newItem) self.live_controller.replace_service_manager_item(newItem)
self.set_modified() self.set_modified()
def add_service_item(self, item, rebuild=False, expand=None, replace=False, repaint=True, selected=False): def add_service_item(self, item, rebuild=False, expand=None, replace=False, repaint=True, selected=False):
@ -1289,7 +1289,7 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
item.merge(self.service_items[sitem][u'service_item']) item.merge(self.service_items[sitem][u'service_item'])
self.service_items[sitem][u'service_item'] = item self.service_items[sitem][u'service_item'] = item
self.repaint_service_list(sitem, child) self.repaint_service_list(sitem, child)
self.live_controller.replaceServiceManagerItem(item) self.live_controller.replace_service_manager_item(item)
else: else:
item.render() item.render()
# nothing selected for dnd # nothing selected for dnd
@ -1312,7 +1312,7 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
self.repaint_service_list(self.drop_position, -1) self.repaint_service_list(self.drop_position, -1)
# if rebuilding list make sure live is fixed. # if rebuilding list make sure live is fixed.
if rebuild: if rebuild:
self.live_controller.replaceServiceManagerItem(item) self.live_controller.replace_service_manager_item(item)
self.drop_position = 0 self.drop_position = 0
self.set_modified() self.set_modified()
@ -1323,7 +1323,7 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
self.application.set_busy_cursor() self.application.set_busy_cursor()
item, child = self.find_service_item() item, child = self.find_service_item()
if self.service_items[item][u'service_item'].is_valid: if self.service_items[item][u'service_item'].is_valid:
self.preview_controller.addServiceManagerItem(self.service_items[item][u'service_item'], child) self.preview_controller.add_service_manager_item(self.service_items[item][u'service_item'], child)
else: else:
critical_error_message_box(translate('OpenLP.ServiceManager', 'Missing Display Handler'), critical_error_message_box(translate('OpenLP.ServiceManager', 'Missing Display Handler'),
translate('OpenLP.ServiceManager', translate('OpenLP.ServiceManager',
@ -1361,12 +1361,12 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
child = row child = row
self.application.set_busy_cursor() self.application.set_busy_cursor()
if self.service_items[item][u'service_item'].is_valid: if self.service_items[item][u'service_item'].is_valid:
self.live_controller.addServiceManagerItem(self.service_items[item][u'service_item'], child) self.live_controller.add_service_manager_item(self.service_items[item][u'service_item'], child)
if Settings().value(self.main_window.general_settings_section + u'/auto preview'): if Settings().value(self.main_window.general_settings_section + u'/auto preview'):
item += 1 item += 1
if self.service_items and item < len(self.service_items) and \ if self.service_items and item < len(self.service_items) and \
self.service_items[item][u'service_item'].is_capable(ItemCapabilities.CanPreview): self.service_items[item][u'service_item'].is_capable(ItemCapabilities.CanPreview):
self.preview_controller.addServiceManagerItem(self.service_items[item][u'service_item'], 0) self.preview_controller.add_service_manager_item(self.service_items[item][u'service_item'], 0)
next_item = self.service_manager_list.topLevelItem(item) next_item = self.service_manager_list.topLevelItem(item)
self.service_manager_list.setCurrentItem(next_item) self.service_manager_list.setCurrentItem(next_item)
self.live_controller.preview_widget.setFocus() self.live_controller.preview_widget.setFocus()
@ -1588,10 +1588,14 @@ class ServiceManager(QtGui.QWidget, ServiceManagerDialog):
def _get_application(self): def _get_application(self):
""" """
Adds the openlp to the class dynamically Adds the openlp to the class dynamically.
Windows needs to access the application in a dynamic manner.
""" """
if not hasattr(self, u'_application'): if os.name == u'nt':
self._application = Registry().get(u'application') return Registry().get(u'application')
return self._application else:
if not hasattr(self, u'_application'):
self._application = Registry().get(u'application')
return self._application
application = property(_get_application) application = property(_get_application)

View File

@ -29,6 +29,7 @@
""" """
The :mod:`slidecontroller` module contains the most important part of OpenLP - the slide controller The :mod:`slidecontroller` module contains the most important part of OpenLP - the slide controller
""" """
from __future__ import division
import os import os
import logging import logging
import copy import copy
@ -93,7 +94,7 @@ class SlideController(DisplayController):
Registry().register_function(u'bootstrap_post_set_up', self.screen_size_changed) Registry().register_function(u'bootstrap_post_set_up', self.screen_size_changed)
self.screens = ScreenList() self.screens = ScreenList()
try: try:
self.ratio = float(self.screens.current[u'size'].width()) / float(self.screens.current[u'size'].height()) self.ratio = self.screens.current[u'size'].width() / self.screens.current[u'size'].height()
except ZeroDivisionError: except ZeroDivisionError:
self.ratio = 1 self.ratio = 1
self.loop_list = [ self.loop_list = [
@ -194,15 +195,15 @@ class SlideController(DisplayController):
self.toolbar.add_toolbar_widget(self.hide_menu) self.toolbar.add_toolbar_widget(self.hide_menu)
self.blank_screen = create_action(self, u'blankScreen', self.blank_screen = create_action(self, u'blankScreen',
text=translate('OpenLP.SlideController', 'Blank Screen'), icon=u':/slides/slide_blank.png', text=translate('OpenLP.SlideController', 'Blank Screen'), icon=u':/slides/slide_blank.png',
checked=False, can_shortcuts=True, category=self.category, triggers=self.onBlankDisplay) checked=False, can_shortcuts=True, category=self.category, triggers=self.on_blank_display)
self.theme_screen = create_action(self, u'themeScreen', self.theme_screen = create_action(self, u'themeScreen',
text=translate('OpenLP.SlideController', 'Blank to Theme'), icon=u':/slides/slide_theme.png', text=translate('OpenLP.SlideController', 'Blank to Theme'), icon=u':/slides/slide_theme.png',
checked=False, can_shortcuts=True, category=self.category, checked=False, can_shortcuts=True, category=self.category,
triggers=self.onThemeDisplay) triggers=self.on_theme_display)
self.desktop_screen = create_action(self, u'desktopScreen', self.desktop_screen = create_action(self, u'desktopScreen',
text=translate('OpenLP.SlideController', 'Show Desktop'), icon=u':/slides/slide_desktop.png', text=translate('OpenLP.SlideController', 'Show Desktop'), icon=u':/slides/slide_desktop.png',
checked=False, can_shortcuts=True, category=self.category, checked=False, can_shortcuts=True, category=self.category,
triggers=self.onHideDisplay) triggers=self.on_hide_display)
self.hide_menu.setDefaultAction(self.blank_screen) self.hide_menu.setDefaultAction(self.blank_screen)
self.hide_menu.menu().addAction(self.blank_screen) self.hide_menu.menu().addAction(self.blank_screen)
self.hide_menu.menu().addAction(self.theme_screen) self.hide_menu.menu().addAction(self.theme_screen)
@ -230,10 +231,10 @@ class SlideController(DisplayController):
self.toolbar.add_toolbar_widget(self.play_slides_menu) self.toolbar.add_toolbar_widget(self.play_slides_menu)
self.play_slides_loop = create_action(self, u'playSlidesLoop', text=UiStrings().PlaySlidesInLoop, self.play_slides_loop = create_action(self, u'playSlidesLoop', text=UiStrings().PlaySlidesInLoop,
icon=u':/media/media_time.png', checked=False, can_shortcuts=True, icon=u':/media/media_time.png', checked=False, can_shortcuts=True,
category=self.category, triggers=self.onPlaySlidesLoop) category=self.category, triggers=self.on_play_slides_loop)
self.play_slides_once = create_action(self, u'playSlidesOnce', text=UiStrings().PlaySlidesToEnd, self.play_slides_once = create_action(self, u'playSlidesOnce', text=UiStrings().PlaySlidesToEnd,
icon=u':/media/media_time.png', checked=False, can_shortcuts=True, icon=u':/media/media_time.png', checked=False, can_shortcuts=True,
category=self.category, triggers=self.onPlaySlidesOnce) category=self.category, triggers=self.on_play_slides_once)
if Settings().value(self.main_window.advanced_settings_section + u'/slide limits') == SlideLimits.Wrap: if Settings().value(self.main_window.advanced_settings_section + u'/slide limits') == SlideLimits.Wrap:
self.play_slides_menu.setDefaultAction(self.play_slides_loop) self.play_slides_menu.setDefaultAction(self.play_slides_loop)
else: else:
@ -249,12 +250,12 @@ class SlideController(DisplayController):
self.toolbar.add_toolbar_widget(self.delay_spin_box) self.toolbar.add_toolbar_widget(self.delay_spin_box)
else: else:
self.toolbar.add_toolbar_action(u'goLive', icon=u':/general/general_live.png', self.toolbar.add_toolbar_action(u'goLive', icon=u':/general/general_live.png',
tooltip=translate('OpenLP.SlideController', 'Move to live.'), triggers=self.onGoLive) tooltip=translate('OpenLP.SlideController', 'Move to live.'), triggers=self.on_go_live)
self.toolbar.add_toolbar_action(u'addToService', icon=u':/general/general_add.png', self.toolbar.add_toolbar_action(u'addToService', icon=u':/general/general_add.png',
tooltip=translate('OpenLP.SlideController', 'Add to Service.'), triggers=self.onPreviewAddToService) tooltip=translate('OpenLP.SlideController', 'Add to Service.'), triggers=self.on_preview_add_to_service)
self.toolbar.addSeparator() self.toolbar.addSeparator()
self.toolbar.add_toolbar_action(u'editSong', icon=u':/general/general_edit.png', self.toolbar.add_toolbar_action(u'editSong', icon=u':/general/general_edit.png',
tooltip=translate('OpenLP.SlideController', 'Edit and reload song preview.'), triggers=self.onEditSong) tooltip=translate('OpenLP.SlideController', 'Edit and reload song preview.'), triggers=self.on_edit_song)
self.controller_layout.addWidget(self.toolbar) self.controller_layout.addWidget(self.toolbar)
# Build the Media Toolbar # Build the Media Toolbar
self.media_controller.register_controller(self) self.media_controller.register_controller(self)
@ -272,7 +273,7 @@ class SlideController(DisplayController):
icon=u':/slides/media_playback_pause.png', text=translate('OpenLP.SlideController', 'Pause Audio'), icon=u':/slides/media_playback_pause.png', text=translate('OpenLP.SlideController', 'Pause Audio'),
tooltip=translate('OpenLP.SlideController', 'Pause audio.'), tooltip=translate('OpenLP.SlideController', 'Pause audio.'),
checked=False, visible=False, category=self.category, context=QtCore.Qt.WindowShortcut, checked=False, visible=False, category=self.category, context=QtCore.Qt.WindowShortcut,
can_shortcuts=True, triggers=self.onAudioPauseClicked) can_shortcuts=True, triggers=self.set_audio_pause_clicked)
self.audio_menu = QtGui.QMenu(translate('OpenLP.SlideController', 'Background Audio'), self.toolbar) self.audio_menu = QtGui.QMenu(translate('OpenLP.SlideController', 'Background Audio'), self.toolbar)
self.audio_pause_item.setMenu(self.audio_menu) self.audio_pause_item.setMenu(self.audio_menu)
self.audio_pause_item.setParent(self.toolbar) self.audio_pause_item.setParent(self.toolbar)
@ -281,7 +282,7 @@ class SlideController(DisplayController):
self.nextTrackItem = create_action(self, u'nextTrackItem', text=UiStrings().NextTrack, self.nextTrackItem = create_action(self, u'nextTrackItem', text=UiStrings().NextTrack,
icon=u':/slides/media_playback_next.png', icon=u':/slides/media_playback_next.png',
tooltip=translate('OpenLP.SlideController', 'Go to next audio track.'), tooltip=translate('OpenLP.SlideController', 'Go to next audio track.'),
category=self.category, can_shortcuts=True, triggers=self.onNextTrackClicked) category=self.category, can_shortcuts=True, triggers=self.on_next_track_clicked)
self.audio_menu.addAction(self.nextTrackItem) self.audio_menu.addAction(self.nextTrackItem)
self.trackMenu = self.audio_menu.addMenu(translate('OpenLP.SlideController', 'Tracks')) self.trackMenu = self.audio_menu.addMenu(translate('OpenLP.SlideController', 'Tracks'))
self.audio_time_label = QtGui.QLabel(u' 00:00 ', self.toolbar) self.audio_time_label = QtGui.QLabel(u' 00:00 ', self.toolbar)
@ -348,10 +349,10 @@ class SlideController(DisplayController):
can_shortcuts=True, can_shortcuts=True,
context=QtCore.Qt.WidgetWithChildrenShortcut, context=QtCore.Qt.WidgetWithChildrenShortcut,
category=self.category if s.get(u'configurable') else None, category=self.category if s.get(u'configurable') else None,
triggers=self._slideShortcutActivated) for s in shortcuts]) triggers=self._slide_shortcut_activated) for s in shortcuts])
self.shortcutTimer.timeout.connect(self._slideShortcutActivated) self.shortcutTimer.timeout.connect(self._slide_shortcut_activated)
# Signals # Signals
self.preview_widget.clicked.connect(self.onSlideSelected) self.preview_widget.clicked.connect(self.on_slide_selected)
if self.is_live: if self.is_live:
# Need to use event as called across threads and UI is updated # Need to use event as called across threads and UI is updated
QtCore.QObject.connect(self, QtCore.SIGNAL(u'slidecontroller_toggle_display'), self.toggle_display) QtCore.QObject.connect(self, QtCore.SIGNAL(u'slidecontroller_toggle_display'), self.toggle_display)
@ -359,11 +360,11 @@ class SlideController(DisplayController):
self.toolbar.set_widget_visible(self.loop_list, False) self.toolbar.set_widget_visible(self.loop_list, False)
self.toolbar.set_widget_visible(self.wide_menu, False) self.toolbar.set_widget_visible(self.wide_menu, False)
else: else:
self.preview_widget.doubleClicked.connect(self.onGoLiveClick) self.preview_widget.doubleClicked.connect(self.on_preview_add_to_service)
self.toolbar.set_widget_visible([u'editSong'], False) self.toolbar.set_widget_visible([u'editSong'], False)
if self.is_live: if self.is_live:
self.setLiveHotkeys(self) self.set_live_hotkeys(self)
self.__addActionsToWidget(self.controller) self.__add_actions_to_widget(self.controller)
else: else:
self.controller.addActions([self.nextItem, self.previous_item]) self.controller.addActions([self.nextItem, self.previous_item])
Registry().register_function(u'slidecontroller_%s_stop_loop' % self.type_prefix, self.on_stop_loop) Registry().register_function(u'slidecontroller_%s_stop_loop' % self.type_prefix, self.on_stop_loop)
@ -378,7 +379,7 @@ class SlideController(DisplayController):
QtCore.QObject.connect(self, QtCore.SIGNAL(u'slidecontroller_%s_previous' % self.type_prefix), QtCore.QObject.connect(self, QtCore.SIGNAL(u'slidecontroller_%s_previous' % self.type_prefix),
self.on_slide_selected_previous) self.on_slide_selected_previous)
def _slideShortcutActivated(self): def _slide_shortcut_activated(self):
""" """
Called, when a shortcut has been activated to jump to a chorus, verse, Called, when a shortcut has been activated to jump to a chorus, verse,
etc. etc.
@ -425,7 +426,7 @@ class SlideController(DisplayController):
self.shortcutTimer.stop() self.shortcutTimer.stop()
self.current_shortcut = u'' self.current_shortcut = u''
self.preview_widget.change_slide(self.slideList[matches[0]]) self.preview_widget.change_slide(self.slideList[matches[0]])
self.slideSelected() self.slide_selected()
elif sender_name != u'shortcutTimer': elif sender_name != u'shortcutTimer':
# Start the time as we did not have any match. # Start the time as we did not have any match.
self.shortcutTimer.start(350) self.shortcutTimer.start(350)
@ -435,28 +436,28 @@ class SlideController(DisplayController):
# We had more than one match for example "V1" and "V10", but # We had more than one match for example "V1" and "V10", but
# "V1" was the slide we wanted to go. # "V1" was the slide we wanted to go.
self.preview_widget.change_slide(self.slideList[self.current_shortcut]) self.preview_widget.change_slide(self.slideList[self.current_shortcut])
self.slideSelected() self.slide_selected()
# Reset the shortcut. # Reset the shortcut.
self.current_shortcut = u'' self.current_shortcut = u''
def setLiveHotkeys(self, parent=None): def set_live_hotkeys(self, parent=None):
""" """
Set the live hotkeys Set the live hotkeys
""" """
self.previousService = create_action(parent, u'previousService', self.previousService = create_action(parent, u'previousService',
text=translate('OpenLP.SlideController', 'Previous Service'), text=translate('OpenLP.SlideController', 'Previous Service'),
can_shortcuts=True, context=QtCore.Qt.WidgetWithChildrenShortcut, category=self.category, can_shortcuts=True, context=QtCore.Qt.WidgetWithChildrenShortcut, category=self.category,
triggers=self.servicePrevious) triggers=self.service_previous)
self.nextService = create_action(parent, 'nextService', self.nextService = create_action(parent, 'nextService',
text=translate('OpenLP.SlideController', 'Next Service'), text=translate('OpenLP.SlideController', 'Next Service'),
can_shortcuts=True, context=QtCore.Qt.WidgetWithChildrenShortcut, category=self.category, can_shortcuts=True, context=QtCore.Qt.WidgetWithChildrenShortcut, category=self.category,
triggers=self.serviceNext) triggers=self.service_next)
self.escapeItem = create_action(parent, 'escapeItem', self.escapeItem = create_action(parent, 'escapeItem',
text=translate('OpenLP.SlideController', 'Escape Item'), text=translate('OpenLP.SlideController', 'Escape Item'),
can_shortcuts=True, context=QtCore.Qt.WidgetWithChildrenShortcut, category=self.category, can_shortcuts=True, context=QtCore.Qt.WidgetWithChildrenShortcut, category=self.category,
triggers=self.liveEscape) triggers=self.live_escape)
def liveEscape(self): def live_escape(self):
""" """
If you press ESC on the live screen it should close the display temporarily. If you press ESC on the live screen it should close the display temporarily.
""" """
@ -468,24 +469,24 @@ class SlideController(DisplayController):
Toggle the display settings triggered from remote messages. Toggle the display settings triggered from remote messages.
""" """
if action == u'blank' or action == u'hide': if action == u'blank' or action == u'hide':
self.onBlankDisplay(True) self.on_blank_display(True)
elif action == u'theme': elif action == u'theme':
self.onThemeDisplay(True) self.on_theme_display(True)
elif action == u'desktop': elif action == u'desktop':
self.onHideDisplay(True) self.on_hide_display(True)
elif action == u'show': elif action == u'show':
self.onBlankDisplay(False) self.on_blank_display(False)
self.onThemeDisplay(False) self.on_theme_display(False)
self.onHideDisplay(False) self.on_hide_display(False)
def servicePrevious(self): def service_previous(self):
""" """
Live event to select the previous service item from the service manager. Live event to select the previous service item from the service manager.
""" """
self.keypress_queue.append(ServiceItemAction.Previous) self.keypress_queue.append(ServiceItemAction.Previous)
self._process_queue() self._process_queue()
def serviceNext(self): def service_next(self):
""" """
Live event to select the next service item from the service manager. Live event to select the next service item from the service manager.
""" """
@ -520,11 +521,11 @@ class SlideController(DisplayController):
self.display = MainDisplay(self, self.is_live, self) self.display = MainDisplay(self, self.is_live, self)
self.display.setup() self.display.setup()
if self.is_live: if self.is_live:
self.__addActionsToWidget(self.display) self.__add_actions_to_widget(self.display)
self.display.audio_player.connectSlot(QtCore.SIGNAL(u'tick(qint64)'), self.on_audio_time_remaining) self.display.audio_player.connectSlot(QtCore.SIGNAL(u'tick(qint64)'), self.on_audio_time_remaining)
# The SlidePreview's ratio. # The SlidePreview's ratio.
try: try:
self.ratio = float(self.screens.current[u'size'].width()) / float(self.screens.current[u'size'].height()) self.ratio = self.screens.current[u'size'].width() / self.screens.current[u'size'].height()
except ZeroDivisionError: except ZeroDivisionError:
self.ratio = 1 self.ratio = 1
self.media_controller.setup_display(self.display, False) self.media_controller.setup_display(self.display, False)
@ -538,7 +539,7 @@ class SlideController(DisplayController):
if self.service_item: if self.service_item:
self.refresh_service_item() self.refresh_service_item()
def __addActionsToWidget(self, widget): def __add_actions_to_widget(self, widget):
""" """
Add actions to the widget specified by `widget` Add actions to the widget specified by `widget`
""" """
@ -553,7 +554,7 @@ class SlideController(DisplayController):
splitters is moved or when the screen size is changed. Note, that this splitters is moved or when the screen size is changed. Note, that this
method is (also) called frequently from the mainwindow *paintEvent*. method is (also) called frequently from the mainwindow *paintEvent*.
""" """
if self.ratio < float(self.preview_frame.width()) / float(self.preview_frame.height()): if self.ratio < self.preview_frame.width() / self.preview_frame.height():
# We have to take the height as limit. # We have to take the height as limit.
max_height = self.preview_frame.height() - self.grid.margin() * 2 max_height = self.preview_frame.height() - self.grid.margin() * 2
self.slide_preview.setFixedSize(QtCore.QSize(max_height * self.ratio, max_height)) self.slide_preview.setFixedSize(QtCore.QSize(max_height * self.ratio, max_height))
@ -566,9 +567,9 @@ class SlideController(DisplayController):
self.slide_preview.setFixedSize(QtCore.QSize(max_width, max_width / self.ratio)) self.slide_preview.setFixedSize(QtCore.QSize(max_width, max_width / self.ratio))
self.preview_display.setFixedSize(QtCore.QSize(max_width, max_width / self.ratio)) self.preview_display.setFixedSize(QtCore.QSize(max_width, max_width / self.ratio))
self.preview_display.screen = {u'size': self.preview_display.geometry()} self.preview_display.screen = {u'size': self.preview_display.geometry()}
self.onControllerSizeChanged(self.controller.width()) self.on_controller_size_changed(self.controller.width())
def onControllerSizeChanged(self, width): def on_controller_size_changed(self, width):
""" """
Change layout of display control buttons on controller size change Change layout of display control buttons on controller size change
""" """
@ -584,14 +585,15 @@ class SlideController(DisplayController):
self.toolbar.set_widget_visible(self.wide_menu, False) self.toolbar.set_widget_visible(self.wide_menu, False)
self.toolbar.set_widget_visible(self.narrow_menu) self.toolbar.set_widget_visible(self.narrow_menu)
def onSongBarHandler(self): def on_song_bar_handler(self):
""" """
Some song handler Some song handler
""" """
request = self.sender().text() request = self.sender().text()
slide_no = self.slideList[request] slide_no = self.slideList[request]
self.__updatePreviewSelection(slide_no) width = self.main_window.controlSplitter.sizes()[self.split]
self.slideSelected() self.preview_widget.replace_service_item(self.service_item, width, slide_no)
self.slide_selected()
def receive_spin_delay(self): def receive_spin_delay(self):
""" """
@ -679,44 +681,44 @@ class SlideController(DisplayController):
""" """
log.debug(u'add_service_item live = %s' % self.is_live) log.debug(u'add_service_item live = %s' % self.is_live)
item.render() item.render()
slideno = 0 slide_no = 0
if self.song_edit: if self.song_edit:
slideno = self.selected_row slide_no = self.selected_row
self.song_edit = False self.song_edit = False
self._process_item(item, slideno) self._process_item(item, slide_no)
def replaceServiceManagerItem(self, item): def replace_service_manager_item(self, item):
""" """
Replacement item following a remote edit Replacement item following a remote edit
""" """
if item == self.service_item: if item == self.service_item:
self._process_item(item, self.preview_widget.current_slide_number()) self._process_item(item, self.preview_widget.current_slide_number())
def addServiceManagerItem(self, item, slideno): def add_service_manager_item(self, item, slide_no):
""" """
Method to install the service item into the controller and request the correct toolbar for the plugin. Called by Method to install the service item into the controller and request the correct toolbar for the plugin. Called by
:class:`~openlp.core.ui.ServiceManager` :class:`~openlp.core.ui.ServiceManager`
""" """
log.debug(u'addServiceManagerItem live = %s' % self.is_live) log.debug(u'add_service_manager_item live = %s' % self.is_live)
# If no valid slide number is specified we take the first one, but we # If no valid slide number is specified we take the first one, but we remember the initial value to see if we
# remember the initial value to see if we should reload the song or not # should reload the song or not
slidenum = slideno slidenum = slide_no
if slideno == -1: if slide_no == -1:
slidenum = 0 slidenum = 0
# If service item is the same as the current one, only change slide # If service item is the same as the current one, only change slide
if slideno >= 0 and item == self.service_item: if slide_no >= 0 and item == self.service_item:
self.preview_widget.change_slide(slidenum) self.preview_widget.change_slide(slidenum)
self.slideSelected() self.slide_selected()
else: else:
self._process_item(item, slidenum) self._process_item(item, slidenum)
if self.is_live and item.auto_play_slides_loop and item.timed_slide_interval > 0: if self.is_live and item.auto_play_slides_loop and item.timed_slide_interval > 0:
self.play_slides_loop.setChecked(item.auto_play_slides_loop) self.play_slides_loop.setChecked(item.auto_play_slides_loop)
self.delay_spin_box.setValue(int(item.timed_slide_interval)) self.delay_spin_box.setValue(int(item.timed_slide_interval))
self.onPlaySlidesLoop() self.on_play_slides_loop()
elif self.is_live and item.auto_play_slides_once and item.timed_slide_interval > 0: elif self.is_live and item.auto_play_slides_once and item.timed_slide_interval > 0:
self.play_slides_once.setChecked(item.auto_play_slides_once) self.play_slides_once.setChecked(item.auto_play_slides_once)
self.delay_spin_box.setValue(int(item.timed_slide_interval)) self.delay_spin_box.setValue(int(item.timed_slide_interval))
self.onPlaySlidesOnce() self.on_play_slides_once()
def _process_item(self, service_item, slideno): def _process_item(self, service_item, slideno):
""" """
@ -728,14 +730,14 @@ class SlideController(DisplayController):
# take a copy not a link to the servicemanager copy. # take a copy not a link to the servicemanager copy.
self.service_item = copy.copy(service_item) self.service_item = copy.copy(service_item)
if old_item and self.is_live and old_item.is_capable(ItemCapabilities.ProvidesOwnDisplay): if old_item and self.is_live and old_item.is_capable(ItemCapabilities.ProvidesOwnDisplay):
self._resetBlank() self._reset_blank()
Registry().execute( Registry().execute(
u'%s_start' % service_item.name.lower(), [service_item, self.is_live, self.hide_mode(), slideno]) u'%s_start' % service_item.name.lower(), [service_item, self.is_live, self.hide_mode(), slideno])
self.slideList = {} self.slideList = {}
if self.is_live: if self.is_live:
self.song_menu.menu().clear() self.song_menu.menu().clear()
self.display.audio_player.reset() self.display.audio_player.reset()
self.setAudioItemsVisibility(False) self.set_audio_items_visibility(False)
self.audio_pause_item.setChecked(False) self.audio_pause_item.setChecked(False)
# If the current item has background audio # If the current item has background audio
if self.service_item.is_capable(ItemCapabilities.HasBackgroundAudio): if self.service_item.is_capable(ItemCapabilities.HasBackgroundAudio):
@ -745,7 +747,7 @@ class SlideController(DisplayController):
for counter in range(len(self.service_item.background_audio)): for counter in range(len(self.service_item.background_audio)):
action = self.trackMenu.addAction(os.path.basename(self.service_item.background_audio[counter])) action = self.trackMenu.addAction(os.path.basename(self.service_item.background_audio[counter]))
action.setData(counter) action.setData(counter)
action.triggered.connect(self.onTrackTriggered) action.triggered.connect(self.on_track_triggered)
self.display.audio_player.repeat = Settings().value( self.display.audio_player.repeat = Settings().value(
self.main_window.general_settings_section + u'/audio repeat list') self.main_window.general_settings_section + u'/audio repeat list')
if Settings().value(self.main_window.general_settings_section + u'/audio start paused'): if Settings().value(self.main_window.general_settings_section + u'/audio start paused'):
@ -753,12 +755,10 @@ class SlideController(DisplayController):
self.display.audio_player.pause() self.display.audio_player.pause()
else: else:
self.display.audio_player.play() self.display.audio_player.play()
self.setAudioItemsVisibility(True) self.set_audio_items_visibility(True)
row = 0 row = 0
text = [] width = self.main_window.controlSplitter.sizes()[self.split]
width = self.main_window.control_splitter.sizes()[self.split]
for framenumber, frame in enumerate(self.service_item.get_frames()): for framenumber, frame in enumerate(self.service_item.get_frames()):
slideHeight = 0
if self.service_item.is_text(): if self.service_item.is_text():
if frame[u'verseTag']: if frame[u'verseTag']:
# These tags are already translated. # These tags are already translated.
@ -769,12 +769,11 @@ class SlideController(DisplayController):
if verse_def not in self.slideList: if verse_def not in self.slideList:
self.slideList[verse_def] = framenumber self.slideList[verse_def] = framenumber
if self.is_live: if self.is_live:
self.song_menu.menu().addAction(verse_def, self.onSongBarHandler) self.song_menu.menu().addAction(verse_def, self.on_song_bar_handler)
else: else:
row += 1 row += 1
self.slideList[unicode(row)] = row - 1 self.slideList[unicode(row)] = row - 1
else: else:
slideHeight = width * (1 / self.ratio)
row += 1 row += 1
self.slideList[unicode(row)] = row - 1 self.slideList[unicode(row)] = row - 1
# If current slide set background to image # If current slide set background to image
@ -789,8 +788,8 @@ class SlideController(DisplayController):
if not self.service_item.is_image(): if not self.service_item.is_image():
self.display.build_html(self.service_item) self.display.build_html(self.service_item)
if service_item.is_media(): if service_item.is_media():
self.onMediaStart(service_item) self.on_media_start(service_item)
self.slideSelected(True) self.slide_selected(True)
if old_item: if old_item:
# Close the old item after the new one is opened # Close the old item after the new one is opened
# This avoids the service theme/desktop flashing on screen # This avoids the service theme/desktop flashing on screen
@ -799,7 +798,7 @@ class SlideController(DisplayController):
if old_item.is_command() and not service_item.is_command(): if old_item.is_command() and not service_item.is_command():
Registry().execute(u'%s_stop' % old_item.name.lower(), [old_item, self.is_live]) Registry().execute(u'%s_stop' % old_item.name.lower(), [old_item, self.is_live])
if old_item.is_media() and not service_item.is_media(): if old_item.is_media() and not service_item.is_media():
self.onMediaClose() self.on_media_close()
Registry().execute(u'slidecontroller_%s_started' % self.type_prefix, [service_item]) Registry().execute(u'slidecontroller_%s_started' % self.type_prefix, [service_item])
# Screen event methods # Screen event methods
@ -812,49 +811,49 @@ class SlideController(DisplayController):
return return
if self.service_item.is_command(): if self.service_item.is_command():
Registry().execute(u'%s_slide' % self.service_item.name.lower(), [self.service_item, self.is_live, index]) Registry().execute(u'%s_slide' % self.service_item.name.lower(), [self.service_item, self.is_live, index])
self.updatePreview() self.update_preview()
else: else:
self.preview_widget.change_slide(index) self.preview_widget.change_slide(index)
self.slideSelected() self.slide_selected()
def mainDisplaySetBackground(self): def main_display_set_background(self):
""" """
Allow the main display to blank the main display at startup time Allow the main display to blank the main display at startup time
""" """
log.debug(u'mainDisplaySetBackground live = %s' % self.is_live) log.debug(u'main_display_set_background live = %s' % self.is_live)
display_type = Settings().value(self.main_window.general_settings_section + u'/screen blank') display_type = Settings().value(self.main_window.general_settings_section + u'/screen blank')
if self.screens.which_screen(self.window()) != self.screens.which_screen(self.display): if self.screens.which_screen(self.window()) != self.screens.which_screen(self.display):
# Order done to handle initial conversion # Order done to handle initial conversion
if display_type == u'themed': if display_type == u'themed':
self.onThemeDisplay(True) self.on_theme_display(True)
elif display_type == u'hidden': elif display_type == u'hidden':
self.onHideDisplay(True) self.on_hide_display(True)
elif display_type == u'blanked': elif display_type == u'blanked':
self.onBlankDisplay(True) self.on_blank_display(True)
else: else:
Registry().execute(u'live_display_show') Registry().execute(u'live_display_show')
else: else:
self.liveEscape() self.live_escape()
def on_slide_blank(self): def on_slide_blank(self):
""" """
Handle the slidecontroller blank event Handle the slidecontroller blank event
""" """
self.onBlankDisplay(True) self.on_blank_display(True)
def on_slide_unblank(self): def on_slide_unblank(self):
""" """
Handle the slidecontroller unblank event Handle the slidecontroller unblank event
""" """
self.onBlankDisplay(False) self.on_blank_display(False)
def onBlankDisplay(self, checked=None): def on_blank_display(self, checked=None):
""" """
Handle the blank screen button actions Handle the blank screen button actions
""" """
if checked is None: if checked is None:
checked = self.blank_screen.isChecked() checked = self.blank_screen.isChecked()
log.debug(u'onBlankDisplay %s' % checked) log.debug(u'on_blank_display %s' % checked)
self.hide_menu.setDefaultAction(self.blank_screen) self.hide_menu.setDefaultAction(self.blank_screen)
self.blank_screen.setChecked(checked) self.blank_screen.setChecked(checked)
self.theme_screen.setChecked(False) self.theme_screen.setChecked(False)
@ -863,17 +862,17 @@ class SlideController(DisplayController):
Settings().setValue(self.main_window.general_settings_section + u'/screen blank', u'blanked') Settings().setValue(self.main_window.general_settings_section + u'/screen blank', u'blanked')
else: else:
Settings().remove(self.main_window.general_settings_section + u'/screen blank') Settings().remove(self.main_window.general_settings_section + u'/screen blank')
self.blankPlugin() self.blank_plugin()
self.updatePreview() self.update_preview()
self.onToggleLoop() self.on_toggle_loop()
def onThemeDisplay(self, checked=None): def on_theme_display(self, checked=None):
""" """
Handle the Theme screen button Handle the Theme screen button
""" """
if checked is None: if checked is None:
checked = self.theme_screen.isChecked() checked = self.theme_screen.isChecked()
log.debug(u'onThemeDisplay %s' % checked) log.debug(u'on_theme_display %s' % checked)
self.hide_menu.setDefaultAction(self.theme_screen) self.hide_menu.setDefaultAction(self.theme_screen)
self.blank_screen.setChecked(False) self.blank_screen.setChecked(False)
self.theme_screen.setChecked(checked) self.theme_screen.setChecked(checked)
@ -882,17 +881,17 @@ class SlideController(DisplayController):
Settings().setValue(self.main_window.general_settings_section + u'/screen blank', u'themed') Settings().setValue(self.main_window.general_settings_section + u'/screen blank', u'themed')
else: else:
Settings().remove(self.main_window.general_settings_section + u'/screen blank') Settings().remove(self.main_window.general_settings_section + u'/screen blank')
self.blankPlugin() self.blank_plugin()
self.updatePreview() self.update_preview()
self.onToggleLoop() self.on_toggle_loop()
def onHideDisplay(self, checked=None): def on_hide_display(self, checked=None):
""" """
Handle the Hide screen button Handle the Hide screen button
""" """
if checked is None: if checked is None:
checked = self.desktop_screen.isChecked() checked = self.desktop_screen.isChecked()
log.debug(u'onHideDisplay %s' % checked) log.debug(u'on_hide_display %s' % checked)
self.hide_menu.setDefaultAction(self.desktop_screen) self.hide_menu.setDefaultAction(self.desktop_screen)
self.blank_screen.setChecked(False) self.blank_screen.setChecked(False)
self.theme_screen.setChecked(False) self.theme_screen.setChecked(False)
@ -901,16 +900,16 @@ class SlideController(DisplayController):
Settings().setValue(self.main_window.general_settings_section + u'/screen blank', u'hidden') Settings().setValue(self.main_window.general_settings_section + u'/screen blank', u'hidden')
else: else:
Settings().remove(self.main_window.general_settings_section + u'/screen blank') Settings().remove(self.main_window.general_settings_section + u'/screen blank')
self.hidePlugin(checked) self.hide_plugin(checked)
self.updatePreview() self.update_preview()
self.onToggleLoop() self.on_toggle_loop()
def blankPlugin(self): def blank_plugin(self):
""" """
Blank/Hide the display screen within a plugin if required. Blank/Hide the display screen within a plugin if required.
""" """
hide_mode = self.hide_mode() hide_mode = self.hide_mode()
log.debug(u'blankPlugin %s ', hide_mode) log.debug(u'blank_plugin %s ', hide_mode)
if self.service_item is not None: if self.service_item is not None:
if hide_mode: if hide_mode:
if not self.service_item.is_command(): if not self.service_item.is_command():
@ -927,11 +926,11 @@ class SlideController(DisplayController):
else: else:
Registry().execute(u'live_display_show') Registry().execute(u'live_display_show')
def hidePlugin(self, hide): def hide_plugin(self, hide):
""" """
Tell the plugin to hide the display screen. Tell the plugin to hide the display screen.
""" """
log.debug(u'hidePlugin %s ', hide) log.debug(u'hide_plugin %s ', hide)
if self.service_item is not None: if self.service_item is not None:
if hide: if hide:
Registry().execute(u'live_display_hide', HideMode.Screen) Registry().execute(u'live_display_hide', HideMode.Screen)
@ -946,13 +945,13 @@ class SlideController(DisplayController):
else: else:
Registry().execute(u'live_display_show') Registry().execute(u'live_display_show')
def onSlideSelected(self): def on_slide_selected(self):
""" """
Slide selected in controller Slide selected in controller
""" """
self.slideSelected() self.slide_selected()
def slideSelected(self, start=False): def slide_selected(self, start=False):
""" """
Generate the preview when you click on a slide. Generate the preview when you click on a slide.
if this is the Live Controller also display on the screen if this is the Live Controller also display on the screen
@ -975,7 +974,7 @@ class SlideController(DisplayController):
self.display.image(to_display) self.display.image(to_display)
# reset the store used to display first image # reset the store used to display first image
self.service_item.bg_image_bytes = None self.service_item.bg_image_bytes = None
self.updatePreview() self.update_preview()
self.selected_row = row self.selected_row = row
self.preview_widget.change_slide(row) self.preview_widget.change_slide(row)
Registry().execute(u'slidecontroller_%s_changed' % self.type_prefix, row) Registry().execute(u'slidecontroller_%s_changed' % self.type_prefix, row)
@ -986,14 +985,14 @@ class SlideController(DisplayController):
The slide has been changed. Update the slidecontroller accordingly The slide has been changed. Update the slidecontroller accordingly
""" """
self.preview_widget.change_slide(row) self.preview_widget.change_slide(row)
self.updatePreview() self.update_preview()
Registry().execute(u'slidecontroller_%s_changed' % self.type_prefix, row) Registry().execute(u'slidecontroller_%s_changed' % self.type_prefix, row)
def updatePreview(self): def update_preview(self):
""" """
This updates the preview frame, for example after changing a slide or using *Blank to Theme*. This updates the preview frame, for example after changing a slide or using *Blank to Theme*.
""" """
log.debug(u'updatePreview %s ' % self.screens.current[u'primary']) log.debug(u'update_preview %s ' % self.screens.current[u'primary'])
if not self.screens.current[u'primary'] and self.service_item and \ if not self.screens.current[u'primary'] and self.service_item and \
self.service_item.is_capable(ItemCapabilities.ProvidesOwnDisplay): self.service_item.is_capable(ItemCapabilities.ProvidesOwnDisplay):
# Grab now, but try again in a couple of seconds if slide change is slow # Grab now, but try again in a couple of seconds if slide change is slow
@ -1029,7 +1028,7 @@ class SlideController(DisplayController):
return return
Registry().execute(u'%s_next' % self.service_item.name.lower(), [self.service_item, self.is_live]) Registry().execute(u'%s_next' % self.service_item.name.lower(), [self.service_item, self.is_live])
if self.service_item.is_command() and self.is_live: if self.service_item.is_command() and self.is_live:
self.updatePreview() self.update_preview()
else: else:
row = self.preview_widget.current_slide_number() + 1 row = self.preview_widget.current_slide_number() + 1
if row == self.preview_widget.slide_count(): if row == self.preview_widget.slide_count():
@ -1037,7 +1036,7 @@ class SlideController(DisplayController):
if self.slide_limits == SlideLimits.Wrap: if self.slide_limits == SlideLimits.Wrap:
row = 0 row = 0
elif self.is_live and self.slide_limits == SlideLimits.Next: elif self.is_live and self.slide_limits == SlideLimits.Next:
self.serviceNext() self.service_next()
return return
else: else:
row = self.preview_widget.slide_count() - 1 row = self.preview_widget.slide_count() - 1
@ -1046,7 +1045,7 @@ class SlideController(DisplayController):
else: else:
row = self.preview_widget.slide_count() - 1 row = self.preview_widget.slide_count() - 1
self.preview_widget.change_slide(row) self.preview_widget.change_slide(row)
self.slideSelected() self.slide_selected()
def on_slide_selected_previous(self): def on_slide_selected_previous(self):
""" """
@ -1056,7 +1055,7 @@ class SlideController(DisplayController):
return return
Registry().execute(u'%s_previous' % self.service_item.name.lower(), [self.service_item, self.is_live]) Registry().execute(u'%s_previous' % self.service_item.name.lower(), [self.service_item, self.is_live])
if self.service_item.is_command() and self.is_live: if self.service_item.is_command() and self.is_live:
self.updatePreview() self.update_preview()
else: else:
row = self.preview_widget.current_slide_number() - 1 row = self.preview_widget.current_slide_number() - 1
if row == -1: if row == -1:
@ -1069,19 +1068,19 @@ class SlideController(DisplayController):
else: else:
row = 0 row = 0
self.preview_widget.change_slide(row) self.preview_widget.change_slide(row)
self.slideSelected() self.slide_selected()
def onToggleLoop(self): def on_toggle_loop(self):
""" """
Toggles the loop state. Toggles the loop state.
""" """
hide_mode = self.hide_mode() hide_mode = self.hide_mode()
if hide_mode is None and (self.play_slides_loop.isChecked() or self.play_slides_once.isChecked()): if hide_mode is None and (self.play_slides_loop.isChecked() or self.play_slides_once.isChecked()):
self.onStartLoop() self.on_start_loop()
else: else:
self.on_stop_loop() self.on_stop_loop()
def onStartLoop(self): def on_start_loop(self):
""" """
Start the timer loop running and store the timer id Start the timer loop running and store the timer id
""" """
@ -1096,7 +1095,7 @@ class SlideController(DisplayController):
self.killTimer(self.timer_id) self.killTimer(self.timer_id)
self.timer_id = 0 self.timer_id = 0
def onPlaySlidesLoop(self, checked=None): def on_play_slides_loop(self, checked=None):
""" """
Start or stop 'Play Slides in Loop' Start or stop 'Play Slides in Loop'
""" """
@ -1104,7 +1103,7 @@ class SlideController(DisplayController):
checked = self.play_slides_loop.isChecked() checked = self.play_slides_loop.isChecked()
else: else:
self.play_slides_loop.setChecked(checked) self.play_slides_loop.setChecked(checked)
log.debug(u'onPlaySlidesLoop %s' % checked) log.debug(u'on_play_slides_loop %s' % checked)
if checked: if checked:
self.play_slides_loop.setIcon(build_icon(u':/media/media_stop.png')) self.play_slides_loop.setIcon(build_icon(u':/media/media_stop.png'))
self.play_slides_loop.setText(UiStrings().StopPlaySlidesInLoop) self.play_slides_loop.setText(UiStrings().StopPlaySlidesInLoop)
@ -1115,9 +1114,9 @@ class SlideController(DisplayController):
else: else:
self.play_slides_loop.setIcon(build_icon(u':/media/media_time.png')) self.play_slides_loop.setIcon(build_icon(u':/media/media_time.png'))
self.play_slides_loop.setText(UiStrings().PlaySlidesInLoop) self.play_slides_loop.setText(UiStrings().PlaySlidesInLoop)
self.onToggleLoop() self.on_toggle_loop()
def onPlaySlidesOnce(self, checked=None): def on_play_slides_once(self, checked=None):
""" """
Start or stop 'Play Slides to End' Start or stop 'Play Slides to End'
""" """
@ -1125,7 +1124,7 @@ class SlideController(DisplayController):
checked = self.play_slides_once.isChecked() checked = self.play_slides_once.isChecked()
else: else:
self.play_slides_once.setChecked(checked) self.play_slides_once.setChecked(checked)
log.debug(u'onPlaySlidesOnce %s' % checked) log.debug(u'on_play_slides_once %s' % checked)
if checked: if checked:
self.play_slides_once.setIcon(build_icon(u':/media/media_stop.png')) self.play_slides_once.setIcon(build_icon(u':/media/media_stop.png'))
self.play_slides_once.setText(UiStrings().StopPlaySlidesToEnd) self.play_slides_once.setText(UiStrings().StopPlaySlidesToEnd)
@ -1136,15 +1135,15 @@ class SlideController(DisplayController):
else: else:
self.play_slides_once.setIcon(build_icon(u':/media/media_time')) self.play_slides_once.setIcon(build_icon(u':/media/media_time'))
self.play_slides_once.setText(UiStrings().PlaySlidesToEnd) self.play_slides_once.setText(UiStrings().PlaySlidesToEnd)
self.onToggleLoop() self.on_toggle_loop()
def setAudioItemsVisibility(self, visible): def set_audio_items_visibility(self, visible):
""" """
Set the visibility of the audio stuff Set the visibility of the audio stuff
""" """
self.toolbar.set_widget_visible(self.audio_list, visible) self.toolbar.set_widget_visible(self.audio_list, visible)
def onAudioPauseClicked(self, checked): def set_audio_pause_clicked(self, checked):
""" """
Pause the audio player Pause the audio player
""" """
@ -1162,7 +1161,7 @@ class SlideController(DisplayController):
if event.timerId() == self.timer_id: if event.timerId() == self.timer_id:
self.on_slide_selected_next(self.play_slides_loop.isChecked()) self.on_slide_selected_next(self.play_slides_loop.isChecked())
def onEditSong(self): def on_edit_song(self):
""" """
From the preview display requires the service Item to be editied From the preview display requires the service Item to be editied
""" """
@ -1171,14 +1170,14 @@ class SlideController(DisplayController):
if new_item: if new_item:
self.add_service_item(new_item) self.add_service_item(new_item)
def onPreviewAddToService(self): def on_preview_add_to_service(self):
""" """
From the preview display request the Item to be added to service From the preview display request the Item to be added to service
""" """
if self.service_item: if self.service_item:
self.service_manager.add_service_item(self.service_item) self.service_manager.add_service_item(self.service_item)
def onGoLiveClick(self): def on_go_live_click(self):
""" """
triggered by clicking the Preview slide items triggered by clicking the Preview slide items
""" """
@ -1188,10 +1187,10 @@ class SlideController(DisplayController):
if self.service_item.is_command(): if self.service_item.is_command():
Registry().execute(u'%s_stop' % self.service_item.name.lower(), [self.service_item, self.is_live]) Registry().execute(u'%s_stop' % self.service_item.name.lower(), [self.service_item, self.is_live])
if self.service_item.is_media(): if self.service_item.is_media():
self.onMediaClose() self.on_media_close()
self.onGoLive() self.on_go_live()
def onGoLive(self): def on_go_live(self):
""" """
If preview copy slide item to live controller from Preview Controller If preview copy slide item to live controller from Preview Controller
""" """
@ -1200,41 +1199,41 @@ class SlideController(DisplayController):
if self.service_item.from_service: if self.service_item.from_service:
self.service_manager.preview_live(self.service_item.unique_identifier, row) self.service_manager.preview_live(self.service_item.unique_identifier, row)
else: else:
self.live_controller.addServiceManagerItem(self.service_item, row) self.live_controller.add_service_manager_item(self.service_item, row)
def onMediaStart(self, item): def on_media_start(self, item):
""" """
Respond to the arrival of a media service item Respond to the arrival of a media service item
""" """
log.debug(u'SlideController onMediaStart') log.debug(u'SlideController on_media_start')
self.media_controller.video(self.controller_type, item, self.hide_mode()) self.media_controller.video(self.controller_type, item, self.hide_mode())
if not self.is_live: if not self.is_live:
self.preview_display.show() self.preview_display.show()
self.slide_preview.hide() self.slide_preview.hide()
def onMediaClose(self): def on_media_close(self):
""" """
Respond to a request to close the Video Respond to a request to close the Video
""" """
log.debug(u'SlideController onMediaClose') log.debug(u'SlideController on_media_close')
self.media_controller.media_reset(self) self.media_controller.media_reset(self)
self.preview_display.hide() self.preview_display.hide()
self.slide_preview.show() self.slide_preview.show()
def _resetBlank(self): def _reset_blank(self):
""" """
Used by command items which provide their own displays to reset the Used by command items which provide their own displays to reset the
screen hide attributes screen hide attributes
""" """
hide_mode = self.hide_mode() hide_mode = self.hide_mode()
if hide_mode == HideMode.Blank: if hide_mode == HideMode.Blank:
self.onBlankDisplay(True) self.on_blank_display(True)
elif hide_mode == HideMode.Theme: elif hide_mode == HideMode.Theme:
self.onThemeDisplay(True) self.on_theme_display(True)
elif hide_mode == HideMode.Screen: elif hide_mode == HideMode.Screen:
self.onHideDisplay(True) self.on_hide_display(True)
else: else:
self.hidePlugin(False) self.hide_plugin(False)
def hide_mode(self): def hide_mode(self):
""" """
@ -1251,7 +1250,7 @@ class SlideController(DisplayController):
else: else:
return None return None
def onNextTrackClicked(self): def on_next_track_clicked(self):
""" """
Go to the next track when next is clicked Go to the next track when next is clicked
""" """
@ -1266,7 +1265,7 @@ class SlideController(DisplayController):
seconds %= 60 seconds %= 60
self.audio_time_label.setText(u' %02d:%02d ' % (minutes, seconds)) self.audio_time_label.setText(u' %02d:%02d ' % (minutes, seconds))
def onTrackTriggered(self): def on_track_triggered(self):
""" """
Start playing a track Start playing a track
""" """

View File

@ -836,10 +836,14 @@ class ThemeManager(QtGui.QWidget):
def _get_application(self): def _get_application(self):
""" """
Adds the openlp to the class dynamically Adds the openlp to the class dynamically.
Windows needs to access the application in a dynamic manner.
""" """
if not hasattr(self, u'_application'): if os.name == u'nt':
self._application = Registry().get(u'application') return Registry().get(u'application')
return self._application else:
if not hasattr(self, u'_application'):
self._application = Registry().get(u'application')
return self._application
application = property(_get_application) application = property(_get_application)

View File

@ -178,8 +178,8 @@ class Ui_ThemeWizard(object):
self.lineSpacingLabel = QtGui.QLabel(self.mainAreaPage) self.lineSpacingLabel = QtGui.QLabel(self.mainAreaPage)
self.lineSpacingLabel.setObjectName(u'LineSpacingLabel') self.lineSpacingLabel.setObjectName(u'LineSpacingLabel')
self.lineSpacingSpinBox = QtGui.QSpinBox(self.mainAreaPage) self.lineSpacingSpinBox = QtGui.QSpinBox(self.mainAreaPage)
self.lineSpacingSpinBox.setMinimum(-50) self.lineSpacingSpinBox.setMinimum(-250)
self.lineSpacingSpinBox.setMaximum(50) self.lineSpacingSpinBox.setMaximum(250)
self.lineSpacingSpinBox.setObjectName(u'LineSpacingSpinBox') self.lineSpacingSpinBox.setObjectName(u'LineSpacingSpinBox')
self.mainAreaLayout.addRow(self.lineSpacingLabel, self.lineSpacingSpinBox) self.mainAreaLayout.addRow(self.lineSpacingLabel, self.lineSpacingSpinBox)
self.outlineCheckBox = QtGui.QCheckBox(self.mainAreaPage) self.outlineCheckBox = QtGui.QCheckBox(self.mainAreaPage)

View File

@ -320,10 +320,14 @@ class OpenLPWizard(QtGui.QWizard):
def _get_application(self): def _get_application(self):
""" """
Adds the openlp to the class dynamically Adds the openlp to the class dynamically.
Windows needs to access the application in a dynamic manner.
""" """
if not hasattr(self, u'_application'): if os.name == u'nt':
self._application = Registry().get(u'application') return Registry().get(u'application')
return self._application else:
if not hasattr(self, u'_application'):
self._application = Registry().get(u'application')
return self._application
application = property(_get_application) application = property(_get_application)

View File

@ -346,9 +346,9 @@ def get_uno_instance(resolver):
""" """
log.debug(u'get UNO Desktop Openoffice - resolve') log.debug(u'get UNO Desktop Openoffice - resolve')
if UNO_CONNECTION_TYPE == u'pipe': if UNO_CONNECTION_TYPE == u'pipe':
return resolver.resolve(u'uno:pipe,name=openlp_pipe; urp;StarOffice.ComponentContext') return resolver.resolve(u'uno:pipe,name=openlp_pipe;urp;StarOffice.ComponentContext')
else: else:
return resolver.resolve(u'uno:socket,host=localhost,port=2002; urp;StarOffice.ComponentContext') return resolver.resolve(u'uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext')
def format_time(text, local_time): def format_time(text, local_time):

View File

@ -28,6 +28,7 @@
############################################################################### ###############################################################################
import logging import logging
import os
import re import re
from PyQt4 import QtGui from PyQt4 import QtGui
@ -191,10 +192,14 @@ class EditBibleForm(QtGui.QDialog, Ui_EditBibleDialog):
def _get_application(self): def _get_application(self):
""" """
Adds the openlp to the class dynamically Adds the openlp to the class dynamically.
Windows needs to access the application in a dynamic manner.
""" """
if not hasattr(self, u'_application'): if os.name == u'nt':
self._application = Registry().get(u'application') return Registry().get(u'application')
return self._application else:
if not hasattr(self, u'_application'):
self._application = Registry().get(u'application')
return self._application
application = property(_get_application) application = property(_get_application)

View File

@ -544,11 +544,15 @@ class BibleDB(QtCore.QObject, Manager):
def _get_application(self): def _get_application(self):
""" """
Adds the openlp to the class dynamically Adds the openlp to the class dynamically.
Windows needs to access the application in a dynamic manner.
""" """
if not hasattr(self, u'_application'): if os.name == u'nt':
self._application = Registry().get(u'application') return Registry().get(u'application')
return self._application else:
if not hasattr(self, u'_application'):
self._application = Registry().get(u'application')
return self._application
application = property(_get_application) application = property(_get_application)

View File

@ -29,6 +29,7 @@
""" """
The :mod:`http` module enables OpenLP to retrieve scripture from bible websites. The :mod:`http` module enables OpenLP to retrieve scripture from bible websites.
""" """
import os
import logging import logging
import re import re
import socket import socket
@ -301,11 +302,15 @@ class BGExtract(object):
def _get_application(self): def _get_application(self):
""" """
Adds the openlp to the class dynamically Adds the openlp to the class dynamically.
Windows needs to access the application in a dynamic manner.
""" """
if not hasattr(self, u'_application'): if os.name == u'nt':
self._application = Registry().get(u'application') return Registry().get(u'application')
return self._application else:
if not hasattr(self, u'_application'):
self._application = Registry().get(u'application')
return self._application
application = property(_get_application) application = property(_get_application)
@ -362,8 +367,8 @@ class BSExtract(object):
The version of the Bible like NIV for New International Version The version of the Bible like NIV for New International Version
""" """
log.debug(u'BSExtract.get_books_from_http("%s")', version) log.debug(u'BSExtract.get_books_from_http("%s")', version)
urlversion = urllib.quote(version.encode("utf-8")) url_version = urllib.quote(version.encode("utf-8"))
chapter_url = u'http://m.bibleserver.com/overlay/selectBook?translation=%s' % (urlversion) chapter_url = u'http://m.bibleserver.com/overlay/selectBook?translation=%s' % (url_version)
soup = get_soup_for_bible_ref(chapter_url) soup = get_soup_for_bible_ref(chapter_url)
if not soup: if not soup:
return None return None
@ -377,11 +382,15 @@ class BSExtract(object):
def _get_application(self): def _get_application(self):
""" """
Adds the openlp to the class dynamically Adds the openlp to the class dynamically.
Windows needs to access the application in a dynamic manner.
""" """
if not hasattr(self, u'_application'): if os.name == u'nt':
self._application = Registry().get(u'application') return Registry().get(u'application')
return self._application else:
if not hasattr(self, u'_application'):
self._application = Registry().get(u'application')
return self._application
application = property(_get_application) application = property(_get_application)
@ -477,11 +486,15 @@ class CWExtract(object):
def _get_application(self): def _get_application(self):
""" """
Adds the openlp to the class dynamically Adds the openlp to the class dynamically.
Windows needs to access the application in a dynamic manner.
""" """
if not hasattr(self, u'_application'): if os.name == u'nt':
self._application = Registry().get(u'application') return Registry().get(u'application')
return self._application else:
if not hasattr(self, u'_application'):
self._application = Registry().get(u'application')
return self._application
application = property(_get_application) application = property(_get_application)
@ -598,9 +611,8 @@ class HTTPBible(BibleDB):
if show_error: if show_error:
critical_error_message_box( critical_error_message_box(
translate('BiblesPlugin', 'No Book Found'), translate('BiblesPlugin', 'No Book Found'),
translate('BiblesPlugin', 'No matching ' translate('BiblesPlugin', 'No matching book could be found in this Bible. Check that you have '
'book could be found in this Bible. Check that you ' 'spelled the name of the book correctly.'))
'have spelled the name of the book correctly.'))
return [] return []
book = db_book.name book = db_book.name
if BibleDB.get_verse_count(self, book_id, reference[1]) == 0: if BibleDB.get_verse_count(self, book_id, reference[1]) == 0:
@ -667,14 +679,19 @@ class HTTPBible(BibleDB):
def _get_application(self): def _get_application(self):
""" """
Adds the openlp to the class dynamically Adds the openlp to the class dynamically.
Windows needs to access the application in a dynamic manner.
""" """
if not hasattr(self, u'_application'): if os.name == u'nt':
self._application = Registry().get(u'application') return Registry().get(u'application')
return self._application else:
if not hasattr(self, u'_application'):
self._application = Registry().get(u'application')
return self._application
application = property(_get_application) application = property(_get_application)
def get_soup_for_bible_ref(reference_url, header=None, pre_parse_regex=None, pre_parse_substitute=None): def get_soup_for_bible_ref(reference_url, header=None, pre_parse_regex=None, pre_parse_substitute=None):
""" """
Gets a webpage and returns a parsed and optionally cleaned soup or None. Gets a webpage and returns a parsed and optionally cleaned soup or None.
@ -724,13 +741,10 @@ def send_error_message(error_type):
if error_type == u'download': if error_type == u'download':
critical_error_message_box( critical_error_message_box(
translate('BiblesPlugin.HTTPBible', 'Download Error'), translate('BiblesPlugin.HTTPBible', 'Download Error'),
translate('BiblesPlugin.HTTPBible', 'There was a ' translate('BiblesPlugin.HTTPBible', 'There was a problem downloading your verse selection. Please check '
'problem downloading your verse selection. Please check your ' 'your Internet connection, and if this error continues to occur please consider reporting a bug.'))
'Internet connection, and if this error continues to occur '
'please consider reporting a bug.'))
elif error_type == u'parse': elif error_type == u'parse':
critical_error_message_box( critical_error_message_box(
translate('BiblesPlugin.HTTPBible', 'Parse Error'), translate('BiblesPlugin.HTTPBible', 'Parse Error'),
translate('BiblesPlugin.HTTPBible', 'There was a ' translate('BiblesPlugin.HTTPBible', 'There was a problem extracting your verse selection. If this error '
'problem extracting your verse selection. If this error continues ' 'continues to occur please consider reporting a bug.'))
'to occur please consider reporting a bug.'))

View File

@ -100,8 +100,7 @@ class EditCustomForm(QtGui.QDialog, Ui_CustomEditDialog):
self.credit_edit.setText(self.custom_slide.credits) self.credit_edit.setText(self.custom_slide.credits)
custom_XML = CustomXMLParser(self.custom_slide.text) custom_XML = CustomXMLParser(self.custom_slide.text)
slide_list = custom_XML.get_verses() slide_list = custom_XML.get_verses()
for slide in slide_list: self.slide_list_view.addItems([slide[1] for slide in slide_list])
self.slide_list_view.addItem(slide[1])
theme = self.custom_slide.theme_name theme = self.custom_slide.theme_name
find_and_set_in_combo_box(self.theme_combo_box, theme) find_and_set_in_combo_box(self.theme_combo_box, theme)
self.title_edit.setFocus() self.title_edit.setFocus()

View File

@ -41,14 +41,19 @@ class CustomSlide(BaseModel):
""" """
CustomSlide model CustomSlide model
""" """
# By default sort the customs by its title considering language specific # By default sort the customs by its title considering language specific characters.
# characters.
def __lt__(self, other): def __lt__(self, other):
return get_locale_key(self.title) < get_locale_key(other.title) return get_locale_key(self.title) < get_locale_key(other.title)
def __eq__(self, other): def __eq__(self, other):
return get_locale_key(self.title) == get_locale_key(other.title) return get_locale_key(self.title) == get_locale_key(other.title)
def __hash__(self):
"""
Return the hash for a custom slide.
"""
return self.id
def init_schema(url): def init_schema(url):
""" """

View File

@ -473,7 +473,7 @@ class ImageMediaItem(MediaManagerItem):
This boolean is set to True when the list in the interface should be reloaded after saving the new images This boolean is set to True when the list in the interface should be reloaded after saving the new images
""" """
for filename in images_list: for filename in images_list:
if type(filename) is not str and type(filename) is not unicode: if not isinstance(filename, basestring):
continue continue
log.debug(u'Adding new image: %s', filename) log.debug(u'Adding new image: %s', filename)
imageFile = ImageFilenames() imageFile = ImageFilenames()

View File

@ -80,15 +80,15 @@ class PresentationMediaItem(MediaManagerItem):
""" """
Build the list of file extensions to be used in the Open file dialog. Build the list of file extensions to be used in the Open file dialog.
""" """
file_type = u'' file_type_list = u''
for controller in self.controllers: for controller in self.controllers:
if self.controllers[controller].enabled(): if self.controllers[controller].enabled():
file_types = self.controllers[controller].supports + self.controllers[controller].also_supports file_types = self.controllers[controller].supports + self.controllers[controller].also_supports
for file_type in file_types: for file_type in file_types:
if file_type.find(file_type) == -1: if file_type.find(file_type) == -1:
file_type += u'*.%s ' % file_type file_type_list += u'*.%s ' % file_type
self.service_manager.supported_suffixes(file_type) self.service_manager.supported_suffixes(file_type)
self.on_new_file_masks = translate('PresentationPlugin.MediaItem', 'Presentations (%s)') % file_type self.on_new_file_masks = translate('PresentationPlugin.MediaItem', 'Presentations (%s)') % file_type_list
def required_icons(self): def required_icons(self):
""" """

View File

@ -174,13 +174,13 @@ class PPTViewer(QtGui.QWidget):
int(self.widthEdit.text()), int(self.heightEdit.text())) int(self.widthEdit.text()), int(self.heightEdit.text()))
filename = str(self.pptEdit.text().replace(u'/', u'\\')) filename = str(self.pptEdit.text().replace(u'/', u'\\'))
folder = str(self.folderEdit.text().replace(u'/', u'\\')) folder = str(self.folderEdit.text().replace(u'/', u'\\'))
print filename, folder print(filename, folder)
self.pptid = self.pptdll.OpenPPT(filename, None, rect, folder) self.pptid = self.pptdll.OpenPPT(filename, None, rect, folder)
print u'id: ' + unicode(self.pptid) print(u'id: ' + unicode(self.pptid))
if oldid >= 0: if oldid >= 0:
self.pptdll.ClosePPT(oldid); self.pptdll.ClosePPT(oldid);
slides = self.pptdll.GetSlideCount(self.pptid) slides = self.pptdll.GetSlideCount(self.pptid)
print u'slidecount: ' + unicode(slides) print(u'slidecount: ' + unicode(slides))
self.total.setNum(self.pptdll.GetSlideCount(self.pptid)) self.total.setNum(self.pptdll.GetSlideCount(self.pptid))
self.updateCurrSlide() self.updateCurrSlide()
@ -188,14 +188,14 @@ class PPTViewer(QtGui.QWidget):
if self.pptid < 0: if self.pptid < 0:
return return
slide = unicode(self.pptdll.GetCurrentSlide(self.pptid)) slide = unicode(self.pptdll.GetCurrentSlide(self.pptid))
print u'currslide: ' + slide print(u'currslide: ' + slide)
self.slideEdit.setText(slide) self.slideEdit.setText(slide)
app.processEvents() app.processEvents()
def gotoClick(self): def gotoClick(self):
if self.pptid < 0: if self.pptid < 0:
return return
print self.slideEdit.text() print(self.slideEdit.text())
self.pptdll.GotoSlide(self.pptid, int(self.slideEdit.text())) self.pptdll.GotoSlide(self.pptid, int(self.slideEdit.text()))
self.updateCurrSlide() self.updateCurrSlide()
app.processEvents() app.processEvents()
@ -207,7 +207,7 @@ class PPTViewer(QtGui.QWidget):
if __name__ == '__main__': if __name__ == '__main__':
pptdll = cdll.LoadLibrary(r'pptviewlib.dll') pptdll = cdll.LoadLibrary(r'pptviewlib.dll')
pptdll.SetDebug(1) pptdll.SetDebug(1)
print u'Begin...' print(u'Begin...')
app = QtGui.QApplication(sys.argv) app = QtGui.QApplication(sys.argv)
window = PPTViewer() window = PPTViewer()
window.pptdll = pptdll window.pptdll = pptdll

View File

@ -349,10 +349,14 @@ class DuplicateSongRemovalForm(OpenLPWizard):
def _get_application(self): def _get_application(self):
""" """
Adds the openlp to the class dynamically Adds the openlp to the class dynamically.
Windows needs to access the application in a dynamic manner.
""" """
if not hasattr(self, u'_application'): if os.name == u'nt':
self._application = Registry().get(u'application') return Registry().get(u'application')
return self._application else:
if not hasattr(self, u'_application'):
self._application = Registry().get(u'application')
return self._application
application = property(_get_application) application = property(_get_application)

View File

@ -275,7 +275,6 @@ class Ui_EditSongDialog(object):
self.bottom_layout.setObjectName(u'bottom_layout') self.bottom_layout.setObjectName(u'bottom_layout')
self.warning_label = QtGui.QLabel(edit_song_dialog) self.warning_label = QtGui.QLabel(edit_song_dialog)
self.warning_label.setObjectName(u'warning_label') self.warning_label.setObjectName(u'warning_label')
self.warning_label.setVisible(False)
self.bottom_layout.addWidget(self.warning_label) self.bottom_layout.addWidget(self.warning_label)
self.button_box = create_button_box(edit_song_dialog, u'button_box', [u'cancel', u'save']) self.button_box = create_button_box(edit_song_dialog, u'button_box', [u'cancel', u'save'])
self.bottom_layout.addWidget(self.button_box) self.bottom_layout.addWidget(self.button_box)
@ -323,8 +322,10 @@ class Ui_EditSongDialog(object):
self.from_media_button.setText(translate('SongsPlugin.EditSongForm', 'Add &Media')) self.from_media_button.setText(translate('SongsPlugin.EditSongForm', 'Add &Media'))
self.audio_remove_button.setText(translate('SongsPlugin.EditSongForm', '&Remove')) self.audio_remove_button.setText(translate('SongsPlugin.EditSongForm', '&Remove'))
self.audio_remove_all_button.setText(translate('SongsPlugin.EditSongForm', 'Remove &All')) self.audio_remove_all_button.setText(translate('SongsPlugin.EditSongForm', 'Remove &All'))
self.warning_label.setText( self.not_all_verses_used_warning = \
translate('SongsPlugin.EditSongForm', '<strong>Warning:</strong> Not all of the verses are in use.')) translate('SongsPlugin.EditSongForm', '<strong>Warning:</strong> Not all of the verses are in use.')
self.no_verse_order_entered_warning = \
translate('SongsPlugin.EditSongForm', '<strong>Warning:</strong> You have not entered a verse order.')
def create_combo_box(parent, name): def create_combo_box(parent, name):

View File

@ -456,6 +456,8 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
self.title_edit.setFocus() self.title_edit.setFocus()
# Hide or show the preview button. # Hide or show the preview button.
self.preview_button.setVisible(preview) self.preview_button.setVisible(preview)
# Check if all verse tags are used.
self.on_verse_order_text_changed(self.verse_order_edit.text())
def tag_rows(self): def tag_rows(self):
""" """
@ -683,21 +685,33 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
self.verse_edit_button.setEnabled(False) self.verse_edit_button.setEnabled(False)
self.verse_delete_button.setEnabled(False) self.verse_delete_button.setEnabled(False)
def on_verse_order_text_changed(self, text): def on_verse_order_text_changed(self, text):
verses = [] """
verse_names = [] Checks if the verse order is complete or missing. Shows a error message according to the state of the verse
order = self._extract_verse_order(text) order.
``text``
The text of the verse order edit (ignored).
"""
# Extract all verses which were used in the order.
verses_in_order = self._extract_verse_order(self.verse_order_edit.text())
# Find the verses which were not used in the order.
verses_not_used = []
for index in range(self.verse_list_widget.rowCount()): for index in range(self.verse_list_widget.rowCount()):
verse = self.verse_list_widget.item(index, 0) verse = self.verse_list_widget.item(index, 0)
verse = verse.data(QtCore.Qt.UserRole) verse = verse.data(QtCore.Qt.UserRole)
if verse not in verse_names: if verse not in verses_in_order:
verses.append(verse)
verse_names.append(u'%s%s' % (VerseType.translated_tag(verse[0]), verse[1:]))
verses_not_used = []
for verse in verses:
if not verse in order:
verses_not_used.append(verse) verses_not_used.append(verse)
self.warning_label.setVisible(len(verses_not_used) > 0) # Set the label text.
label_text = u''
# No verse order was entered.
if not verses_in_order:
label_text = self.no_verse_order_entered_warning
# The verse order does not contain all verses.
elif verses_not_used:
label_text = self.not_all_verses_used_warning
self.warning_label.setText(label_text)
def on_copyright_insert_button_triggered(self): def on_copyright_insert_button_triggered(self):
text = self.copyright_edit.text() text = self.copyright_edit.text()

View File

@ -27,6 +27,7 @@
# Temple Place, Suite 330, Boston, MA 02111-1307 USA # # Temple Place, Suite 330, Boston, MA 02111-1307 USA #
############################################################################### ###############################################################################
import logging import logging
import os
from PyQt4 import QtGui, QtCore from PyQt4 import QtGui, QtCore
from sqlalchemy.sql import and_ from sqlalchemy.sql import and_
@ -525,10 +526,14 @@ class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog):
def _get_application(self): def _get_application(self):
""" """
Adds the application to the class dynamically Adds the openlp to the class dynamically.
Windows needs to access the application in a dynamic manner.
""" """
if not hasattr(self, u'_application'): if os.name == u'nt':
self._application = Registry().get(u'application') return Registry().get(u'application')
return self._application else:
if not hasattr(self, u'_application'):
self._application = Registry().get(u'application')
return self._application
application = property(_get_application) application = property(_get_application)

View File

@ -84,10 +84,14 @@ class OpenLyricsExport(object):
def _get_application(self): def _get_application(self):
""" """
Adds the openlp to the class dynamically Adds the openlp to the class dynamically.
Windows needs to access the application in a dynamic manner.
""" """
if not hasattr(self, u'_application'): if os.name == u'nt':
self._application = Registry().get(u'application') return Registry().get(u'application')
return self._application else:
if not hasattr(self, u'_application'):
self._application = Registry().get(u'application')
return self._application
application = property(_get_application) application = property(_get_application)

View File

@ -1,131 +0,0 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2013 Raoul Snyman #
# Portions copyright (c) 2008-2013 Tim Bentley, Gerald Britton, Jonathan #
# Corwin, Samuel Findlay, Michael Gorven, Scott Guerrieri, Matthias Hub, #
# Meinert Jordan, Armin Köhler, Erik Lundin, Edwin Lunando, Brian T. Meyer. #
# Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias Põldaru, #
# Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith, #
# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Dave Warnock, #
# Frode Woldsund, Martin Zibricky, Patrick Zimmermann #
# --------------------------------------------------------------------------- #
# 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 #
###############################################################################
from openlp.plugins.songs.lib.opensongimport import OpenSongImport
from openlp.core.lib.db import Manager
from openlp.plugins.songs.lib.db import init_schema
import logging
LOG_FILENAME = 'test.log'
logging.basicConfig(filename=LOG_FILENAME,level=logging.INFO)
# Stubs to replace the UI functions for raw testing
class wizard_stub:
def __init__(self):
self.progressBar=progbar_stub()
def incrementProgressBar(self, str):
pass
class progbar_stub:
def __init__(self):
pass
def setMaximum(self, arg):
pass
def test():
manager = Manager(u'songs', init_schema)
o = OpenSongImport(manager, filenames=[u'test.opensong'])
o.import_wizard = wizard_stub()
o.commit = False
o.do_import()
o.print_song()
assert o.copyright == u'2010 Martin Thompson'
assert o.authors == [u'MartiÑ Thómpson', u'Martin2 Thómpson']
assert o.title == u'Martins Test'
assert o.alternate_title == u''
assert o.song_number == u'1'
assert [u'C1', u'Chorus 1'] in o.verses
assert [u'C2', u'Chorus 2'] in o.verses
assert not [u'C3', u'Chorus 3'] in o.verses
assert [u'B1', u'Bridge 1\nBridge 1 line 2'] in o.verses
assert [u'V1', u'v1 Line 1\nV1 Line 2'] in o.verses
assert [u'V2', u'v2 Line 1\nV2 Line 2'] in o.verses
assert [u'V3A', u'V3 Line 1\nV3 Line 2'] in o.verses
assert [u'RAP1', u'Rap 1 Line 1\nRap 1 Line 2'] in o.verses
assert [u'RAP2', u'Rap 2 Line 1\nRap 2 Line 2'] in o.verses
assert [u'RAP3', u'Rap 3 Line 1\nRap 3 Line 2'] in o.verses
assert [u'X1', u'Unreferenced verse line 1'] in o.verses
assert o.verse_order_list == [u'V1', u'C1', u'V2', u'C2', u'V3A', u'B1', u'V1', u'T1', u'RAP1', u'RAP2', u'RAP3']
assert o.ccli_number == u'Blah'
assert o.topics == [u'TestTheme', u'TestAltTheme']
o.filenames = [u'test.opensong.zip']
o.set_defaults()
o.do_import()
o.print_song()
assert o.copyright == u'2010 Martin Thompson'
assert o.authors == [u'MartiÑ Thómpson']
assert o.title == u'Martins Test'
assert o.alternate_title == u''
assert o.song_number == u'1'
assert [u'B1', u'Bridge 1\nBridge 1 line 2'] in o.verses
assert [u'C1', u'Chorus 1'] in o.verses
assert [u'C2', u'Chorus 2'] in o.verses
assert not [u'C3', u'Chorus 3'] in o.verses
assert [u'V1', u'v1 Line 1\nV1 Line 2'] in o.verses
assert [u'V2', u'v2 Line 1\nV2 Line 2'] in o.verses
print o.verse_order_list
assert o.verse_order_list == [u'V1', u'C1', u'V2', u'C2', u'V3', u'B1', u'V1']
o.filenames = [u'test2.opensong']
o.set_defaults()
o.do_import()
o.print_song()
assert o.copyright == u'2010 Martin Thompson'
assert o.authors == [u'Martin Thompson']
assert o.title == u'Martins 2nd Test'
assert o.alternate_title == u''
assert o.song_number == u'2'
print o.verses
assert [u'B1', u'Bridge 1\nBridge 1 line 2'] in o.verses
assert [u'C1', u'Chorus 1'] in o.verses
assert [u'C2', u'Chorus 2'] in o.verses
assert not [u'C3', u'Chorus 3'] in o.verses
assert [u'V1', u'v1 Line 1\nV1 Line 2'] in o.verses
assert [u'V2', u'v2 Line 1\nV2 Line 2'] in o.verses
print o.verse_order_list
assert o.verse_order_list == [u'V1', u'V2', u'B1', u'C1', u'C2']
o.filenames = [u'test3.opensong']
o.set_defaults()
o.do_import()
o.print_song()
assert o.copyright == u'2010'
assert o.authors == [u'Martin Thompson']
assert o.title == u'Test single verse'
assert o.alternate_title == u''
assert o.ccli_number == u'123456'
assert o.verse_order_list == [u'V1']
assert o.topics == [u'Worship: Declaration']
print o.verses[0]
assert [u'V1', u'Line 1\nLine 2'] in o.verses
print "Tests passed"
if __name__ == "__main__":
test()

View File

@ -85,6 +85,7 @@ MODULES = [
'migrate', 'migrate',
'uno', 'uno',
'icu', 'icu',
'bs4',
] ]
@ -98,9 +99,9 @@ OPTIONAL_MODULES = [
w = sys.stdout.write w = sys.stdout.write
def check_vers(version, required, text): def check_vers(version, required, text):
if type(version) is not str: if not isinstance(version, str):
version = '.'.join(map(str, version)) version = '.'.join(map(str, version))
if type(required) is not str: if not isinstance(required, str):
required = '.'.join(map(str, required)) required = '.'.join(map(str, required))
w(' %s >= %s ... ' % (text, required)) w(' %s >= %s ... ' % (text, required))
if LooseVersion(version) >= LooseVersion(required): if LooseVersion(version) >= LooseVersion(required):

View File

@ -33,11 +33,11 @@ class TestFormattingTags(TestCase):
""" """
with patch(u'openlp.core.lib.translate') as mocked_translate, \ with patch(u'openlp.core.lib.translate') as mocked_translate, \
patch(u'openlp.core.lib.settings') as mocked_settings, \ patch(u'openlp.core.lib.settings') as mocked_settings, \
patch(u'openlp.core.lib.formattingtags.cPickle') as mocked_cPickle: patch(u'openlp.core.lib.formattingtags.json') as mocked_json:
# GIVEN: Our mocked modules and functions. # GIVEN: Our mocked modules and functions.
mocked_translate.side_effect = lambda module, string_to_translate, comment: string_to_translate mocked_translate.side_effect = lambda module, string_to_translate, comment: string_to_translate
mocked_settings.value.return_value = u'' mocked_settings.value.return_value = u''
mocked_cPickle.load.return_value = [] mocked_json.load.return_value = []
# WHEN: Get the display tags. # WHEN: Get the display tags.
FormattingTags.load_tags() FormattingTags.load_tags()
@ -54,11 +54,11 @@ class TestFormattingTags(TestCase):
""" """
with patch(u'openlp.core.lib.translate') as mocked_translate, \ with patch(u'openlp.core.lib.translate') as mocked_translate, \
patch(u'openlp.core.lib.settings') as mocked_settings, \ patch(u'openlp.core.lib.settings') as mocked_settings, \
patch(u'openlp.core.lib.formattingtags.cPickle') as mocked_cPickle: patch(u'openlp.core.lib.formattingtags.json') as mocked_json:
# GIVEN: Our mocked modules and functions. # GIVEN: Our mocked modules and functions.
mocked_translate.side_effect = lambda module, string_to_translate: string_to_translate mocked_translate.side_effect = lambda module, string_to_translate: string_to_translate
mocked_settings.value.return_value = u'' mocked_settings.value.return_value = u''
mocked_cPickle.loads.side_effect = [[], [TAG]] mocked_json.loads.side_effect = [[], [TAG]]
# WHEN: Get the display tags. # WHEN: Get the display tags.
FormattingTags.load_tags() FormattingTags.load_tags()

View File

@ -272,13 +272,13 @@ class TestServiceItem(TestCase):
service_item.add_icon = MagicMock() service_item.add_icon = MagicMock()
# WHEN: adding an media from a saved Service and mocked exists # WHEN: adding an media from a saved Service and mocked exists
line = self.convert_file_service_item(u'migrate_video_20_22.osd') line = read_service_from_file(u'migrate_video_20_22.osd')
with patch('os.path.exists'): with patch('os.path.exists'):
service_item.set_from_service(line, TEST_PATH) service_item.set_from_service(line[0], TEST_RESOURCES_PATH)
# THEN: We should get back a converted service item # THEN: We should get back a converted service item
assert service_item.is_valid is True, u'The new service item should be valid' assert service_item.is_valid is True, u'The new service item should be valid'
assert service_item.processor is None, u'The Processor should have been set' assert service_item.processor == u'VLC', u'The Processor should have been set'
assert service_item.title is None, u'The title should be set to a value' assert service_item.title is not None, u'The title should be set to a value'
assert service_item.is_capable(ItemCapabilities.HasDetailedTitleDisplay) is False, \ assert service_item.is_capable(ItemCapabilities.HasDetailedTitleDisplay) is False, \
u'The Capability should have been removed' u'The Capability should have been removed'

View File

@ -0,0 +1 @@
__author__ = 'tim'

View File

@ -0,0 +1,73 @@
"""
Package to test the openlp.plugin.bible.lib.https package.
"""
from unittest import TestCase
from mock import MagicMock
from openlp.core.lib import Registry
from openlp.plugins.bibles.lib.http import BGExtract, CWExtract
class TestBibleHTTP(TestCase):
def setUp(self):
"""
Set up the Registry
"""
Registry.create()
Registry().register(u'service_list', MagicMock())
Registry().register(u'application', MagicMock())
def bible_gateway_extract_books_test(self):
"""
Test the Bible Gateway retrieval of book list for NIV bible
"""
# GIVEN: A new Bible Gateway extraction class
handler = BGExtract()
# WHEN: The Books list is called
books = handler.get_books_from_http(u'NIV')
# THEN: We should get back a valid service item
assert len(books) == 66, u'The bible should not have had any books added or removed'
def bible_gateway_extract_verse_test(self):
"""
Test the Bible Gateway retrieval of verse list for NIV bible John 3
"""
# GIVEN: A new Bible Gateway extraction class
handler = BGExtract()
# WHEN: The Books list is called
results = handler.get_bible_chapter(u'NIV', u'John', 3)
# THEN: We should get back a valid service item
assert len(results.verselist) == 36, u'The book of John should not have had any verses added or removed'
def crosswalk_extract_books_test(self):
"""
Test Crosswalk retrieval of book list for NIV bible
"""
# GIVEN: A new Bible Gateway extraction class
handler = CWExtract()
# WHEN: The Books list is called
books = handler.get_books_from_http(u'niv')
# THEN: We should get back a valid service item
assert len(books) == 66, u'The bible should not have had any books added or removed'
def crosswalk_extract_verse_test(self):
"""
Test Crosswalk retrieval of verse list for NIV bible John 3
"""
# GIVEN: A new Bible Gateway extraction class
handler = CWExtract()
# WHEN: The Books list is called
results = handler.get_bible_chapter(u'niv', u'john', 3)
# THEN: We should get back a valid service item
assert len(results.verselist) == 36, u'The book of John should not have had any verses added or removed'

View File

@ -45,3 +45,66 @@ class TestEditSongForm(TestCase):
def is_verse_edit_form_executed_test(self): def is_verse_edit_form_executed_test(self):
pass pass
def verse_order_no_warning_test(self):
"""
Test if the verse order warning is not shown
"""
# GIVEN: Mocked methods.
given_verse_order = u'V1 V2'
self.form.verse_list_widget.rowCount = MagicMock(return_value=2)
# Mock out the verse.
first_verse = MagicMock()
first_verse.data = MagicMock(return_value=u'V1')
second_verse = MagicMock()
second_verse.data = MagicMock(return_value= u'V2')
self.form.verse_list_widget.item = MagicMock(side_effect=[first_verse, second_verse])
self.form._extract_verse_order = MagicMock(return_value=given_verse_order.split())
# WHEN: Call the method.
self.form.on_verse_order_text_changed(given_verse_order)
# THEN: No text should be shown.
assert self.form.warning_label.text() == u'', u'There should be no warning.'
def verse_order_incomplete_warning_test(self):
"""
Test if the verse-order-incomple warning is shown
"""
# GIVEN: Mocked methods.
given_verse_order = u'V1'
self.form.verse_list_widget.rowCount = MagicMock(return_value=2)
# Mock out the verse.
first_verse = MagicMock()
first_verse.data = MagicMock(return_value=u'V1')
second_verse = MagicMock()
second_verse.data = MagicMock(return_value= u'V2')
self.form.verse_list_widget.item = MagicMock(side_effect=[first_verse, second_verse])
self.form._extract_verse_order = MagicMock(return_value=[given_verse_order])
# WHEN: Call the method.
self.form.on_verse_order_text_changed(given_verse_order)
# THEN: The verse-order-incomplete text should be shown.
assert self.form.warning_label.text() == self.form.not_all_verses_used_warning, \
u'The verse-order-incomplete warning should be shown.'
def bug_1170435_test(self):
"""
Regression test for bug 1170435 (test if "no verse order" message is shown)
"""
# GIVEN: Mocked methods.
given_verse_order = u''
self.form.verse_list_widget.rowCount = MagicMock(return_value=1)
# Mock out the verse. (We want a verse type to be returned).
mocked_verse = MagicMock()
mocked_verse.data = MagicMock(return_value=u'V1')
self.form.verse_list_widget.item = MagicMock(return_value=mocked_verse)
self.form._extract_verse_order = MagicMock(return_value=[])
self.form.verse_order_edit.text = MagicMock(return_value=given_verse_order)
# WHEN: Call the method.
self.form.on_verse_order_text_changed(given_verse_order)
# THEN: The no-verse-order message should be shown.
assert self.form.warning_label.text() == self.form.no_verse_order_entered_warning, \
u'The no-verse-order message should be shown.'