Merge master.

This commit is contained in:
Patrick Zimmermann 2013-01-18 22:45:36 +01:00
commit a8041466ad
19 changed files with 138 additions and 33 deletions

View File

@ -1 +1 @@
2.0
2.1.0-bzr2141

View File

@ -37,7 +37,9 @@ import logging
import os
import uuid
from openlp.core.lib import build_icon, clean_tags, expand_tags, translate, ImageSource
from PyQt4 import QtCore, QtGui
from openlp.core.lib import build_icon, clean_tags, expand_tags, translate, ImageSource, Settings
log = logging.getLogger(__name__)
@ -405,13 +407,15 @@ class ServiceItem(object):
for slide in serviceitem[u'serviceitem'][u'data']:
self._raw_frames.append(slide)
elif self.service_item_type == ServiceItemType.Image:
settingsSection = serviceitem[u'serviceitem'][u'header'][u'name']
background = QtGui.QColor(Settings().value(settingsSection + u'/background color', u'#000000'))
if path:
for text_image in serviceitem[u'serviceitem'][u'data']:
filename = os.path.join(path, text_image)
self.add_from_image(filename, text_image)
self.add_from_image(filename, text_image, background)
else:
for text_image in serviceitem[u'serviceitem'][u'data']:
self.add_from_image(text_image[u'path'], text_image[u'title'])
self.add_from_image(text_image[u'path'], text_image[u'title'], background)
elif self.service_item_type == ServiceItemType.Command:
for text_image in serviceitem[u'serviceitem'][u'data']:
if path:

View File

@ -26,5 +26,9 @@
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
"""
The :mod:`~openlp.core.theme` module contains all the themeing functions used by
OpenLP when displaying a song or a scripture.
"""
from openlp.core.theme.theme import Theme

View File

@ -26,3 +26,7 @@
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
"""
The :mod:`~openlp.core.ui.media.vendor` module contains any scripts or libraries
from 3rd party vendors which are required to make certain media modules work.
"""

View File

@ -69,7 +69,7 @@ class ScreenList(object):
screen_list.screen_list = []
screen_list.display_count = 0
screen_list.screen_count_changed()
screen_list._load_screen_settings()
screen_list.load_screen_settings()
QtCore.QObject.connect(desktop, QtCore.SIGNAL(u'resized(int)'), screen_list.screen_resolution_changed)
QtCore.QObject.connect(desktop, QtCore.SIGNAL(u'screenCountChanged(int)'), screen_list.screen_count_changed)
return screen_list
@ -237,7 +237,7 @@ class ScreenList(object):
y >= size.y() and y <= (size.y() + size.height()):
return screen[u'number']
def _load_screen_settings(self):
def load_screen_settings(self):
"""
Loads the screen size and the monitor number from the settings.
"""

View File

@ -995,6 +995,7 @@ class SlideController(DisplayController):
self.selectedRow = row
self.__checkUpdateSelectedSlide(row)
Receiver.send_message(u'slidecontroller_%s_changed' % self.typePrefix, row)
self.display.setFocus()
def onSlideChange(self, row):
"""

View File

@ -29,7 +29,7 @@
"""
The :mod:`openlp.core.utils` module provides the utility libraries for OpenLP.
"""
from datetime import datetime
from datetime import datetime, timedelta
from distutils.version import LooseVersion
import logging
import locale
@ -277,20 +277,31 @@ def check_latest_version(current_version):
``current_version``
The current version of OpenLP.
**Rules around versions and version files:**
* If a version number has a build (i.e. -bzr1234), then it is a nightly.
* If a version number's minor version is an odd number, it is a development release.
* If a version number's minor version is an even number, it is a stable release.
"""
version_string = current_version[u'full']
# set to prod in the distribution config file.
settings = Settings()
settings.beginGroup(u'general')
last_test = settings.value(u'last version test', datetime.now().date())
# This defaults to yesterday in order to force the update check to run when you've never run it before.
last_test = settings.value(u'last version test', datetime.now().date() - timedelta(days=1))
this_test = datetime.now().date()
settings.setValue(u'last version test', this_test)
settings.endGroup()
if last_test != this_test:
if current_version[u'build']:
req = urllib2.Request(u'http://www.openlp.org/files/dev_version.txt')
req = urllib2.Request(u'http://www.openlp.org/files/nightly_version.txt')
else:
req = urllib2.Request(u'http://www.openlp.org/files/version.txt')
version_parts = current_version[u'version'].split(u'.')
if int(version_parts[1]) % 2 != 0:
req = urllib2.Request(u'http://www.openlp.org/files/dev_version.txt')
else:
req = urllib2.Request(u'http://www.openlp.org/files/version.txt')
req.add_header(u'User-Agent', u'OpenLP/%s' % current_version[u'full'])
remote_version = None
try:

