forked from openlp/openlp
Merge master.
This commit is contained in:
commit
a8041466ad
@ -1 +1 @@
|
||||
2.0
|
||||
2.1.0-bzr2141
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
4
openlp/core/ui/media/vendor/__init__.py
vendored
4
openlp/core/ui/media/vendor/__init__.py
vendored
@ -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.
|
||||
"""
|
||||
|
@ -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.
|
||||
"""
|
||||
|
@ -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):
|
||||
"""
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
@ -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()
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user