View File

@ -26,5 +26,31 @@
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
"""
Forms in OpenLP are made up of two classes. One class holds all the graphical
elements, like buttons and lists, and the other class holds all the functional
code, like slots and loading and saving.
The first class, commonly known as the **Dialog** class, is typically named
``Ui_<name>Dialog``. It is a slightly modified version of the class that the
``pyuic4`` command produces from Qt4's .ui file. Typical modifications will be
converting most strings from "" to u'' and using OpenLP's ``translate()``
function for translating strings.
The second class, commonly known as the **Form** class, is typically named
``<name>Form``. This class is the one which is instantiated and used. It uses
dual inheritance to inherit from (usually) QtGui.QDialog and the Ui class
mentioned above, like so::
class AuthorsForm(QtGui.QDialog, Ui_AuthorsDialog):
def __init__(self, parent=None):
QtGui.QDialog.__init__(self, parent)
self.setupUi(self)
This allows OpenLP to use ``self.object`` for all the GUI elements while keeping
them separate from the functionality, so that it is easier to recreate the GUI
from the .ui files later if necessary.
"""
from alertform import AlertForm

View File

@ -26,6 +26,10 @@
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
"""
The :mod:`~openlp.plugins.alerts.lib.alertsmanager` module contains the part of
the plugin which manages storing and displaying of alerts.
"""
import logging

View File

@ -26,6 +26,10 @@
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
"""
The :mod:`~openlp.plugins.custom.customplugin` module contains the Plugin class
for the Custom Slides plugin.
"""
import logging

View File

@ -26,6 +26,10 @@
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
"""
The :mod:`~openlp.plugins.custom.lib.customtab` module contains the settings tab
for the Custom Slides plugin, which is inserted into the configuration dialog.
"""
from PyQt4 import QtCore, QtGui
@ -66,6 +70,9 @@ class CustomTab(SettingsTab):
'Import missing custom slides from service files'))
def onDisplayFooterCheckBoxChanged(self, check_state):
"""
Toggle the setting for displaying the footer.
"""
self.displayFooter = False
# we have a set value convert to True/False
if check_state == QtCore.Qt.Checked:

View File

@ -50,6 +50,7 @@ from lxml import etree, objectify
log = logging.getLogger(__name__)
#TODO: These classes need to be refactored into a single class.
class CustomXMLBuilder(object):
"""
This class builds the XML used to describe songs.
@ -84,11 +85,11 @@ class CustomXMLBuilder(object):
self.lyrics.setAttribute(u'language', u'en')
self.song.appendChild(self.lyrics)
def add_verse_to_lyrics(self, type, number, content):
def add_verse_to_lyrics(self, verse_type, number, content):
"""
Add a verse to the ``<lyrics>`` tag.
``type``
``verse_type``
A string denoting the type of verse. Possible values are "Chorus",
"Verse", "Bridge", and "Custom".
@ -99,7 +100,7 @@ class CustomXMLBuilder(object):
The actual text of the verse to be stored.
"""
verse = self.custom_xml.createElement(u'verse')
verse.setAttribute(u'type', type)
verse.setAttribute(u'type', verse_type)
verse.setAttribute(u'label', number)
self.lyrics.appendChild(verse)
# add data as a CDATA section to protect the XML from special chars

View File

@ -77,7 +77,7 @@ class PresentationPlugin(Plugin):
if self.controllers[controller].enabled():
try:
self.controllers[controller].start_process()
except:
except Exception:
log.warn(u'Failed to start controller process')
self.controllers[controller].available = False
self.mediaItem.buildFileMaskString()

View File

@ -26,7 +26,6 @@
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
"""
Forms in OpenLP are made up of two classes. One class holds all the graphical
elements, like buttons and lists, and the other class holds all the functional

View File

@ -26,6 +26,10 @@
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
"""
The :mod:`~openlp.plugins.songs.forms.editsongform` module contains the form
used to edit songs.
"""
import logging
import re
@ -42,7 +46,7 @@ from openlp.plugins.songs.forms import EditVerseForm, MediaFilesForm
from openlp.plugins.songs.lib import SongXML, VerseType, clean_song
from openlp.plugins.songs.lib.db import Book, Song, Author, Topic, MediaFile
from openlp.plugins.songs.lib.ui import SongStrings
from editsongdialog import Ui_EditSongDialog
from openlp.plugins.songs.forms.editsongdialog import Ui_EditSongDialog
log = logging.getLogger(__name__)
@ -56,7 +60,7 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
"""
Constructor
"""
QtGui.QDialog.__init__(self, parent)
super(EditSongForm, self).__init__(parent)
self.mediaitem = mediaitem
self.song = None
# can this be automated?
@ -113,12 +117,18 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
self.whitespace = re.compile(r'\W+', re.UNICODE)
def initialise(self):
"""
Set up the form for when it is displayed.
"""
self.verseEditButton.setEnabled(False)
self.verseDeleteButton.setEnabled(False)
self.authorRemoveButton.setEnabled(False)
self.topicRemoveButton.setEnabled(False)
def loadAuthors(self):
"""
Load the authors from the database into the combobox.
"""
authors = self.manager.get_all_objects(Author,
order_by_ref=Author.display_name)
self.authorsComboBox.clear()
@ -132,14 +142,23 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
set_case_insensitive_completer(self.authors, self.authorsComboBox)
def loadTopics(self):
"""
Load the topics into the combobox.
"""
self.topics = []
self.__loadObjects(Topic, self.topicsComboBox, self.topics)
def loadBooks(self):
"""
Load the song books into the combobox
"""
self.books = []
self.__loadObjects(Book, self.songBookComboBox, self.books)
def __loadObjects(self, cls, combo, cache):
"""
Generically load a set of objects into a cache and a combobox.
"""
objects = self.manager.get_all_objects(cls, order_by_ref=cls.name)
combo.clear()
combo.addItem(u'')
@ -151,6 +170,9 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
set_case_insensitive_completer(cache, combo)
def loadThemes(self, theme_list):
"""
Load the themes into a combobox.
"""
self.themeComboBox.clear()
self.themeComboBox.addItem(u'')
self.themes = theme_list
@ -158,6 +180,9 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
set_case_insensitive_completer(self.themes, self.themeComboBox)
def loadMediaFiles(self):
"""
Load the media files into a combobox.
"""
self.audioAddFromMediaButton.setVisible(False)
for plugin in self.parent().pluginManager.plugins:
if plugin.name == u'media' and plugin.status == PluginStatus.Active:
@ -166,6 +191,9 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
break
def newSong(self):
"""
Blank the edit form out in preparation for a new song.
"""
log.debug(u'New Song')
self.song = None
self.initialise()
@ -313,6 +341,9 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
self.verseListWidget.repaint()
def onAuthorAddButtonClicked(self):
"""
Add the author to the list of authors associated with this song when the button is clicked.
"""
item = int(self.authorsComboBox.currentIndex())
text = self.authorsComboBox.currentText().strip(u' \r\n\t')
# This if statement is for OS X, which doesn't seem to work well with
@ -361,10 +392,16 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
self.authorsListView.addItem(author_item)
def onAuthorsListViewClicked(self):
"""
Run a set of actions when an author in the list is selected (mainly enable the delete button).
"""
if self.authorsListView.count() > 1:
self.authorRemoveButton.setEnabled(True)
def onAuthorRemoveButtonClicked(self):
"""
Remove the author from the list when the delete button is clicked.
"""
self.authorRemoveButton.setEnabled(False)
item = self.authorsListView.currentItem()
row = self.authorsListView.row(item)

View File

@ -107,13 +107,13 @@ class WowImport(SongImport):
"""
if isinstance(self.importSource, list):
self.importWizard.progressBar.setMaximum(len(self.importSource))
for file in self.importSource:
for source in self.importSource:
if self.stopImportFlag:
return
self.setDefaults()
song_data = open(file, 'rb')
song_data = open(source, 'rb')
if song_data.read(19) != u'WoW File\nSong Words':
self.logError(file, unicode(translate('SongsPlugin.WordsofWorshipSongImport',
self.logError(source, unicode(translate('SongsPlugin.WordsofWorshipSongImport',
('Invalid Words of Worship song file. Missing "Wow File\\nSong Words" header.'))))
continue
# Seek to byte which stores number of blocks in the song
@ -121,7 +121,7 @@ class WowImport(SongImport):
no_of_blocks = ord(song_data.read(1))
song_data.seek(66)
if song_data.read(16) != u'CSongDoc::CBlock':
self.logError(file, unicode(translate('SongsPlugin.WordsofWorshipSongImport',
self.logError(source, unicode(translate('SongsPlugin.WordsofWorshipSongImport',
('Invalid Words of Worship song file. Missing "CSongDoc::CBlock" string.'))))
continue
# Seek to the beginning of the first block
@ -150,9 +150,9 @@ class WowImport(SongImport):
copyright_length = ord(song_data.read(1))
if copyright_length:
self.addCopyright(unicode(song_data.read(copyright_length), u'cp1252'))
file_name = os.path.split(file)[1]
file_name = os.path.split(source)[1]
# Get the song title
self.title = file_name.rpartition(u'.')[0]
song_data.close()
if not self.finish():
self.logError(file)
self.logError(source)

View File

@ -26,6 +26,10 @@
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
"""
The :mod:`~openlp.plugins.songs.songsplugin` module contains the Plugin class
for the Songs plugin.
"""
import logging
import os

View File

@ -38,6 +38,7 @@ modules, simply run this script::
"""
import os
import sys
from distutils.version import LooseVersion
is_win = sys.platform.startswith('win')
@ -89,15 +90,13 @@ OPTIONAL_MODULES = [
w = sys.stdout.write
def check_vers(version, required, text):
if type(version) is str:
version = version.split('.')
version = map(int, version)
if type(required) is str:
required = required.split('.')
required = map(int, required)
w(' %s >= %s ... ' % (text, '.'.join(map(str, required))))
if version >= required:
w('.'.join(map(str, version)) + os.linesep)
if type(version) is not str:
version = '.'.join(map(str, version))
if type(required) is not str:
required = '.'.join(map(str, required))
w(' %s >= %s ... ' % (text, required))
if LooseVersion(version) >= LooseVersion(required):
w(version + os.linesep)
return True
else:
w('FAIL' + os.linesep)

View File

@ -3,7 +3,7 @@ Package to test the openlp.core.lib package.
"""
from unittest import TestCase
from mock import MagicMock, patch, call
from mock import MagicMock, patch
from openlp.core.lib import str_to_bool, translate, check_directory_exists, get_text_file_string