This commit is contained in:
Tim Bentley 2011-08-19 20:54:27 +01:00
commit 365a0477d7
53 changed files with 888 additions and 498 deletions

View File

@ -20,3 +20,4 @@ _eric4project
openlp/core/resources.py.old openlp/core/resources.py.old
*.qm *.qm
resources/windows/warnOpenLP.txt resources/windows/warnOpenLP.txt
openlp.cfg

View File

@ -79,6 +79,8 @@ class OpenLP(QtGui.QApplication):
class in order to provide the core of the application. class in order to provide the core of the application.
""" """
args = []
def exec_(self): def exec_(self):
""" """
Override exec method to allow the shared memory to be released on exit Override exec method to allow the shared memory to be released on exit
@ -92,7 +94,7 @@ class OpenLP(QtGui.QApplication):
""" """
# On Windows, the args passed into the constructor are # On Windows, the args passed into the constructor are
# ignored. Not very handy, so set the ones we want to use. # ignored. Not very handy, so set the ones we want to use.
self.args = args self.args.extend(args)
# provide a listener for widgets to reqest a screen update. # provide a listener for widgets to reqest a screen update.
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'openlp_process_events'), self.processEvents) QtCore.SIGNAL(u'openlp_process_events'), self.processEvents)
@ -125,6 +127,8 @@ class OpenLP(QtGui.QApplication):
# now kill the splashscreen # now kill the splashscreen
self.splash.finish(self.mainWindow) self.splash.finish(self.mainWindow)
log.debug(u'Splashscreen closed') log.debug(u'Splashscreen closed')
# make sure Qt really display the splash screen
self.processEvents()
self.mainWindow.repaint() self.mainWindow.repaint()
self.processEvents() self.processEvents()
if not has_run_wizard: if not has_run_wizard:
@ -180,6 +184,18 @@ class OpenLP(QtGui.QApplication):
""" """
self.restoreOverrideCursor() self.restoreOverrideCursor()
def event(self, event):
"""
Enables direct file opening on OS X
"""
if event.type() == QtCore.QEvent.FileOpen:
file_name = event.file()
log.debug(u'Got open file event for %s!', file_name)
self.args.insert(0, unicode(file_name))
return True
else:
return QtGui.QApplication.event(self, event)
def main(): def main():
""" """
The main function which parses command line options and then runs The main function which parses command line options and then runs

View File

@ -205,7 +205,7 @@ def clean_tags(text):
text = text.replace(u'<br>', u'\n') text = text.replace(u'<br>', u'\n')
text = text.replace(u'{br}', u'\n') text = text.replace(u'{br}', u'\n')
text = text.replace(u'&nbsp;', u' ') text = text.replace(u'&nbsp;', u' ')
for tag in DisplayTags.get_html_tags(): for tag in FormattingTags.get_html_tags():
text = text.replace(tag[u'start tag'], u'') text = text.replace(tag[u'start tag'], u'')
text = text.replace(tag[u'end tag'], u'') text = text.replace(tag[u'end tag'], u'')
return text return text
@ -214,7 +214,7 @@ def expand_tags(text):
""" """
Expand tags HTML for display Expand tags HTML for display
""" """
for tag in DisplayTags.get_html_tags(): for tag in FormattingTags.get_html_tags():
text = text.replace(tag[u'start tag'], tag[u'start html']) text = text.replace(tag[u'start tag'], tag[u'start html'])
text = text.replace(tag[u'end tag'], tag[u'end html']) text = text.replace(tag[u'end tag'], tag[u'end html'])
return text return text
@ -233,9 +233,9 @@ def check_directory_exists(dir):
except IOError: except IOError:
pass pass
from listwidgetwithdnd import ListWidgetWithDnD
from displaytags import DisplayTags
from eventreceiver import Receiver from eventreceiver import Receiver
from listwidgetwithdnd import ListWidgetWithDnD
from formattingtags import FormattingTags
from spelltextedit import SpellTextEdit from spelltextedit import SpellTextEdit
from settingsmanager import SettingsManager from settingsmanager import SettingsManager
from plugin import PluginStatus, StringContent, Plugin from plugin import PluginStatus, StringContent, Plugin

View File

@ -25,12 +25,12 @@
# Temple Place, Suite 330, Boston, MA 02111-1307 USA # # Temple Place, Suite 330, Boston, MA 02111-1307 USA #
############################################################################### ###############################################################################
""" """
Provide Html Tag management and Display Tag access class Provide HTML Tag management and Formatting Tag access class
""" """
from openlp.core.lib import translate from openlp.core.lib import translate
class DisplayTags(object): class FormattingTags(object):
""" """
Static Class to HTML Tags to be access around the code the list is managed Static Class to HTML Tags to be access around the code the list is managed
by the Options Tab. by the Options Tab.
@ -42,89 +42,93 @@ class DisplayTags(object):
""" """
Provide access to the html_expands list. Provide access to the html_expands list.
""" """
return DisplayTags.html_expands return FormattingTags.html_expands
@staticmethod @staticmethod
def reset_html_tags(): def reset_html_tags():
""" """
Resets the html_expands list. Resets the html_expands list.
""" """
DisplayTags.html_expands = [] FormattingTags.html_expands = []
base_tags = [] base_tags = []
# Append the base tags. # Append the base tags.
# Hex Color tags from http://www.w3schools.com/html/html_colornames.asp # Hex Color tags from http://www.w3schools.com/html/html_colornames.asp
base_tags.append({u'desc': translate('OpenLP.DisplayTags', 'Red'), base_tags.append({u'desc': translate('OpenLP.FormattingTags', 'Red'),
u'start tag': u'{r}', u'start tag': u'{r}',
u'start html': u'<span style="-webkit-text-fill-color:red">', u'start html': u'<span style="-webkit-text-fill-color:red">',
u'end tag': u'{/r}', u'end html': u'</span>', u'protected': True}) u'end tag': u'{/r}', u'end html': u'</span>', u'protected': True})
base_tags.append({u'desc': translate('OpenLP.DisplayTags', 'Black'), base_tags.append({u'desc': translate('OpenLP.FormattingTags', 'Black'),
u'start tag': u'{b}', u'start tag': u'{b}',
u'start html': u'<span style="-webkit-text-fill-color:black">', u'start html': u'<span style="-webkit-text-fill-color:black">',
u'end tag': u'{/b}', u'end html': u'</span>', u'protected': True}) u'end tag': u'{/b}', u'end html': u'</span>', u'protected': True})
base_tags.append({u'desc': translate('OpenLP.DisplayTags', 'Blue'), base_tags.append({u'desc': translate('OpenLP.FormattingTags', 'Blue'),
u'start tag': u'{bl}', u'start tag': u'{bl}',
u'start html': u'<span style="-webkit-text-fill-color:blue">', u'start html': u'<span style="-webkit-text-fill-color:blue">',
u'end tag': u'{/bl}', u'end html': u'</span>', u'protected': True}) u'end tag': u'{/bl}', u'end html': u'</span>', u'protected': True})
base_tags.append({u'desc': translate('OpenLP.DisplayTags', 'Yellow'), base_tags.append({u'desc': translate('OpenLP.FormattingTags', 'Yellow'),
u'start tag': u'{y}', u'start tag': u'{y}',
u'start html': u'<span style="-webkit-text-fill-color:yellow">', u'start html': u'<span style="-webkit-text-fill-color:yellow">',
u'end tag': u'{/y}', u'end html': u'</span>', u'protected': True}) u'end tag': u'{/y}', u'end html': u'</span>', u'protected': True})
base_tags.append({u'desc': translate('OpenLP.DisplayTags', 'Green'), base_tags.append({u'desc': translate('OpenLP.FormattingTags', 'Green'),
u'start tag': u'{g}', u'start tag': u'{g}',
u'start html': u'<span style="-webkit-text-fill-color:green">', u'start html': u'<span style="-webkit-text-fill-color:green">',
u'end tag': u'{/g}', u'end html': u'</span>', u'protected': True}) u'end tag': u'{/g}', u'end html': u'</span>', u'protected': True})
base_tags.append({u'desc': translate('OpenLP.DisplayTags', 'Pink'), base_tags.append({u'desc': translate('OpenLP.FormattingTags', 'Pink'),
u'start tag': u'{pk}', u'start tag': u'{pk}',
u'start html': u'<span style="-webkit-text-fill-color:#FFC0CB">', u'start html': u'<span style="-webkit-text-fill-color:#FFC0CB">',
u'end tag': u'{/pk}', u'end html': u'</span>', u'protected': True}) u'end tag': u'{/pk}', u'end html': u'</span>', u'protected': True})
base_tags.append({u'desc': translate('OpenLP.DisplayTags', 'Orange'), base_tags.append({u'desc': translate('OpenLP.FormattingTags', 'Orange'),
u'start tag': u'{o}', u'start tag': u'{o}',
u'start html': u'<span style="-webkit-text-fill-color:#FFA500">', u'start html': u'<span style="-webkit-text-fill-color:#FFA500">',
u'end tag': u'{/o}', u'end html': u'</span>', u'protected': True}) u'end tag': u'{/o}', u'end html': u'</span>', u'protected': True})
base_tags.append({u'desc': translate('OpenLP.DisplayTags', 'Purple'), base_tags.append({u'desc': translate('OpenLP.FormattingTags', 'Purple'),
u'start tag': u'{pp}', u'start tag': u'{pp}',
u'start html': u'<span style="-webkit-text-fill-color:#800080">', u'start html': u'<span style="-webkit-text-fill-color:#800080">',
u'end tag': u'{/pp}', u'end html': u'</span>', u'protected': True}) u'end tag': u'{/pp}', u'end html': u'</span>', u'protected': True})
base_tags.append({u'desc': translate('OpenLP.DisplayTags', 'White'), base_tags.append({u'desc': translate('OpenLP.FormattingTags', 'White'),
u'start tag': u'{w}', u'start tag': u'{w}',
u'start html': u'<span style="-webkit-text-fill-color:white">', u'start html': u'<span style="-webkit-text-fill-color:white">',
u'end tag': u'{/w}', u'end html': u'</span>', u'protected': True}) u'end tag': u'{/w}', u'end html': u'</span>', u'protected': True})
base_tags.append({ base_tags.append({
u'desc': translate('OpenLP.DisplayTags', 'Superscript'), u'desc': translate('OpenLP.FormattingTags', 'Superscript'),
u'start tag': u'{su}', u'start html': u'<sup>', u'start tag': u'{su}', u'start html': u'<sup>',
u'end tag': u'{/su}', u'end html': u'</sup>', u'protected': True}) u'end tag': u'{/su}', u'end html': u'</sup>', u'protected': True})
base_tags.append({u'desc': translate('OpenLP.DisplayTags', 'Subscript'), base_tags.append({
u'desc': translate('OpenLP.FormattingTags', 'Subscript'),
u'start tag': u'{sb}', u'start html': u'<sub>', u'start tag': u'{sb}', u'start html': u'<sub>',
u'end tag': u'{/sb}', u'end html': u'</sub>', u'protected': True}) u'end tag': u'{/sb}', u'end html': u'</sub>', u'protected': True})
base_tags.append({u'desc': translate('OpenLP.DisplayTags', 'Paragraph'), base_tags.append({
u'desc': translate('OpenLP.FormattingTags', 'Paragraph'),
u'start tag': u'{p}', u'start html': u'<p>', u'end tag': u'{/p}', u'start tag': u'{p}', u'start html': u'<p>', u'end tag': u'{/p}',
u'end html': u'</p>', u'protected': True}) u'end html': u'</p>', u'protected': True})
base_tags.append({u'desc': translate('OpenLP.DisplayTags', 'Bold'), base_tags.append({u'desc': translate('OpenLP.FormattingTags', 'Bold'),
u'start tag': u'{st}', u'start html': u'<strong>', u'start tag': u'{st}', u'start html': u'<strong>',
u'end tag': u'{/st}', u'end html': u'</strong>', u'end tag': u'{/st}', u'end html': u'</strong>',
u'protected': True}) u'protected': True})
base_tags.append({u'desc': translate('OpenLP.DisplayTags', 'Italics'), base_tags.append({
u'desc': translate('OpenLP.FormattingTags', 'Italics'),
u'start tag': u'{it}', u'start html': u'<em>', u'end tag': u'{/it}', u'start tag': u'{it}', u'start html': u'<em>', u'end tag': u'{/it}',
u'end html': u'</em>', u'protected': True}) u'end html': u'</em>', u'protected': True})
base_tags.append({u'desc': translate('OpenLP.DisplayTags', 'Underline'), base_tags.append({
u'desc': translate('OpenLP.FormattingTags', 'Underline'),
u'start tag': u'{u}', u'start tag': u'{u}',
u'start html': u'<span style="text-decoration: underline;">', u'start html': u'<span style="text-decoration: underline;">',
u'end tag': u'{/u}', u'end html': u'</span>', u'protected': True}) u'end tag': u'{/u}', u'end html': u'</span>', u'protected': True})
base_tags.append({u'desc': translate('OpenLP.DisplayTags', 'Break'), base_tags.append({u'desc': translate('OpenLP.FormattingTags', 'Break'),
u'start tag': u'{br}', u'start html': u'<br>', u'end tag': u'', u'start tag': u'{br}', u'start html': u'<br>', u'end tag': u'',
u'end html': u'', u'protected': True}) u'end html': u'', u'protected': True})
DisplayTags.add_html_tags(base_tags) FormattingTags.add_html_tags(base_tags)
@staticmethod @staticmethod
def add_html_tags(tags): def add_html_tags(tags):
""" """
Add a list of tags to the list Add a list of tags to the list
""" """
DisplayTags.html_expands.extend(tags) FormattingTags.html_expands.extend(tags)
@staticmethod @staticmethod
def remove_html_tag(tag_id): def remove_html_tag(tag_id):
""" """
Removes an individual html_expands tag. Removes an individual html_expands tag.
""" """
DisplayTags.html_expands.pop(tag_id) FormattingTags.html_expands.pop(tag_id)

View File

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

View File

@ -27,8 +27,12 @@
""" """
Extend QListWidget to handle drag and drop functionality Extend QListWidget to handle drag and drop functionality
""" """
import os.path
from PyQt4 import QtCore, QtGui from PyQt4 import QtCore, QtGui
from openlp.core.lib import Receiver
class ListWidgetWithDnD(QtGui.QListWidget): class ListWidgetWithDnD(QtGui.QListWidget):
""" """
Provide a list widget to store objects and handle drag and drop events Provide a list widget to store objects and handle drag and drop events
@ -41,6 +45,16 @@ class ListWidgetWithDnD(QtGui.QListWidget):
self.mimeDataText = name self.mimeDataText = name
assert(self.mimeDataText) assert(self.mimeDataText)
def activateDnD(self):
"""
Activate DnD of widget
"""
self.setAcceptDrops(True)
self.setDragDropMode(QtGui.QAbstractItemView.DragDrop)
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'%s_dnd' % self.mimeDataText),
self.parent().loadFile)
def mouseMoveEvent(self, event): def mouseMoveEvent(self, event):
""" """
Drag and drop event does not care what data is selected Drag and drop event does not care what data is selected
@ -58,3 +72,39 @@ class ListWidgetWithDnD(QtGui.QListWidget):
drag.setMimeData(mimeData) drag.setMimeData(mimeData)
mimeData.setText(self.mimeDataText) mimeData.setText(self.mimeDataText)
drag.start(QtCore.Qt.CopyAction) drag.start(QtCore.Qt.CopyAction)
def dragEnterEvent(self, event):
if event.mimeData().hasUrls():
event.accept()
else:
event.ignore()
def dragMoveEvent(self, event):
if event.mimeData().hasUrls():
event.setDropAction(QtCore.Qt.CopyAction)
event.accept()
else:
event.ignore()
def dropEvent(self, event):
"""
Receive drop event check if it is a file and process it if it is.
``event``
Handle of the event pint passed
"""
if event.mimeData().hasUrls():
event.setDropAction(QtCore.Qt.CopyAction)
event.accept()
files = []
for url in event.mimeData().urls():
localFile = unicode(url.toLocalFile())
if os.path.isfile(localFile):
files.append(localFile)
elif os.path.isdir(localFile):
listing = os.listdir(localFile)
for file in listing:
files.append(os.path.join(localFile,file))
Receiver.send_message(u'%s_dnd' % self.mimeDataText,files)
else:
event.ignore()

View File

@ -96,7 +96,7 @@ class MediaManagerItem(QtGui.QWidget):
self.plugin = plugin self.plugin = plugin
visible_title = self.plugin.getString(StringContent.VisibleName) visible_title = self.plugin.getString(StringContent.VisibleName)
self.title = unicode(visible_title[u'title']) self.title = unicode(visible_title[u'title'])
self.settingsSection = self.plugin.name.lower() self.settingsSection = self.plugin.name
self.icon = None self.icon = None
if icon: if icon:
self.icon = build_icon(icon) self.icon = build_icon(icon)
@ -113,7 +113,7 @@ class MediaManagerItem(QtGui.QWidget):
self.retranslateUi() self.retranslateUi()
self.auto_select_id = -1 self.auto_select_id = -1
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'%s_service_load' % self.plugin.name.lower()), QtCore.SIGNAL(u'%s_service_load' % self.plugin.name),
self.serviceLoad) self.serviceLoad)
def requiredIcons(self): def requiredIcons(self):
@ -252,7 +252,6 @@ class MediaManagerItem(QtGui.QWidget):
self.listView.setSelectionMode( self.listView.setSelectionMode(
QtGui.QAbstractItemView.ExtendedSelection) QtGui.QAbstractItemView.ExtendedSelection)
self.listView.setAlternatingRowColors(True) self.listView.setAlternatingRowColors(True)
self.listView.setDragEnabled(True)
self.listView.setObjectName(u'%sListView' % self.plugin.name) self.listView.setObjectName(u'%sListView' % self.plugin.name)
# Add to pageLayout # Add to pageLayout
self.pageLayout.addWidget(self.listView) self.pageLayout.addWidget(self.listView)
@ -339,26 +338,65 @@ class MediaManagerItem(QtGui.QWidget):
log.info(u'New files(s) %s', unicode(files)) log.info(u'New files(s) %s', unicode(files))
if files: if files:
Receiver.send_message(u'cursor_busy') Receiver.send_message(u'cursor_busy')
names = [] self.validateAndLoad(files)
for count in range(0, self.listView.count()): Receiver.send_message(u'cursor_normal')
names.append(self.listView.item(count).text())
newFiles = [] def loadFile(self, files):
for file in files: """
filename = os.path.split(unicode(file))[1] Turn file from Drag and Drop into an array so the Validate code
if filename in names: can run it.
``files``
The list of files to be loaded
"""
newFiles = []
errorShown = False
for file in files:
type = file.split(u'.')[-1]
if type.lower() not in self.onNewFileMasks:
if not errorShown:
critical_error_message_box( critical_error_message_box(
UiStrings().Duplicate, translate('OpenLP.MediaManagerItem',
'Invalid File Type'),
unicode(translate('OpenLP.MediaManagerItem', unicode(translate('OpenLP.MediaManagerItem',
'Duplicate filename %s.\nThis filename is already in ' 'Invalid File %s.\nSuffix not supported'))
'the list')) % filename) % file)
else: errorShown = True
newFiles.append(file) else:
newFiles.append(file)
if file:
self.validateAndLoad(newFiles)
def validateAndLoad(self, files):
"""
Process a list for files either from the File Dialog or from Drag and
Drop
``files``
The files to be loaded
"""
names = []
for count in range(0, self.listView.count()):
names.append(self.listView.item(count).text())
newFiles = []
duplicatesFound = False
for file in files:
filename = os.path.split(unicode(file))[1]
if filename in names:
duplicatesFound = True
else:
newFiles.append(file)
if newFiles:
self.loadList(newFiles) self.loadList(newFiles)
lastDir = os.path.split(unicode(files[0]))[0] lastDir = os.path.split(unicode(files[0]))[0]
SettingsManager.set_last_dir(self.settingsSection, lastDir) SettingsManager.set_last_dir(self.settingsSection, lastDir)
SettingsManager.set_list(self.settingsSection, SettingsManager.set_list(self.settingsSection,
self.settingsSection, self.getFileList()) self.settingsSection, self.getFileList())
Receiver.send_message(u'cursor_normal') if duplicatesFound:
critical_error_message_box(
UiStrings().Duplicate,
unicode(translate('OpenLP.MediaManagerItem',
'Duplicate files found on import and ignored.')))
def contextMenu(self, point): def contextMenu(self, point):
item = self.listView.itemAt(point) item = self.listView.itemAt(point)
@ -558,7 +596,7 @@ class MediaManagerItem(QtGui.QWidget):
QtGui.QMessageBox.information(self, UiStrings().NISs, QtGui.QMessageBox.information(self, UiStrings().NISs,
translate('OpenLP.MediaManagerItem', translate('OpenLP.MediaManagerItem',
'You must select an existing service item to add to.')) 'You must select an existing service item to add to.'))
elif self.plugin.name.lower() == serviceItem.name.lower(): elif self.plugin.name == serviceItem.name:
self.generateSlideData(serviceItem) self.generateSlideData(serviceItem)
self.plugin.serviceManager.addServiceItem(serviceItem, self.plugin.serviceManager.addServiceItem(serviceItem,
replace=True) replace=True)

View File

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

View File

@ -46,8 +46,6 @@ VERSE = u'The Lord said to {r}Noah{/r}: \n' \
'r{/pk}{o}e{/o}{pp}n{/pp} of the Lord\n' 'r{/pk}{o}e{/o}{pp}n{/pp} of the Lord\n'
FOOTER = [u'Arky Arky (Unknown)', u'Public Domain', u'CCLI 123456'] FOOTER = [u'Arky Arky (Unknown)', u'Public Domain', u'CCLI 123456']
HTML_END = u'</div></body></html>'
class Renderer(object): class Renderer(object):
""" """
Class to pull all Renderer interactions into one place. The plugins will Class to pull all Renderer interactions into one place. The plugins will
@ -56,20 +54,20 @@ class Renderer(object):
""" """
log.info(u'Renderer Loaded') log.info(u'Renderer Loaded')
def __init__(self, image_manager, theme_manager): def __init__(self, imageManager, themeManager):
""" """
Initialise the render manager. Initialise the render manager.
``image_manager`` ``imageManager``
A ImageManager instance which takes care of e. g. caching and resizing A ImageManager instance which takes care of e. g. caching and resizing
images. images.
``theme_manager`` ``themeManager``
The ThemeManager instance, used to get the current theme details. The ThemeManager instance, used to get the current theme details.
""" """
log.debug(u'Initialisation started') log.debug(u'Initialisation started')
self.theme_manager = theme_manager self.themeManager = themeManager
self.image_manager = image_manager self.imageManager = imageManager
self.screens = ScreenList.get_instance() self.screens = ScreenList.get_instance()
self.service_theme = u'' self.service_theme = u''
self.theme_level = u'' self.theme_level = u''
@ -77,7 +75,7 @@ class Renderer(object):
self.theme_data = None self.theme_data = None
self.bg_frame = None self.bg_frame = None
self.force_page = False self.force_page = False
self.display = MainDisplay(None, self.image_manager, False) self.display = MainDisplay(None, self.imageManager, False)
self.display.setup() self.display.setup()
def update_display(self): def update_display(self):
@ -85,10 +83,10 @@ class Renderer(object):
Updates the render manager's information about the current screen. Updates the render manager's information about the current screen.
""" """
log.debug(u'Update Display') log.debug(u'Update Display')
self._calculate_default(self.screens.current[u'size']) self._calculate_default()
if self.display: if self.display:
self.display.close() self.display.close()
self.display = MainDisplay(None, self.image_manager, False) self.display = MainDisplay(None, self.imageManager, False)
self.display.setup() self.display.setup()
self.bg_frame = None self.bg_frame = None
self.theme_data = None self.theme_data = None
@ -101,14 +99,14 @@ class Renderer(object):
The global-level theme to be set. The global-level theme to be set.
``theme_level`` ``theme_level``
Defaults to *``ThemeLevel.Global``*. The theme level, can be Defaults to ``ThemeLevel.Global``. The theme level, can be
``ThemeLevel.Global``, ``ThemeLevel.Service`` or ``ThemeLevel.Global``, ``ThemeLevel.Service`` or
``ThemeLevel.Song``. ``ThemeLevel.Song``.
""" """
self.global_theme = global_theme self.global_theme = global_theme
self.theme_level = theme_level self.theme_level = theme_level
self.global_theme_data = \ self.global_theme_data = \
self.theme_manager.getThemeData(self.global_theme) self.themeManager.getThemeData(self.global_theme)
self.theme_data = None self.theme_data = None
def set_service_theme(self, service_theme): def set_service_theme(self, service_theme):
@ -162,12 +160,12 @@ class Renderer(object):
if override_levels: if override_levels:
self.theme_data = override_theme self.theme_data = override_theme
else: else:
self.theme_data = self.theme_manager.getThemeData(theme) self.theme_data = self.themeManager.getThemeData(theme)
self._calculate_default(self.screens.current[u'size']) self._calculate_default()
self._build_text_rectangle(self.theme_data) self._build_text_rectangle(self.theme_data)
# if No file do not update cache # if No file do not update cache
if self.theme_data.background_filename: if self.theme_data.background_filename:
self.image_manager.add_image(self.theme_data.theme_name, self.imageManager.add_image(self.theme_data.theme_name,
self.theme_data.background_filename) self.theme_data.background_filename)
return self._rect, self._rect_footer return self._rect, self._rect_footer
@ -185,7 +183,7 @@ class Renderer(object):
# save value for use in format_slide # save value for use in format_slide
self.force_page = force_page self.force_page = force_page
# set the default image size for previews # set the default image size for previews
self._calculate_default(self.screens.preview[u'size']) self._calculate_default()
# build a service item to generate preview # build a service item to generate preview
serviceItem = ServiceItem() serviceItem = ServiceItem()
serviceItem.theme = theme_data serviceItem.theme = theme_data
@ -193,7 +191,7 @@ class Renderer(object):
# make big page for theme edit dialog to get line count # make big page for theme edit dialog to get line count
serviceItem.add_from_text(u'', VERSE + VERSE + VERSE) serviceItem.add_from_text(u'', VERSE + VERSE + VERSE)
else: else:
self.image_manager.del_image(theme_data.theme_name) self.imageManager.del_image(theme_data.theme_name)
serviceItem.add_from_text(u'', VERSE) serviceItem.add_from_text(u'', VERSE)
serviceItem.renderer = self serviceItem.renderer = self
serviceItem.raw_footer = FOOTER serviceItem.raw_footer = FOOTER
@ -203,52 +201,58 @@ class Renderer(object):
raw_html = serviceItem.get_rendered_frame(0) raw_html = serviceItem.get_rendered_frame(0)
preview = self.display.text(raw_html) preview = self.display.text(raw_html)
# Reset the real screen size for subsequent render requests # Reset the real screen size for subsequent render requests
self._calculate_default(self.screens.current[u'size']) self._calculate_default()
return preview return preview
self.force_page = False
def format_slide(self, text, line_break, item): def format_slide(self, text, item):
""" """
Calculate how much text can fit on a slide. Calculate how much text can fit on a slide.
``text`` ``text``
The words to go on the slides. The words to go on the slides.
``line_break`` ``item``
Add line endings after each line of text used for bibles. The :class:`~openlp.core.lib.serviceitem.ServiceItem` item object.
""" """
log.debug(u'format slide') log.debug(u'format slide')
# clean up line endings # Add line endings after each line of text used for bibles.
lines = self._lines_split(text) line_end = u'<br>'
pages = self._paginate_slide(lines, line_break, self.force_page) if item.is_capable(ItemCapabilities.NoLineBreaks):
if len(pages) > 1: line_end = u' '
# Songs and Custom # Bibles
if item.is_capable(ItemCapabilities.AllowsVirtualSplit): if item.is_capable(ItemCapabilities.AllowsWordSplit):
# Do not forget the line breaks ! pages = self._paginate_slide_words(text.split(u'\n'), line_end)
slides = text.split(u'[---]') else:
pages = [] # Clean up line endings.
for slide in slides: lines = self._lines_split(text)
lines = slide.strip(u'\n').split(u'\n') pages = self._paginate_slide(lines, line_end)
new_pages = self._paginate_slide(lines, line_break, if len(pages) > 1:
self.force_page) # Songs and Custom
pages.extend(new_pages) if item.is_capable(ItemCapabilities.AllowsVirtualSplit):
# Bibles # Do not forget the line breaks!
elif item.is_capable(ItemCapabilities.AllowsWordSplit): slides = text.split(u'[---]')
pages = self._paginate_slide_words(text, line_break) pages = []
return pages for slide in slides:
lines = slide.strip(u'\n').split(u'\n')
pages.extend(self._paginate_slide(lines, line_end))
new_pages = []
for page in pages:
while page.endswith(u'<br>'):
page = page[:-4]
new_pages.append(page)
return new_pages
def _calculate_default(self, screen): def _calculate_default(self):
""" """
Calculate the default dimentions of the screen. Calculate the default dimentions of the screen.
``screen``
The QSize of the screen.
""" """
log.debug(u'_calculate default %s', screen) screen_size = self.screens.current[u'size']
self.width = screen.width() self.width = screen_size.width()
self.height = screen.height() self.height = screen_size.height()
self.screen_ratio = float(self.height) / float(self.width) self.screen_ratio = float(self.height) / float(self.width)
log.debug(u'calculate default %d, %d, %f', log.debug(u'_calculate default %s, %f' % (screen_size,
self.width, self.height, self.screen_ratio) self.screen_ratio))
# 90% is start of footer # 90% is start of footer
self.footer_start = int(self.height * 0.90) self.footer_start = int(self.height * 0.90)
@ -301,177 +305,202 @@ class Renderer(object):
self.web.resize(self.page_width, self.page_height) self.web.resize(self.page_width, self.page_height)
self.web_frame = self.web.page().mainFrame() self.web_frame = self.web.page().mainFrame()
# Adjust width and height to account for shadow. outline done in css # Adjust width and height to account for shadow. outline done in css
self.page_shell = u'<html><head><style>' \ html = u"""<!DOCTYPE html><html><head><script>
u'*{margin: 0; padding: 0; border: 0;} '\ function show_text(newtext) {
u'#main {position:absolute; top:0px; %s %s}</style></head><body>' \ var main = document.getElementById('main');
u'<div id="main">' % \ main.innerHTML = newtext;
// We need to be sure that the page is loaded, that is why we
// return the element's height (even though we do not use the
// returned value).
return main.offsetHeight;
}
</script><style>*{margin: 0; padding: 0; border: 0;}
#main {position: absolute; top: 0px; %s %s}</style></head><body>
<div id="main"></div></body></html>""" % \
(build_lyrics_format_css(self.theme_data, self.page_width, (build_lyrics_format_css(self.theme_data, self.page_width,
self.page_height), build_lyrics_outline_css(self.theme_data)) self.page_height), build_lyrics_outline_css(self.theme_data))
self.web.setHtml(html)
def _paginate_slide(self, lines, line_break, force_page=False): def _paginate_slide(self, lines, line_end):
""" """
Figure out how much text can appear on a slide, using the current Figure out how much text can appear on a slide, using the current
theme settings. theme settings.
**Note:** The smallest possible "unit" of text for a slide is one line.
If the line is too long it will be cut off when displayed.
``lines`` ``lines``
The words to be fitted on the slide split into lines. The text to be fitted on the slide split into lines.
``line_break``
Add line endings after each line of text (used for bibles).
``force_page``
Flag to tell message lines in page.
``line_end``
The text added after each line. Either ``u' '`` or ``u'<br>``.
""" """
log.debug(u'_paginate_slide - Start') log.debug(u'_paginate_slide - Start')
line_end = u''
if line_break:
line_end = u'<br>'
formatted = []
html_text = u''
styled_text = u''
line_count = 0
for line in lines:
if line_count != -1:
line_count += 1
styled_line = expand_tags(line) + line_end
styled_text += styled_line
html = self.page_shell + styled_text + HTML_END
self.web.setHtml(html)
# Text too long so go to next page.
if self.web_frame.contentsSize().height() > self.page_height:
if force_page and line_count > 0:
Receiver.send_message(u'theme_line_count', line_count - 1)
line_count = -1
while html_text.endswith(u'<br>'):
html_text = html_text[:-4]
formatted.append(html_text)
html_text = u''
styled_text = styled_line
html_text += line + line_end
while html_text.endswith(u'<br>'):
html_text = html_text[:-4]
formatted.append(html_text)
log.debug(u'_paginate_slide - End')
return formatted
def _paginate_slide_words(self, text, line_break):
"""
Figure out how much text can appear on a slide, using the current
theme settings. This version is to handle text which needs to be split
into words to get it to fit.
``text``
The words to be fitted on the slide split into lines.
``line_break``
Add line endings after each line of text used for bibles.
"""
log.debug(u'_paginate_slide_words - Start')
line_end = u' '
if line_break:
line_end = u'<br>'
formatted = [] formatted = []
previous_html = u'' previous_html = u''
previous_raw = u'' previous_raw = u''
lines = text.split(u'\n') separator = u'<br>'
html_lines = map(expand_tags, lines)
# Text too long so go to next page.
if self._text_fits_on_slide(separator.join(html_lines)):
html_text, previous_raw = self._binary_chop(formatted,
previous_html, previous_raw, html_lines, lines, separator, u'')
else:
previous_raw = separator.join(lines)
if previous_raw:
formatted.append(previous_raw)
log.debug(u'_paginate_slide - End')
return formatted
def _paginate_slide_words(self, lines, line_end):
"""
Figure out how much text can appear on a slide, using the current
theme settings.
**Note:** The smallest possible "unit" of text for a slide is one word.
If one line is too long it will be processed word by word. This is
sometimes need for **bible** verses.
``lines``
The text to be fitted on the slide split into lines.
``line_end``
The text added after each line. Either ``u' '`` or ``u'<br>``.
This is needed for **bibles**.
"""
log.debug(u'_paginate_slide_words - Start')
formatted = []
previous_html = u''
previous_raw = u''
for line in lines: for line in lines:
line = line.strip() line = line.strip()
styled_line = expand_tags(line) html_line = expand_tags(line)
html = self.page_shell + previous_html + styled_line + HTML_END
self.web.setHtml(html)
# Text too long so go to next page. # Text too long so go to next page.
if self.web_frame.contentsSize().height() > self.page_height: if self._text_fits_on_slide(previous_html + html_line):
# Check if there was a verse before the current one and append # Check if there was a verse before the current one and append
# it, when it fits on the page. # it, when it fits on the page.
if previous_html: if previous_html:
html = self.page_shell + previous_html + HTML_END if not self._text_fits_on_slide(previous_html):
self.web.setHtml(html)
if self.web_frame.contentsSize().height() <= \
self.page_height:
while previous_raw.endswith(u'<br>'):
previous_raw = previous_raw[:-4]
formatted.append(previous_raw) formatted.append(previous_raw)
previous_html = u'' previous_html = u''
previous_raw = u'' previous_raw = u''
html = self.page_shell + styled_line + HTML_END
self.web.setHtml(html)
# Now check if the current verse will fit, if it does # Now check if the current verse will fit, if it does
# not we have to start to process the verse word by # not we have to start to process the verse word by
# word. # word.
if self.web_frame.contentsSize().height() <= \ if not self._text_fits_on_slide(html_line):
self.page_height: previous_html = html_line + line_end
previous_html = styled_line + line_end
previous_raw = line + line_end previous_raw = line + line_end
continue continue
# Figure out how many words of the line will fit on screen by # Figure out how many words of the line will fit on screen as
# using the algorithm known as "binary chop". # the line will not fit as a whole.
raw_words = self._words_split(line) raw_words = self._words_split(line)
html_words = [expand_tags(word) for word in raw_words] html_words = map(expand_tags, raw_words)
smallest_index = 0 previous_html, previous_raw = self._binary_chop(
highest_index = len(html_words) - 1 formatted, previous_html, previous_raw, html_words,
index = int(highest_index / 2) raw_words, u' ', line_end)
while True:
html = self.page_shell + previous_html + \
u''.join(html_words[:index + 1]).strip() + HTML_END
self.web.setHtml(html)
if self.web_frame.contentsSize().height() > \
self.page_height:
# We know that it does not fit, so change/calculate the
# new index and highest_index accordingly.
highest_index = index
index = int(index - (index - smallest_index) / 2)
else:
smallest_index = index
index = int(index + (highest_index - index) / 2)
# We found the number of words which will fit.
if smallest_index == index or highest_index == index:
index = smallest_index
formatted.append(previous_raw.rstrip(u'<br>') +
u''.join(raw_words[:index + 1]))
previous_html = u''
previous_raw = u''
else:
continue
# Check if the rest of the line fits on the slide. If it
# does we do not have to do the much more intensive "word by
# word" checking.
html = self.page_shell + \
u''.join(html_words[index + 1:]).strip() + HTML_END
self.web.setHtml(html)
if self.web_frame.contentsSize().height() <= \
self.page_height:
previous_html = \
u''.join(html_words[index + 1:]).strip() + line_end
previous_raw = \
u''.join(raw_words[index + 1:]).strip() + line_end
break
else:
# The other words do not fit, thus reset the indexes,
# create a new list and continue with "word by word".
raw_words = raw_words[index + 1:]
html_words = html_words[index + 1:]
smallest_index = 0
highest_index = len(html_words) - 1
index = int(highest_index / 2)
else: else:
previous_html += styled_line + line_end previous_html += html_line + line_end
previous_raw += line + line_end previous_raw += line + line_end
while previous_raw.endswith(u'<br>'):
previous_raw = previous_raw[:-4]
formatted.append(previous_raw) formatted.append(previous_raw)
log.debug(u'_paginate_slide_words - End') log.debug(u'_paginate_slide_words - End')
return formatted return formatted
def _binary_chop(self, formatted, previous_html, previous_raw, html_list,
raw_list, separator, line_end):
"""
This implements the binary chop algorithm for faster rendering. This
algorithm works line based (line by line) and word based (word by word).
It is assumed that this method is **only** called, when the lines/words
to be rendered do **not** fit as a whole.
``formatted``
The list to append any slides.
``previous_html``
The html text which is know to fit on a slide, but is not yet added
to the list of slides. (unicode string)
``previous_raw``
The raw text (with formatting tags) which is know to fit on a slide,
but is not yet added to the list of slides. (unicode string)
``html_list``
The elements which do not fit on a slide and needs to be processed
using the binary chop. The text contains html.
``raw_list``
The elements which do not fit on a slide and needs to be processed
using the binary chop. The elements can contain formatting tags.
``separator``
The separator for the elements. For lines this is ``u'<br>'`` and
for words this is ``u' '``.
``line_end``
The text added after each "element line". Either ``u' '`` or
``u'<br>``. This is needed for bibles.
"""
smallest_index = 0
highest_index = len(html_list) - 1
index = int(highest_index / 2)
while True:
if self._text_fits_on_slide(
previous_html + separator.join(html_list[:index + 1]).strip()):
# We know that it does not fit, so change/calculate the
# new index and highest_index accordingly.
highest_index = index
index = int(index - (index - smallest_index) / 2)
else:
smallest_index = index
index = int(index + (highest_index - index) / 2)
# We found the number of words which will fit.
if smallest_index == index or highest_index == index:
index = smallest_index
formatted.append(previous_raw.rstrip(u'<br>') +
separator.join(raw_list[:index + 1]))
previous_html = u''
previous_raw = u''
# Stop here as the theme line count was requested.
if self.force_page:
Receiver.send_message(u'theme_line_count', index + 1)
break
else:
continue
# Check if the remaining elements fit on the slide.
if not self._text_fits_on_slide(
separator.join(html_list[index + 1:]).strip()):
previous_html = separator.join(
html_list[index + 1:]).strip() + line_end
previous_raw = separator.join(
raw_list[index + 1:]).strip() + line_end
break
else:
# The remaining elements do not fit, thus reset the indexes,
# create a new list and continue.
raw_list = raw_list[index + 1:]
html_list = html_list[index + 1:]
smallest_index = 0
highest_index = len(html_list) - 1
index = int(highest_index / 2)
return previous_html, previous_raw
def _text_fits_on_slide(self, text):
"""
Checks if the given ``text`` fits on a slide. If it does ``True`` is
returned, otherwise ``False``.
``text``
The text to check. It can contain HTML tags.
"""
self.web_frame.evaluateJavaScript(u'show_text("%s")' %
text.replace(u'\\', u'\\\\').replace(u'\"', u'\\\"'))
return self.web_frame.contentsSize().height() > self.page_height
def _words_split(self, line): def _words_split(self, line):
""" """
Split the slide up by word so can wrap better Split the slide up by word so can wrap better
""" """
# this parse we are to be wordy # this parse we are to be wordy
line = line.replace(u'\n', u' ') line = line.replace(u'\n', u' ')
words = line.split(u' ') return line.split(u' ')
return [word + u' ' for word in words]
def _lines_split(self, text): def _lines_split(self, text):
""" """
@ -479,5 +508,5 @@ class Renderer(object):
""" """
# this parse we do not want to use this so remove it # this parse we do not want to use this so remove it
text = text.replace(u'\n[---]', u'') text = text.replace(u'\n[---]', u'')
lines = text.split(u'\n') text = text.replace(u'[---]', u'')
return [line.replace(u'[---]', u'') for line in lines] return text.split(u'\n')

View File

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

View File

@ -39,7 +39,7 @@ except ImportError:
from PyQt4 import QtCore, QtGui from PyQt4 import QtCore, QtGui
from openlp.core.lib import translate, DisplayTags from openlp.core.lib import translate, FormattingTags
from openlp.core.lib.ui import checkable_action from openlp.core.lib.ui import checkable_action
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -48,9 +48,10 @@ class SpellTextEdit(QtGui.QPlainTextEdit):
""" """
Spell checking widget based on QPlanTextEdit. Spell checking widget based on QPlanTextEdit.
""" """
def __init__(self, *args): def __init__(self, parent=None, formattingTagsAllowed=True):
global ENCHANT_AVAILABLE global ENCHANT_AVAILABLE
QtGui.QPlainTextEdit.__init__(self, *args) QtGui.QPlainTextEdit.__init__(self, parent)
self.formattingTagsAllowed = formattingTagsAllowed
# Default dictionary based on the current locale. # Default dictionary based on the current locale.
if ENCHANT_AVAILABLE: if ENCHANT_AVAILABLE:
try: try:
@ -110,16 +111,17 @@ class SpellTextEdit(QtGui.QPlainTextEdit):
spell_menu.addAction(action) spell_menu.addAction(action)
# Only add the spelling suggests to the menu if there are # Only add the spelling suggests to the menu if there are
# suggestions. # suggestions.
if len(spell_menu.actions()): if spell_menu.actions():
popupMenu.insertMenu(popupMenu.actions()[0], spell_menu) popupMenu.insertMenu(popupMenu.actions()[0], spell_menu)
tagMenu = QtGui.QMenu(translate('OpenLP.SpellTextEdit', tagMenu = QtGui.QMenu(translate('OpenLP.SpellTextEdit',
'Formatting Tags')) 'Formatting Tags'))
for html in DisplayTags.get_html_tags(): if self.formattingTagsAllowed:
action = SpellAction(html[u'desc'], tagMenu) for html in FormattingTags.get_html_tags():
action.correct.connect(self.htmlTag) action = SpellAction(html[u'desc'], tagMenu)
tagMenu.addAction(action) action.correct.connect(self.htmlTag)
popupMenu.insertSeparator(popupMenu.actions()[0]) tagMenu.addAction(action)
popupMenu.insertMenu(popupMenu.actions()[0], tagMenu) popupMenu.insertSeparator(popupMenu.actions()[0])
popupMenu.insertMenu(popupMenu.actions()[0], tagMenu)
popupMenu.exec_(event.globalPos()) popupMenu.exec_(event.globalPos())
def setLanguage(self, action): def setLanguage(self, action):
@ -148,7 +150,7 @@ class SpellTextEdit(QtGui.QPlainTextEdit):
""" """
Replaces the selected text with word. Replaces the selected text with word.
""" """
for html in DisplayTags.get_html_tags(): for html in FormattingTags.get_html_tags():
if tag == html[u'desc']: if tag == html[u'desc']:
cursor = self.textCursor() cursor = self.textCursor()
if self.textCursor().hasSelection(): if self.textCursor().hasSelection():

View File

@ -69,7 +69,7 @@ from advancedtab import AdvancedTab
from aboutform import AboutForm from aboutform import AboutForm
from pluginform import PluginForm from pluginform import PluginForm
from settingsform import SettingsForm from settingsform import SettingsForm
from displaytagform import DisplayTagForm from formattingtagform import FormattingTagForm
from shortcutlistform import ShortcutListForm from shortcutlistform import ShortcutListForm
from mediadockmanager import MediaDockManager from mediadockmanager import MediaDockManager
from servicemanager import ServiceManager from servicemanager import ServiceManager

View File

@ -61,6 +61,5 @@ class AboutForm(QtGui.QDialog, Ui_AboutDialog):
Launch a web browser and go to the contribute page on the site. Launch a web browser and go to the contribute page on the site.
""" """
import webbrowser import webbrowser
url = u'http://www.openlp.org/en/documentation/introduction/' \ url = u'http://openlp.org/en/documentation/introduction/contributing'
+ u'contributing.html'
webbrowser.open_new(url) webbrowser.open_new(url)

View File

@ -129,6 +129,7 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
os.path.join(gettempdir(), u'openlp', screenshot))) os.path.join(gettempdir(), u'openlp', screenshot)))
item.setCheckState(QtCore.Qt.Unchecked) item.setCheckState(QtCore.Qt.Unchecked)
item.setFlags(item.flags() | QtCore.Qt.ItemIsUserCheckable) item.setFlags(item.flags() | QtCore.Qt.ItemIsUserCheckable)
Receiver.send_message(u'cursor_normal')
def nextId(self): def nextId(self):
""" """
@ -156,10 +157,27 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
item = self.themesListWidget.item(iter) item = self.themesListWidget.item(iter)
if item.checkState() == QtCore.Qt.Checked: if item.checkState() == QtCore.Qt.Checked:
self.themeComboBox.addItem(item.text()) self.themeComboBox.addItem(item.text())
# Check if this is a re-run of the wizard.
self.has_run_wizard = QtCore.QSettings().value(
u'general/has run wizard', QtCore.QVariant(False)).toBool()
if self.has_run_wizard:
# Add any existing themes to list.
for theme in self.parent().themeManagerContents.getThemes():
index = self.themeComboBox.findText(theme)
if index == -1:
self.themeComboBox.addItem(theme)
default_theme = unicode(QtCore.QSettings().value(
u'themes/global theme',
QtCore.QVariant(u'')).toString())
# Pre-select the current default theme.
index = self.themeComboBox.findText(default_theme)
self.themeComboBox.setCurrentIndex(index)
elif pageId == FirstTimePage.Progress: elif pageId == FirstTimePage.Progress:
Receiver.send_message(u'cursor_busy')
self._preWizard() self._preWizard()
self._performWizard() self._performWizard()
self._postWizard() self._postWizard()
Receiver.send_message(u'cursor_normal')
def updateScreenListCombo(self): def updateScreenListCombo(self):
""" """
@ -248,11 +266,21 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
""" """
if self.max_progress: if self.max_progress:
self.progressBar.setValue(self.progressBar.maximum()) self.progressBar.setValue(self.progressBar.maximum())
self.progressLabel.setText(translate('OpenLP.FirstTimeWizard', if self.has_run_wizard:
'Download complete. Click the finish button to start OpenLP.')) self.progressLabel.setText(translate('OpenLP.FirstTimeWizard',
'Download complete.'
' Click the finish button to return to OpenLP.'))
else:
self.progressLabel.setText(translate('OpenLP.FirstTimeWizard',
'Download complete.'
' Click the finish button to start OpenLP.'))
else: else:
self.progressLabel.setText(translate('OpenLP.FirstTimeWizard', if self.has_run_wizard:
'Click the finish button to start OpenLP.')) self.progressLabel.setText(translate('OpenLP.FirstTimeWizard',
'Click the finish button to return to OpenLP.'))
else:
self.progressLabel.setText(translate('OpenLP.FirstTimeWizard',
'Click the finish button to start OpenLP.'))
self.finishButton.setVisible(True) self.finishButton.setVisible(True)
self.finishButton.setEnabled(True) self.finishButton.setEnabled(True)
self.cancelButton.setVisible(False) self.cancelButton.setVisible(False)

View File

@ -30,15 +30,15 @@ from PyQt4 import QtCore, QtGui
from openlp.core.lib import translate from openlp.core.lib import translate
from openlp.core.lib.ui import UiStrings from openlp.core.lib.ui import UiStrings
class Ui_DisplayTagDialog(object): class Ui_FormattingTagDialog(object):
def setupUi(self, displayTagDialog): def setupUi(self, formattingTagDialog):
displayTagDialog.setObjectName(u'displayTagDialog') formattingTagDialog.setObjectName(u'formattingTagDialog')
displayTagDialog.resize(725, 548) formattingTagDialog.resize(725, 548)
self.listdataGridLayout = QtGui.QGridLayout(displayTagDialog) self.listdataGridLayout = QtGui.QGridLayout(formattingTagDialog)
self.listdataGridLayout.setMargin(8) self.listdataGridLayout.setMargin(8)
self.listdataGridLayout.setObjectName(u'listdataGridLayout') self.listdataGridLayout.setObjectName(u'listdataGridLayout')
self.tagTableWidget = QtGui.QTableWidget(displayTagDialog) self.tagTableWidget = QtGui.QTableWidget(formattingTagDialog)
self.tagTableWidget.setHorizontalScrollBarPolicy( self.tagTableWidget.setHorizontalScrollBarPolicy(
QtCore.Qt.ScrollBarAlwaysOff) QtCore.Qt.ScrollBarAlwaysOff)
self.tagTableWidget.setEditTriggers( self.tagTableWidget.setEditTriggers(
@ -67,11 +67,11 @@ class Ui_DisplayTagDialog(object):
spacerItem = QtGui.QSpacerItem(40, 20, spacerItem = QtGui.QSpacerItem(40, 20,
QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum) QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum)
self.horizontalLayout.addItem(spacerItem) self.horizontalLayout.addItem(spacerItem)
self.deletePushButton = QtGui.QPushButton(displayTagDialog) self.deletePushButton = QtGui.QPushButton(formattingTagDialog)
self.deletePushButton.setObjectName(u'deletePushButton') self.deletePushButton.setObjectName(u'deletePushButton')
self.horizontalLayout.addWidget(self.deletePushButton) self.horizontalLayout.addWidget(self.deletePushButton)
self.listdataGridLayout.addLayout(self.horizontalLayout, 1, 0, 1, 1) self.listdataGridLayout.addLayout(self.horizontalLayout, 1, 0, 1, 1)
self.editGroupBox = QtGui.QGroupBox(displayTagDialog) self.editGroupBox = QtGui.QGroupBox(formattingTagDialog)
self.editGroupBox.setObjectName(u'editGroupBox') self.editGroupBox.setObjectName(u'editGroupBox')
self.dataGridLayout = QtGui.QGridLayout(self.editGroupBox) self.dataGridLayout = QtGui.QGridLayout(self.editGroupBox)
self.dataGridLayout.setObjectName(u'dataGridLayout') self.dataGridLayout.setObjectName(u'dataGridLayout')
@ -112,38 +112,38 @@ class Ui_DisplayTagDialog(object):
self.savePushButton.setObjectName(u'savePushButton') self.savePushButton.setObjectName(u'savePushButton')
self.dataGridLayout.addWidget(self.savePushButton, 4, 2, 1, 1) self.dataGridLayout.addWidget(self.savePushButton, 4, 2, 1, 1)
self.listdataGridLayout.addWidget(self.editGroupBox, 2, 0, 1, 1) self.listdataGridLayout.addWidget(self.editGroupBox, 2, 0, 1, 1)
self.buttonBox = QtGui.QDialogButtonBox(displayTagDialog) self.buttonBox = QtGui.QDialogButtonBox(formattingTagDialog)
self.buttonBox.setObjectName('displayTagDialogButtonBox') self.buttonBox.setObjectName('formattingTagDialogButtonBox')
self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Close) self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Close)
self.listdataGridLayout.addWidget(self.buttonBox, 3, 0, 1, 1) self.listdataGridLayout.addWidget(self.buttonBox, 3, 0, 1, 1)
self.retranslateUi(displayTagDialog) self.retranslateUi(formattingTagDialog)
QtCore.QMetaObject.connectSlotsByName(displayTagDialog) QtCore.QMetaObject.connectSlotsByName(formattingTagDialog)
def retranslateUi(self, displayTagDialog): def retranslateUi(self, formattingTagDialog):
displayTagDialog.setWindowTitle(translate('OpenLP.displayTagDialog', formattingTagDialog.setWindowTitle(translate(
'Configure Display Tags')) 'OpenLP.FormattingTagDialog', 'Configure Formatting Tags'))
self.editGroupBox.setTitle( self.editGroupBox.setTitle(
translate('OpenLP.DisplayTagDialog', 'Edit Selection')) translate('OpenLP.FormattingTagDialog', 'Edit Selection'))
self.savePushButton.setText( self.savePushButton.setText(
translate('OpenLP.DisplayTagDialog', 'Save')) translate('OpenLP.FormattingTagDialog', 'Save'))
self.descriptionLabel.setText( self.descriptionLabel.setText(
translate('OpenLP.DisplayTagDialog', 'Description')) translate('OpenLP.FormattingTagDialog', 'Description'))
self.tagLabel.setText(translate('OpenLP.DisplayTagDialog', 'Tag')) self.tagLabel.setText(translate('OpenLP.FormattingTagDialog', 'Tag'))
self.startTagLabel.setText( self.startTagLabel.setText(
translate('OpenLP.DisplayTagDialog', 'Start tag')) translate('OpenLP.FormattingTagDialog', 'Start tag'))
self.endTagLabel.setText( self.endTagLabel.setText(
translate('OpenLP.DisplayTagDialog', 'End tag')) translate('OpenLP.FormattingTagDialog', 'End tag'))
self.deletePushButton.setText(UiStrings().Delete) self.deletePushButton.setText(UiStrings().Delete)
self.newPushButton.setText(UiStrings().New) self.newPushButton.setText(UiStrings().New)
self.tagTableWidget.horizontalHeaderItem(0).setText( self.tagTableWidget.horizontalHeaderItem(0).setText(
translate('OpenLP.DisplayTagDialog', 'Description')) translate('OpenLP.FormattingTagDialog', 'Description'))
self.tagTableWidget.horizontalHeaderItem(1).setText( self.tagTableWidget.horizontalHeaderItem(1).setText(
translate('OpenLP.DisplayTagDialog', 'Tag Id')) translate('OpenLP.FormattingTagDialog', 'Tag Id'))
self.tagTableWidget.horizontalHeaderItem(2).setText( self.tagTableWidget.horizontalHeaderItem(2).setText(
translate('OpenLP.DisplayTagDialog', 'Start HTML')) translate('OpenLP.FormattingTagDialog', 'Start HTML'))
self.tagTableWidget.horizontalHeaderItem(3).setText( self.tagTableWidget.horizontalHeaderItem(3).setText(
translate('OpenLP.DisplayTagDialog', 'End HTML')) translate('OpenLP.FormattingTagDialog', 'End HTML'))
self.tagTableWidget.setColumnWidth(0, 120) self.tagTableWidget.setColumnWidth(0, 120)
self.tagTableWidget.setColumnWidth(1, 80) self.tagTableWidget.setColumnWidth(1, 80)
self.tagTableWidget.setColumnWidth(2, 330) self.tagTableWidget.setColumnWidth(2, 330)

View File

@ -25,22 +25,22 @@
# Temple Place, Suite 330, Boston, MA 02111-1307 USA # # Temple Place, Suite 330, Boston, MA 02111-1307 USA #
############################################################################### ###############################################################################
""" """
The :mod:`DisplayTagTab` provides an Tag Edit facility. The Base set are The :mod:`formattingtagform` provides an Tag Edit facility. The Base set are
protected and included each time loaded. Custom tags can be defined and saved. protected and included each time loaded. Custom tags can be defined and saved.
The Custom Tag arrays are saved in a pickle so QSettings works on them. Base The Custom Tag arrays are saved in a pickle so QSettings works on them. Base
Tags cannot be changed. Tags cannot be changed.
""" """
import cPickle import cPickle
from PyQt4 import QtCore, QtGui from PyQt4 import QtCore, QtGui
from openlp.core.lib import translate, DisplayTags from openlp.core.lib import translate, FormattingTags
from openlp.core.lib.ui import critical_error_message_box from openlp.core.lib.ui import critical_error_message_box
from openlp.core.ui.displaytagdialog import Ui_DisplayTagDialog from openlp.core.ui.formattingtagdialog import Ui_FormattingTagDialog
class DisplayTagForm(QtGui.QDialog, Ui_DisplayTagDialog): class FormattingTagForm(QtGui.QDialog, Ui_FormattingTagDialog):
""" """
The :class:`DisplayTagTab` manages the settings tab . The :class:`FormattingTagForm` manages the settings tab .
""" """
def __init__(self, parent): def __init__(self, parent):
""" """
@ -48,7 +48,7 @@ class DisplayTagForm(QtGui.QDialog, Ui_DisplayTagDialog):
""" """
QtGui.QDialog.__init__(self, parent) QtGui.QDialog.__init__(self, parent)
self.setupUi(self) self.setupUi(self)
self._loadDisplayTags() self._loadFormattingTags()
QtCore.QObject.connect(self.tagTableWidget, QtCore.QObject.connect(self.tagTableWidget,
QtCore.SIGNAL(u'clicked(QModelIndex)'), self.onRowSelected) QtCore.SIGNAL(u'clicked(QModelIndex)'), self.onRowSelected)
QtCore.QObject.connect(self.newPushButton, QtCore.QObject.connect(self.newPushButton,
@ -65,19 +65,20 @@ class DisplayTagForm(QtGui.QDialog, Ui_DisplayTagDialog):
Load Display and set field state. Load Display and set field state.
""" """
# Create initial copy from master # Create initial copy from master
self._loadDisplayTags() self._loadFormattingTags()
self._resetTable() self._resetTable()
self.selected = -1 self.selected = -1
return QtGui.QDialog.exec_(self) return QtGui.QDialog.exec_(self)
def _loadDisplayTags(self): def _loadFormattingTags(self):
""" """
Load the Tags from store so can be used in the system or used to Load the Tags from store so can be used in the system or used to
update the display. If Cancel was selected this is needed to reset the update the display. If Cancel was selected this is needed to reset the
dsiplay to the correct version. dsiplay to the correct version.
""" """
# Initial Load of the Tags # Initial Load of the Tags
DisplayTags.reset_html_tags() FormattingTags.reset_html_tags()
# Formatting Tags were also known as display tags.
user_expands = QtCore.QSettings().value(u'displayTags/html_tags', user_expands = QtCore.QSettings().value(u'displayTags/html_tags',
QtCore.QVariant(u'')).toString() QtCore.QVariant(u'')).toString()
# cPickle only accepts str not unicode strings # cPickle only accepts str not unicode strings
@ -85,14 +86,14 @@ class DisplayTagForm(QtGui.QDialog, Ui_DisplayTagDialog):
if user_expands_string: if user_expands_string:
user_tags = cPickle.loads(user_expands_string) user_tags = cPickle.loads(user_expands_string)
# If we have some user ones added them as well # If we have some user ones added them as well
DisplayTags.add_html_tags(user_tags) FormattingTags.add_html_tags(user_tags)
def onRowSelected(self): def onRowSelected(self):
""" """
Table Row selected so display items and set field state. Table Row selected so display items and set field state.
""" """
row = self.tagTableWidget.currentRow() row = self.tagTableWidget.currentRow()
html = DisplayTags.get_html_tags()[row] html = FormattingTags.get_html_tags()[row]
self.selected = row self.selected = row
self.descriptionLineEdit.setText(html[u'desc']) self.descriptionLineEdit.setText(html[u'desc'])
self.tagLineEdit.setText(self._strip(html[u'start tag'])) self.tagLineEdit.setText(self._strip(html[u'start tag']))
@ -117,23 +118,23 @@ class DisplayTagForm(QtGui.QDialog, Ui_DisplayTagDialog):
""" """
Add a new tag to list only if it is not a duplicate. Add a new tag to list only if it is not a duplicate.
""" """
for html in DisplayTags.get_html_tags(): for html in FormattingTags.get_html_tags():
if self._strip(html[u'start tag']) == u'n': if self._strip(html[u'start tag']) == u'n':
critical_error_message_box( critical_error_message_box(
translate('OpenLP.DisplayTagTab', 'Update Error'), translate('OpenLP.FormattingTagForm', 'Update Error'),
translate('OpenLP.DisplayTagTab', translate('OpenLP.FormattingTagForm',
'Tag "n" already defined.')) 'Tag "n" already defined.'))
return return
# Add new tag to list # Add new tag to list
tag = { tag = {
u'desc': translate('OpenLP.DisplayTagTab', 'New Tag'), u'desc': translate('OpenLP.FormattingTagForm', 'New Tag'),
u'start tag': u'{n}', u'start tag': u'{n}',
u'start html': translate('OpenLP.DisplayTagTab', '<HTML here>'), u'start html': translate('OpenLP.FormattingTagForm', '<HTML here>'),
u'end tag': u'{/n}', u'end tag': u'{/n}',
u'end html': translate('OpenLP.DisplayTagTab', '</and here>'), u'end html': translate('OpenLP.FormattingTagForm', '</and here>'),
u'protected': False u'protected': False
} }
DisplayTags.add_html_tags([tag]) FormattingTags.add_html_tags([tag])
self._resetTable() self._resetTable()
# Highlight new row # Highlight new row
self.tagTableWidget.selectRow(self.tagTableWidget.rowCount() - 1) self.tagTableWidget.selectRow(self.tagTableWidget.rowCount() - 1)
@ -145,7 +146,7 @@ class DisplayTagForm(QtGui.QDialog, Ui_DisplayTagDialog):
Delete selected custom tag. Delete selected custom tag.
""" """
if self.selected != -1: if self.selected != -1:
DisplayTags.remove_html_tag(self.selected) FormattingTags.remove_html_tag(self.selected)
self.selected = -1 self.selected = -1
self._resetTable() self._resetTable()
self._saveTable() self._saveTable()
@ -154,7 +155,7 @@ class DisplayTagForm(QtGui.QDialog, Ui_DisplayTagDialog):
""" """
Update Custom Tag details if not duplicate and save the data. Update Custom Tag details if not duplicate and save the data.
""" """
html_expands = DisplayTags.get_html_tags() html_expands = FormattingTags.get_html_tags()
if self.selected != -1: if self.selected != -1:
html = html_expands[self.selected] html = html_expands[self.selected]
tag = unicode(self.tagLineEdit.text()) tag = unicode(self.tagLineEdit.text())
@ -162,8 +163,8 @@ class DisplayTagForm(QtGui.QDialog, Ui_DisplayTagDialog):
if self._strip(html1[u'start tag']) == tag and \ if self._strip(html1[u'start tag']) == tag and \
linenumber != self.selected: linenumber != self.selected:
critical_error_message_box( critical_error_message_box(
translate('OpenLP.DisplayTagTab', 'Update Error'), translate('OpenLP.FormattingTagForm', 'Update Error'),
unicode(translate('OpenLP.DisplayTagTab', unicode(translate('OpenLP.FormattingTagForm',
'Tag %s already defined.')) % tag) 'Tag %s already defined.')) % tag)
return return
html[u'desc'] = unicode(self.descriptionLineEdit.text()) html[u'desc'] = unicode(self.descriptionLineEdit.text())
@ -177,18 +178,15 @@ class DisplayTagForm(QtGui.QDialog, Ui_DisplayTagDialog):
def _saveTable(self): def _saveTable(self):
""" """
Saves all display tags except protected ones. Saves all formatting tags except protected ones.
""" """
tags = [] tags = []
for tag in DisplayTags.get_html_tags(): for tag in FormattingTags.get_html_tags():
if not tag[u'protected']: if not tag[u'protected']:
tags.append(tag) tags.append(tag)
if tags: # Formatting Tags were also known as display tags.
QtCore.QSettings().setValue(u'displayTags/html_tags', QtCore.QSettings().setValue(u'displayTags/html_tags',
QtCore.QVariant(cPickle.dumps(tags))) QtCore.QVariant(cPickle.dumps(tags) if tags else u''))
else:
QtCore.QSettings().setValue(u'displayTags/html_tags',
QtCore.QVariant(u''))
def _resetTable(self): def _resetTable(self):
""" """
@ -199,7 +197,7 @@ class DisplayTagForm(QtGui.QDialog, Ui_DisplayTagDialog):
self.newPushButton.setEnabled(True) self.newPushButton.setEnabled(True)
self.savePushButton.setEnabled(False) self.savePushButton.setEnabled(False)
self.deletePushButton.setEnabled(False) self.deletePushButton.setEnabled(False)
for linenumber, html in enumerate(DisplayTags.get_html_tags()): for linenumber, html in enumerate(FormattingTags.get_html_tags()):
self.tagTableWidget.setRowCount( self.tagTableWidget.setRowCount(
self.tagTableWidget.rowCount() + 1) self.tagTableWidget.rowCount() + 1)
self.tagTableWidget.setItem(linenumber, 0, self.tagTableWidget.setItem(linenumber, 0,

View File

@ -48,13 +48,13 @@ class MainDisplay(QtGui.QGraphicsView):
""" """
This is the display screen. This is the display screen.
""" """
def __init__(self, parent, image_manager, live): def __init__(self, parent, imageManager, live):
if live: if live:
QtGui.QGraphicsView.__init__(self) QtGui.QGraphicsView.__init__(self)
else: else:
QtGui.QGraphicsView.__init__(self, parent) QtGui.QGraphicsView.__init__(self, parent)
self.isLive = live self.isLive = live
self.image_manager = image_manager self.imageManager = imageManager
self.screens = ScreenList.get_instance() self.screens = ScreenList.get_instance()
self.alertTab = None self.alertTab = None
self.hideMode = None self.hideMode = None
@ -188,7 +188,7 @@ class MainDisplay(QtGui.QGraphicsView):
while not self.webLoaded: while not self.webLoaded:
Receiver.send_message(u'openlp_process_events') Receiver.send_message(u'openlp_process_events')
self.setGeometry(self.screen[u'size']) self.setGeometry(self.screen[u'size'])
self.frame.evaluateJavaScript(u'show_text("%s")' % \ self.frame.evaluateJavaScript(u'show_text("%s")' %
slide.replace(u'\\', u'\\\\').replace(u'\"', u'\\\"')) slide.replace(u'\\', u'\\\\').replace(u'\"', u'\\\"'))
return self.preview() return self.preview()
@ -232,7 +232,7 @@ class MainDisplay(QtGui.QGraphicsView):
""" """
API for replacement backgrounds so Images are added directly to cache API for replacement backgrounds so Images are added directly to cache
""" """
self.image_manager.add_image(name, path) self.imageManager.add_image(name, path)
if hasattr(self, u'serviceItem'): if hasattr(self, u'serviceItem'):
self.override[u'image'] = name self.override[u'image'] = name
self.override[u'theme'] = self.serviceItem.themedata.theme_name self.override[u'theme'] = self.serviceItem.themedata.theme_name
@ -249,7 +249,7 @@ class MainDisplay(QtGui.QGraphicsView):
The name of the image to be displayed The name of the image to be displayed
""" """
log.debug(u'image to display') log.debug(u'image to display')
image = self.image_manager.get_image_bytes(name) image = self.imageManager.get_image_bytes(name)
self.resetVideo() self.resetVideo()
self.displayImage(image) self.displayImage(image)
return self.preview() return self.preview()
@ -482,13 +482,13 @@ class MainDisplay(QtGui.QGraphicsView):
self.override = {} self.override = {}
else: else:
# replace the background # replace the background
background = self.image_manager. \ background = self.imageManager. \
get_image_bytes(self.override[u'image']) get_image_bytes(self.override[u'image'])
if self.serviceItem.themedata.background_filename: if self.serviceItem.themedata.background_filename:
self.serviceItem.bg_image_bytes = self.image_manager. \ self.serviceItem.bg_image_bytes = self.imageManager. \
get_image_bytes(self.serviceItem.themedata.theme_name) get_image_bytes(self.serviceItem.themedata.theme_name)
if image: if image:
image_bytes = self.image_manager.get_image_bytes(image) image_bytes = self.imageManager.get_image_bytes(image)
else: else:
image_bytes = None image_bytes = None
html = build_html(self.serviceItem, self.screen, self.alertTab, html = build_html(self.serviceItem, self.screen, self.alertTab,

View File

@ -33,15 +33,17 @@ from tempfile import gettempdir
from PyQt4 import QtCore, QtGui from PyQt4 import QtCore, QtGui
from openlp.core.lib import Renderer, build_icon, OpenLPDockWidget, \ from openlp.core.lib import Renderer, build_icon, OpenLPDockWidget, \
PluginManager, Receiver, translate, ImageManager PluginManager, Receiver, translate, ImageManager, PluginStatus
from openlp.core.lib.ui import UiStrings, base_action, checkable_action, \ from openlp.core.lib.ui import UiStrings, base_action, checkable_action, \
icon_action, shortcut_action icon_action, shortcut_action
from openlp.core.ui import AboutForm, SettingsForm, ServiceManager, \ from openlp.core.ui import AboutForm, SettingsForm, ServiceManager, \
ThemeManager, SlideController, PluginForm, MediaDockManager, \ ThemeManager, SlideController, PluginForm, MediaDockManager, \
ShortcutListForm, DisplayTagForm ShortcutListForm, FormattingTagForm
from openlp.core.utils import AppLocation, add_actions, LanguageManager, \ from openlp.core.utils import AppLocation, add_actions, LanguageManager, \
get_application_version, delete_file get_application_version, delete_file
from openlp.core.utils.actions import ActionList, CategoryOrder from openlp.core.utils.actions import ActionList, CategoryOrder
from openlp.core.ui.firsttimeform import FirstTimeForm
from openlp.core.ui import ScreenList
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -107,6 +109,8 @@ class Ui_MainWindow(object):
self.menuBar.setObjectName(u'menuBar') self.menuBar.setObjectName(u'menuBar')
self.fileMenu = QtGui.QMenu(self.menuBar) self.fileMenu = QtGui.QMenu(self.menuBar)
self.fileMenu.setObjectName(u'fileMenu') self.fileMenu.setObjectName(u'fileMenu')
self.recentFilesMenu = QtGui.QMenu(self.fileMenu)
self.recentFilesMenu.setObjectName(u'recentFilesMenu')
self.fileImportMenu = QtGui.QMenu(self.fileMenu) self.fileImportMenu = QtGui.QMenu(self.fileMenu)
self.fileImportMenu.setObjectName(u'fileImportMenu') self.fileImportMenu.setObjectName(u'fileImportMenu')
self.fileExportMenu = QtGui.QMenu(self.fileMenu) self.fileExportMenu = QtGui.QMenu(self.fileMenu)
@ -244,6 +248,9 @@ class Ui_MainWindow(object):
self.toolsOpenDataFolder = icon_action(mainWindow, self.toolsOpenDataFolder = icon_action(mainWindow,
u'toolsOpenDataFolder', u':/general/general_open.png', u'toolsOpenDataFolder', u':/general/general_open.png',
category=UiStrings().Tools) category=UiStrings().Tools)
self.toolsFirstTimeWizard = icon_action(mainWindow,
u'toolsFirstTimeWizard', u':/general/general_revert.png',
category=UiStrings().Tools)
self.updateThemeImages = base_action(mainWindow, self.updateThemeImages = base_action(mainWindow,
u'updateThemeImages', category=UiStrings().Tools) u'updateThemeImages', category=UiStrings().Tools)
action_list.add_category(UiStrings().Settings, action_list.add_category(UiStrings().Settings,
@ -269,7 +276,8 @@ class Ui_MainWindow(object):
u'settingsShortcutsItem', u'settingsShortcutsItem',
u':/system/system_configure_shortcuts.png', u':/system/system_configure_shortcuts.png',
category=UiStrings().Settings) category=UiStrings().Settings)
self.displayTagItem = icon_action(mainWindow, # Formatting Tags were also known as display tags.
self.formattingTagItem = icon_action(mainWindow,
u'displayTagItem', u':/system/tag_editor.png', u'displayTagItem', u':/system/tag_editor.png',
category=UiStrings().Settings) category=UiStrings().Settings)
self.settingsConfigureItem = icon_action(mainWindow, self.settingsConfigureItem = icon_action(mainWindow,
@ -296,10 +304,11 @@ class Ui_MainWindow(object):
(self.importThemeItem, self.importLanguageItem)) (self.importThemeItem, self.importLanguageItem))
add_actions(self.fileExportMenu, add_actions(self.fileExportMenu,
(self.exportThemeItem, self.exportLanguageItem)) (self.exportThemeItem, self.exportLanguageItem))
self.fileMenuActions = (self.fileNewItem, self.fileOpenItem, add_actions(self.fileMenu, (self.fileNewItem, self.fileOpenItem,
self.fileSaveItem, self.fileSaveAsItem, None, self.fileSaveItem, self.fileSaveAsItem,
self.printServiceOrderItem, None, self.fileImportMenu.menuAction(), self.recentFilesMenu.menuAction(), None,
self.fileExportMenu.menuAction(), self.fileExitItem) self.fileImportMenu.menuAction(), self.fileExportMenu.menuAction(),
None, self.printServiceOrderItem, self.fileExitItem))
add_actions(self.viewModeMenu, (self.modeDefaultItem, add_actions(self.viewModeMenu, (self.modeDefaultItem,
self.modeSetupItem, self.modeLiveItem)) self.modeSetupItem, self.modeLiveItem))
add_actions(self.viewMenu, (self.viewModeMenu.menuAction(), add_actions(self.viewMenu, (self.viewModeMenu.menuAction(),
@ -315,14 +324,15 @@ class Ui_MainWindow(object):
add_actions(self.settingsMenu, (self.settingsPluginListItem, add_actions(self.settingsMenu, (self.settingsPluginListItem,
self.settingsLanguageMenu.menuAction(), None, self.settingsLanguageMenu.menuAction(), None,
self.settingsConfigureItem, self.settingsShortcutsItem, self.settingsConfigureItem, self.settingsShortcutsItem,
self.displayTagItem)) self.formattingTagItem))
else: else:
add_actions(self.settingsMenu, (self.settingsPluginListItem, add_actions(self.settingsMenu, (self.settingsPluginListItem,
self.settingsLanguageMenu.menuAction(), None, self.settingsLanguageMenu.menuAction(), None,
self.displayTagItem, self.settingsShortcutsItem, self.formattingTagItem, self.settingsShortcutsItem,
self.settingsConfigureItem)) self.settingsConfigureItem))
add_actions(self.toolsMenu, (self.toolsAddToolItem, None)) add_actions(self.toolsMenu, (self.toolsAddToolItem, None))
add_actions(self.toolsMenu, (self.toolsOpenDataFolder, None)) add_actions(self.toolsMenu, (self.toolsOpenDataFolder, None))
add_actions(self.toolsMenu, (self.toolsFirstTimeWizard, None))
add_actions(self.toolsMenu, [self.updateThemeImages]) add_actions(self.toolsMenu, [self.updateThemeImages])
if os.name == u'nt': if os.name == u'nt':
add_actions(self.helpMenu, (self.offlineHelpItem, add_actions(self.helpMenu, (self.offlineHelpItem,
@ -339,7 +349,7 @@ class Ui_MainWindow(object):
self.mediaToolBox.setCurrentIndex(0) self.mediaToolBox.setCurrentIndex(0)
# Connect up some signals and slots # Connect up some signals and slots
QtCore.QObject.connect(self.fileMenu, QtCore.QObject.connect(self.fileMenu,
QtCore.SIGNAL(u'aboutToShow()'), self.updateFileMenu) QtCore.SIGNAL(u'aboutToShow()'), self.updateRecentFilesMenu)
QtCore.QMetaObject.connectSlotsByName(mainWindow) QtCore.QMetaObject.connectSlotsByName(mainWindow)
# Hide the entry, as it does not have any functionality yet. # Hide the entry, as it does not have any functionality yet.
self.toolsAddToolItem.setVisible(False) self.toolsAddToolItem.setVisible(False)
@ -356,6 +366,8 @@ class Ui_MainWindow(object):
self.fileMenu.setTitle(translate('OpenLP.MainWindow', '&File')) self.fileMenu.setTitle(translate('OpenLP.MainWindow', '&File'))
self.fileImportMenu.setTitle(translate('OpenLP.MainWindow', '&Import')) self.fileImportMenu.setTitle(translate('OpenLP.MainWindow', '&Import'))
self.fileExportMenu.setTitle(translate('OpenLP.MainWindow', '&Export')) self.fileExportMenu.setTitle(translate('OpenLP.MainWindow', '&Export'))
self.recentFilesMenu.setTitle(
translate('OpenLP.MainWindow', '&Recent Files'))
self.viewMenu.setTitle(translate('OpenLP.MainWindow', '&View')) self.viewMenu.setTitle(translate('OpenLP.MainWindow', '&View'))
self.viewModeMenu.setTitle(translate('OpenLP.MainWindow', 'M&ode')) self.viewModeMenu.setTitle(translate('OpenLP.MainWindow', 'M&ode'))
self.toolsMenu.setTitle(translate('OpenLP.MainWindow', '&Tools')) self.toolsMenu.setTitle(translate('OpenLP.MainWindow', '&Tools'))
@ -403,8 +415,8 @@ class Ui_MainWindow(object):
translate('OpenLP.MainWindow', '&Language')) translate('OpenLP.MainWindow', '&Language'))
self.settingsShortcutsItem.setText( self.settingsShortcutsItem.setText(
translate('OpenLP.MainWindow', 'Configure &Shortcuts...')) translate('OpenLP.MainWindow', 'Configure &Shortcuts...'))
self.displayTagItem.setText( self.formattingTagItem.setText(
translate('OpenLP.MainWindow', '&Configure Display Tags')) translate('OpenLP.MainWindow', '&Configure Formatting Tags...'))
self.settingsConfigureItem.setText( self.settingsConfigureItem.setText(
translate('OpenLP.MainWindow', '&Configure OpenLP...')) translate('OpenLP.MainWindow', '&Configure OpenLP...'))
self.viewMediaManagerItem.setText( self.viewMediaManagerItem.setText(
@ -471,6 +483,10 @@ class Ui_MainWindow(object):
translate('OpenLP.MainWindow', 'Open &Data Folder...')) translate('OpenLP.MainWindow', 'Open &Data Folder...'))
self.toolsOpenDataFolder.setStatusTip(translate('OpenLP.MainWindow', self.toolsOpenDataFolder.setStatusTip(translate('OpenLP.MainWindow',
'Open the folder where songs, bibles and other data resides.')) 'Open the folder where songs, bibles and other data resides.'))
self.toolsFirstTimeWizard.setText(
translate('OpenLP.MainWindow', 'Re-run First Time Wizard'))
self.toolsFirstTimeWizard.setStatusTip(translate('OpenLP.MainWindow',
'Re-run the First Time Wizard, importing songs, Bibles and themes.'))
self.updateThemeImages.setText( self.updateThemeImages.setText(
translate('OpenLP.MainWindow', 'Update Theme Images')) translate('OpenLP.MainWindow', 'Update Theme Images'))
self.updateThemeImages.setStatusTip( self.updateThemeImages.setStatusTip(
@ -511,7 +527,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
self.serviceNotSaved = False self.serviceNotSaved = False
self.aboutForm = AboutForm(self) self.aboutForm = AboutForm(self)
self.settingsForm = SettingsForm(self, self) self.settingsForm = SettingsForm(self, self)
self.displayTagForm = DisplayTagForm(self) self.formattingTagForm = FormattingTagForm(self)
self.shortcutForm = ShortcutListForm(self) self.shortcutForm = ShortcutListForm(self)
self.recentFiles = QtCore.QStringList() self.recentFiles = QtCore.QStringList()
# Set up the path with plugins # Set up the path with plugins
@ -523,8 +539,8 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
self.setupUi(self) self.setupUi(self)
# Load settings after setupUi so default UI sizes are overwritten # Load settings after setupUi so default UI sizes are overwritten
self.loadSettings() self.loadSettings()
# Once settings are loaded update FileMenu with recentFiles # Once settings are loaded update the menu with the recent files.
self.updateFileMenu() self.updateRecentFilesMenu()
self.pluginForm = PluginForm(self) self.pluginForm = PluginForm(self)
# Set up signals and slots # Set up signals and slots
QtCore.QObject.connect(self.importThemeItem, QtCore.QObject.connect(self.importThemeItem,
@ -546,10 +562,12 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
QtCore.SIGNAL(u'triggered()'), self.onHelpWebSiteClicked) QtCore.SIGNAL(u'triggered()'), self.onHelpWebSiteClicked)
QtCore.QObject.connect(self.toolsOpenDataFolder, QtCore.QObject.connect(self.toolsOpenDataFolder,
QtCore.SIGNAL(u'triggered()'), self.onToolsOpenDataFolderClicked) QtCore.SIGNAL(u'triggered()'), self.onToolsOpenDataFolderClicked)
QtCore.QObject.connect(self.toolsFirstTimeWizard,
QtCore.SIGNAL(u'triggered()'), self.onFirstTimeWizardClicked)
QtCore.QObject.connect(self.updateThemeImages, QtCore.QObject.connect(self.updateThemeImages,
QtCore.SIGNAL(u'triggered()'), self.onUpdateThemeImages) QtCore.SIGNAL(u'triggered()'), self.onUpdateThemeImages)
QtCore.QObject.connect(self.displayTagItem, QtCore.QObject.connect(self.formattingTagItem,
QtCore.SIGNAL(u'triggered()'), self.onDisplayTagItemClicked) QtCore.SIGNAL(u'triggered()'), self.onFormattingTagItemClicked)
QtCore.QObject.connect(self.settingsConfigureItem, QtCore.QObject.connect(self.settingsConfigureItem,
QtCore.SIGNAL(u'triggered()'), self.onSettingsConfigureItemClicked) QtCore.SIGNAL(u'triggered()'), self.onSettingsConfigureItemClicked)
QtCore.QObject.connect(self.settingsShortcutsItem, QtCore.QObject.connect(self.settingsShortcutsItem,
@ -714,6 +732,45 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
delete_file(os.path.join(temp_dir, filename)) delete_file(os.path.join(temp_dir, filename))
os.removedirs(temp_dir) os.removedirs(temp_dir)
def onFirstTimeWizardClicked(self):
"""
Re-run the first time wizard. Prompts the user for run confirmation
If wizard is run, songs, bibles and themes are imported. The default
theme is changed (if necessary). The plugins in pluginmanager are
set active/in-active to match the selection in the wizard.
"""
answer = QtGui.QMessageBox.warning(self,
translate('OpenLP.MainWindow', 'Re-run First Time Wizard?'),
translate('OpenLP.MainWindow',
'Are you sure you want to re-run the First Time Wizard?\n\n'
'Re-running this wizard may make changes to your current '
'OpenLP configuration and possibly add songs to your '
'existing songs list and change your default theme.'),
QtGui.QMessageBox.StandardButtons(
QtGui.QMessageBox.Yes |
QtGui.QMessageBox.No),
QtGui.QMessageBox.No)
if answer == QtGui.QMessageBox.No:
return
Receiver.send_message(u'cursor_busy')
screens = ScreenList.get_instance()
if FirstTimeForm(screens, self).exec_() == QtGui.QDialog.Accepted:
self.firstTime()
for plugin in self.pluginManager.plugins:
self.activePlugin = plugin
oldStatus = self.activePlugin.status
self.activePlugin.setStatus()
if oldStatus != self.activePlugin.status:
if self.activePlugin.status == PluginStatus.Active:
self.activePlugin.toggleStatus(PluginStatus.Active)
self.activePlugin.appStartup()
else:
self.activePlugin.toggleStatus(PluginStatus.Inactive)
self.themeManagerContents.configUpdated()
self.themeManagerContents.loadThemes(True)
Receiver.send_message(u'theme_update_global',
self.themeManagerContents.global_theme)
def blankCheck(self): def blankCheck(self):
""" """
Check and display message if screen blank on setup. Check and display message if screen blank on setup.
@ -788,11 +845,11 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
""" """
self.themeManagerContents.updatePreviewImages() self.themeManagerContents.updatePreviewImages()
def onDisplayTagItemClicked(self): def onFormattingTagItemClicked(self):
""" """
Show the Settings dialog Show the Settings dialog
""" """
self.displayTagForm.exec_() self.formattingTagForm.exec_()
def onSettingsConfigureItemClicked(self): def onSettingsConfigureItemClicked(self):
""" """
@ -1085,30 +1142,36 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
QtCore.QVariant(self.controlSplitter.saveState())) QtCore.QVariant(self.controlSplitter.saveState()))
settings.endGroup() settings.endGroup()
def updateFileMenu(self): def updateRecentFilesMenu(self):
""" """
Updates the file menu with the latest list of service files accessed. Updates the recent file menu with the latest list of service files
accessed.
""" """
recentFileCount = QtCore.QSettings().value( recentFileCount = QtCore.QSettings().value(
u'advanced/recent file count', QtCore.QVariant(4)).toInt()[0] u'advanced/recent file count', QtCore.QVariant(4)).toInt()[0]
self.fileMenu.clear()
add_actions(self.fileMenu, self.fileMenuActions[:-1])
existingRecentFiles = [recentFile for recentFile in self.recentFiles existingRecentFiles = [recentFile for recentFile in self.recentFiles
if QtCore.QFile.exists(recentFile)] if QtCore.QFile.exists(recentFile)]
recentFilesToDisplay = existingRecentFiles[0:recentFileCount] recentFilesToDisplay = existingRecentFiles[0:recentFileCount]
if recentFilesToDisplay: self.recentFilesMenu.clear()
self.fileMenu.addSeparator() for fileId, filename in enumerate(recentFilesToDisplay):
for fileId, filename in enumerate(recentFilesToDisplay): log.debug('Recent file name: %s', filename)
log.debug('Recent file name: %s', filename) action = base_action(self, u'')
action = base_action(self, u'') action.setText(u'&%d %s' %
action.setText(u'&%d %s' % (fileId + 1, QtCore.QFileInfo(filename).fileName()))
(fileId + 1, QtCore.QFileInfo(filename).fileName())) action.setData(QtCore.QVariant(filename))
action.setData(QtCore.QVariant(filename)) self.connect(action, QtCore.SIGNAL(u'triggered()'),
self.connect(action, QtCore.SIGNAL(u'triggered()'), self.serviceManagerContents.onRecentServiceClicked)
self.serviceManagerContents.onRecentServiceClicked) self.recentFilesMenu.addAction(action)
self.fileMenu.addAction(action) clearRecentFilesAction = base_action(self, u'')
self.fileMenu.addSeparator() clearRecentFilesAction.setText(
self.fileMenu.addAction(self.fileMenuActions[-1]) translate('OpenLP.MainWindow', 'Clear List',
'Clear List of recent files'))
clearRecentFilesAction.setStatusTip(
translate('OpenLP.MainWindow', 'Clear the list of recent files.'))
add_actions(self.recentFilesMenu, (None, clearRecentFilesAction))
self.connect(clearRecentFilesAction, QtCore.SIGNAL(u'triggered()'),
self.recentFiles.clear)
clearRecentFilesAction.setEnabled(not self.recentFiles.isEmpty())
def addRecentFile(self, filename): def addRecentFile(self, filename):
""" """

View File

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

View File

@ -108,7 +108,7 @@ class Ui_PrintServiceDialog(object):
self.footerLabel = QtGui.QLabel(self.optionsWidget) self.footerLabel = QtGui.QLabel(self.optionsWidget)
self.footerLabel.setObjectName(u'footerLabel') self.footerLabel.setObjectName(u'footerLabel')
self.optionsLayout.addWidget(self.footerLabel) self.optionsLayout.addWidget(self.footerLabel)
self.footerTextEdit = SpellTextEdit(self.optionsWidget) self.footerTextEdit = SpellTextEdit(self.optionsWidget, False)
self.footerTextEdit.setObjectName(u'footerTextEdit') self.footerTextEdit.setObjectName(u'footerTextEdit')
self.optionsLayout.addWidget(self.footerTextEdit) self.optionsLayout.addWidget(self.footerTextEdit)
self.optionsGroupBox = QtGui.QGroupBox() self.optionsGroupBox = QtGui.QGroupBox()

View File

@ -24,6 +24,7 @@
# with this program; if not, write to the Free Software Foundation, Inc., 59 # # with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA # # Temple Place, Suite 330, Boston, MA 02111-1307 USA #
############################################################################### ###############################################################################
import cgi
import datetime import datetime
import os import os
@ -183,7 +184,7 @@ class PrintServiceForm(QtGui.QDialog, Ui_PrintServiceDialog):
self._addElement(u'style', custom_css, html_data.head, self._addElement(u'style', custom_css, html_data.head,
attribute=(u'type', u'text/css')) attribute=(u'type', u'text/css'))
self._addElement(u'body', parent=html_data) self._addElement(u'body', parent=html_data)
self._addElement(u'h1', unicode(self.titleLineEdit.text()), self._addElement(u'h1', cgi.escape(unicode(self.titleLineEdit.text())),
html_data.body, classId=u'serviceTitle') html_data.body, classId=u'serviceTitle')
for index, item in enumerate(self.serviceManager.serviceItems): for index, item in enumerate(self.serviceManager.serviceItems):
self._addPreviewItem(html_data.body, item[u'service_item'], index) self._addPreviewItem(html_data.body, item[u'service_item'], index)
@ -193,8 +194,9 @@ class PrintServiceForm(QtGui.QDialog, Ui_PrintServiceDialog):
classId=u'customNotes') classId=u'customNotes')
self._addElement(u'span', translate('OpenLP.ServiceManager', self._addElement(u'span', translate('OpenLP.ServiceManager',
'Custom Service Notes: '), div, classId=u'customNotesTitle') 'Custom Service Notes: '), div, classId=u'customNotesTitle')
self._addElement(u'span', self.footerTextEdit.toPlainText(), div, self._addElement(u'span',
classId=u'customNotesText') cgi.escape(self.footerTextEdit.toPlainText()),
div, classId=u'customNotesText')
self.document.setHtml(html.tostring(html_data)) self.document.setHtml(html.tostring(html_data))
self.previewWidget.updatePreview() self.previewWidget.updatePreview()
@ -204,8 +206,8 @@ class PrintServiceForm(QtGui.QDialog, Ui_PrintServiceDialog):
item_title = self._addElement(u'h2', parent=div, classId=u'itemTitle') item_title = self._addElement(u'h2', parent=div, classId=u'itemTitle')
self._addElement(u'img', parent=item_title, self._addElement(u'img', parent=item_title,
attribute=(u'src', item.icon)) attribute=(u'src', item.icon))
self._addElement(u'span', u'&nbsp;' + item.get_display_title(), self._addElement(u'span',
item_title) u'&nbsp;' + cgi.escape(item.get_display_title()), item_title)
if self.slideTextCheckBox.isChecked(): if self.slideTextCheckBox.isChecked():
# Add the text of the service item. # Add the text of the service item.
if item.is_text(): if item.is_text():
@ -230,8 +232,9 @@ class PrintServiceForm(QtGui.QDialog, Ui_PrintServiceDialog):
foot_text = item.foot_text foot_text = item.foot_text
foot_text = foot_text.partition(u'<br>')[2] foot_text = foot_text.partition(u'<br>')[2]
if foot_text: if foot_text:
foot = self._addElement(u'div', foot_text, parent=div, foot_text = cgi.escape(foot_text.replace(u'<br>', u'\n'))
classId=u'itemFooter') self._addElement(u'div', foot_text.replace(u'\n', u'<br>'),
parent=div, classId=u'itemFooter')
# Add service items' notes. # Add service items' notes.
if self.notesCheckBox.isChecked(): if self.notesCheckBox.isChecked():
if item.notes: if item.notes:
@ -239,8 +242,8 @@ class PrintServiceForm(QtGui.QDialog, Ui_PrintServiceDialog):
self._addElement(u'span', self._addElement(u'span',
translate('OpenLP.ServiceManager', 'Notes: '), p, translate('OpenLP.ServiceManager', 'Notes: '), p,
classId=u'itemNotesTitle') classId=u'itemNotesTitle')
notes = self._addElement(u'span', self._addElement(u'span',
item.notes.replace(u'\n', u'<br />'), p, cgi.escape(unicode(item.notes)).replace(u'\n', u'<br>'), p,
classId=u'itemNotesText') classId=u'itemNotesText')
# Add play length of media files. # Add play length of media files.
if item.is_media() and self.metaDataCheckBox.isChecked(): if item.is_media() and self.metaDataCheckBox.isChecked():

View File

@ -79,7 +79,7 @@ class ServiceItemEditForm(QtGui.QDialog, Ui_ServiceItemEditDialog):
if not item: if not item:
return return
row = self.listWidget.row(item) row = self.listWidget.row(item)
self.itemList.remove(self.itemList[row]) self.itemList.pop(row)
self.loadData() self.loadData()
if row == self.listWidget.count(): if row == self.listWidget.count():
self.listWidget.setCurrentRow(row - 1) self.listWidget.setCurrentRow(row - 1)
@ -109,7 +109,7 @@ class ServiceItemEditForm(QtGui.QDialog, Ui_ServiceItemEditDialog):
return return
row = self.listWidget.row(item) row = self.listWidget.row(item)
temp = self.itemList[row] temp = self.itemList[row]
self.itemList.remove(self.itemList[row]) self.itemList.pop(row)
if direction == u'up': if direction == u'up':
row -= 1 row -= 1
else: else:

View File

@ -24,6 +24,7 @@
# with this program; if not, write to the Free Software Foundation, Inc., 59 # # with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA # # Temple Place, Suite 330, Boston, MA 02111-1307 USA #
############################################################################### ###############################################################################
import cgi
import cPickle import cPickle
import logging import logging
import os import os
@ -408,20 +409,33 @@ class ServiceManager(QtGui.QWidget):
return False return False
self.newFile() self.newFile()
def onLoadServiceClicked(self): def onLoadServiceClicked(self, loadFile=None):
"""
Loads the service file and saves the existing one it there is one
unchanged
``loadFile``
The service file to the loaded. Will be None is from menu so
selection will be required.
"""
if self.isModified(): if self.isModified():
result = self.saveModifiedService() result = self.saveModifiedService()
if result == QtGui.QMessageBox.Cancel: if result == QtGui.QMessageBox.Cancel:
return False return False
elif result == QtGui.QMessageBox.Save: elif result == QtGui.QMessageBox.Save:
self.saveFile() self.saveFile()
fileName = unicode(QtGui.QFileDialog.getOpenFileName(self.mainwindow, if not loadFile:
translate('OpenLP.ServiceManager', 'Open File'), fileName = unicode(QtGui.QFileDialog.getOpenFileName(
SettingsManager.get_last_dir( self.mainwindow,
self.mainwindow.serviceSettingsSection), translate('OpenLP.ServiceManager', 'Open File'),
translate('OpenLP.ServiceManager', 'OpenLP Service Files (*.osz)'))) SettingsManager.get_last_dir(
if not fileName: self.mainwindow.serviceSettingsSection),
return False translate('OpenLP.ServiceManager',
'OpenLP Service Files (*.osz)')))
if not fileName:
return False
else:
fileName = loadFile
SettingsManager.set_last_dir(self.mainwindow.serviceSettingsSection, SettingsManager.set_last_dir(self.mainwindow.serviceSettingsSection,
split_filename(fileName)[0]) split_filename(fileName)[0])
self.loadFile(fileName) self.loadFile(fileName)
@ -474,6 +488,7 @@ class ServiceManager(QtGui.QWidget):
item[u'service_item'].get_service_repr()}) item[u'service_item'].get_service_repr()})
if not item[u'service_item'].uses_file(): if not item[u'service_item'].uses_file():
continue continue
skipMissing = False
for frame in item[u'service_item'].get_frames(): for frame in item[u'service_item'].get_frames():
if item[u'service_item'].is_image(): if item[u'service_item'].is_image():
path_from = frame[u'path'] path_from = frame[u'path']
@ -482,25 +497,29 @@ class ServiceManager(QtGui.QWidget):
# Only write a file once # Only write a file once
if path_from in write_list: if path_from in write_list:
continue continue
file_size = os.path.getsize(path_from) if not os.path.exists(path_from):
size_limit = 52428800 # 50MiB if not skipMissing:
#if file_size > size_limit: Receiver.send_message(u'cursor_normal')
# # File exeeds size_limit bytes, ask user title = unicode(translate('OpenLP.ServiceManager',
# message = unicode(translate('OpenLP.ServiceManager', 'Service File Missing'))
# 'Do you want to include \n%.1f MB file "%s"\n' message = unicode(translate('OpenLP.ServiceManager',
# 'into the service file?\nThis may take some time.\n\n' 'File missing from service\n\n %s \n\n'
# 'Please note that you need to\ntake care of that file' 'Continue saving?' % path_from ))
# ' yourself,\nif you leave it out.')) % \ answer = QtGui.QMessageBox.critical(self, title,
# (file_size/1048576, os.path.split(path_from)[1]) message,
# ans = QtGui.QMessageBox.question(self.mainwindow, QtGui.QMessageBox.StandardButtons(
# translate('OpenLP.ServiceManager', 'Including Large ' QtGui.QMessageBox.Yes | QtGui.QMessageBox.No |
# 'File'), message, QtGui.QMessageBox.StandardButtons( QtGui.QMessageBox.YesToAll))
# QtGui.QMessageBox.Ok|QtGui.QMessageBox.Cancel), if answer == QtGui.QMessageBox.No:
# QtGui.QMessageBox.Ok) self.mainwindow.finishedProgressBar()
# if ans == QtGui.QMessageBox.Cancel: return False
# continue if answer == QtGui.QMessageBox.YesToAll:
write_list.append(path_from) skipMissing = True
total_size += file_size Receiver.send_message(u'cursor_busy')
else:
file_size = os.path.getsize(path_from)
write_list.append(path_from)
total_size += file_size
log.debug(u'ServiceManager.saveFile - ZIP contents size is %i bytes' % log.debug(u'ServiceManager.saveFile - ZIP contents size is %i bytes' %
total_size) total_size)
service_content = cPickle.dumps(service) service_content = cPickle.dumps(service)
@ -701,6 +720,9 @@ class ServiceManager(QtGui.QWidget):
self.setModified() self.setModified()
def onStartTimeForm(self): def onStartTimeForm(self):
"""
Opens a dialog to type in service item notes.
"""
item = self.findServiceItem()[0] item = self.findServiceItem()[0]
self.startTimeForm.item = self.serviceItems[item] self.startTimeForm.item = self.serviceItems[item]
if self.startTimeForm.exec_(): if self.startTimeForm.exec_():
@ -939,11 +961,11 @@ class ServiceManager(QtGui.QWidget):
if serviceitem.notes: if serviceitem.notes:
tips.append(u'<strong>%s: </strong> %s' % tips.append(u'<strong>%s: </strong> %s' %
(unicode(translate('OpenLP.ServiceManager', 'Notes')), (unicode(translate('OpenLP.ServiceManager', 'Notes')),
unicode(serviceitem.notes))) cgi.escape(unicode(serviceitem.notes))))
if item[u'service_item'] \ if item[u'service_item'] \
.is_capable(ItemCapabilities.AllowsVariableStartTime): .is_capable(ItemCapabilities.AllowsVariableStartTime):
tips.append(item[u'service_item'].get_media_time()) tips.append(item[u'service_item'].get_media_time())
treewidgetitem.setToolTip(0, u'<br />'.join(tips)) treewidgetitem.setToolTip(0, u'<br>'.join(tips))
treewidgetitem.setData(0, QtCore.Qt.UserRole, treewidgetitem.setData(0, QtCore.Qt.UserRole,
QtCore.QVariant(item[u'order'])) QtCore.QVariant(item[u'order']))
treewidgetitem.setSelected(item[u'selected']) treewidgetitem.setSelected(item[u'selected'])
@ -1239,7 +1261,14 @@ class ServiceManager(QtGui.QWidget):
Handle of the event pint passed Handle of the event pint passed
""" """
link = event.mimeData() link = event.mimeData()
if link.hasText(): if event.mimeData().hasUrls():
event.setDropAction(QtCore.Qt.CopyAction)
event.accept()
for url in event.mimeData().urls():
filename = unicode(url.toLocalFile())
if filename.endswith(u'.osz'):
self.onLoadServiceClicked(filename)
elif event.mimeData().hasText():
plugin = unicode(event.mimeData().text()) plugin = unicode(event.mimeData().text())
item = self.serviceManagerList.itemAt(event.pos()) item = self.serviceManagerList.itemAt(event.pos())
# ServiceManager started the drag and drop # ServiceManager started the drag and drop

View File

@ -27,7 +27,7 @@
from PyQt4 import QtCore, QtGui from PyQt4 import QtCore, QtGui
from openlp.core.lib import translate from openlp.core.lib import translate, SpellTextEdit
from openlp.core.lib.ui import create_accept_reject_button_box from openlp.core.lib.ui import create_accept_reject_button_box
class ServiceNoteForm(QtGui.QDialog): class ServiceNoteForm(QtGui.QDialog):
@ -52,7 +52,7 @@ class ServiceNoteForm(QtGui.QDialog):
self.dialogLayout.setContentsMargins(8, 8, 8, 8) self.dialogLayout.setContentsMargins(8, 8, 8, 8)
self.dialogLayout.setSpacing(8) self.dialogLayout.setSpacing(8)
self.dialogLayout.setObjectName(u'verticalLayout') self.dialogLayout.setObjectName(u'verticalLayout')
self.textEdit = QtGui.QTextEdit(self) self.textEdit = SpellTextEdit(self, False)
self.textEdit.setObjectName(u'textEdit') self.textEdit.setObjectName(u'textEdit')
self.dialogLayout.addWidget(self.textEdit) self.dialogLayout.addWidget(self.textEdit)
self.dialogLayout.addWidget(create_accept_reject_button_box(self)) self.dialogLayout.addWidget(create_accept_reject_button_box(self))

View File

@ -123,7 +123,7 @@ class Ui_ShortcutListDialog(object):
def retranslateUi(self, shortcutListDialog): def retranslateUi(self, shortcutListDialog):
shortcutListDialog.setWindowTitle( shortcutListDialog.setWindowTitle(
translate('OpenLP.ShortcutListDialog', 'Customize Shortcuts')) translate('OpenLP.ShortcutListDialog', 'Configure Shortcuts'))
self.descriptionLabel.setText(translate('OpenLP.ShortcutListDialog', self.descriptionLabel.setText(translate('OpenLP.ShortcutListDialog',
'Select an action and click one of the buttons below to start ' 'Select an action and click one of the buttons below to start '
'capturing a new primary or alternate shortcut, respectively.')) 'capturing a new primary or alternate shortcut, respectively.'))

View File

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

View File

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

View File

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

View File

@ -395,6 +395,7 @@ class BibleMediaItem(MediaManagerItem):
log.debug(u'Reloading Bibles') log.debug(u'Reloading Bibles')
self.plugin.manager.reload_bibles() self.plugin.manager.reload_bibles()
self.loadBibles() self.loadBibles()
self.updateAutoCompleter()
def initialiseAdvancedBible(self, bible): def initialiseAdvancedBible(self, bible):
""" """

View File

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

View File

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

View File

@ -52,6 +52,8 @@ class ImageMediaItem(MediaManagerItem):
self.hasSearch = True self.hasSearch = True
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'live_theme_changed'), self.liveThemeChanged) QtCore.SIGNAL(u'live_theme_changed'), self.liveThemeChanged)
# Allow DnD from the desktop
self.listView.activateDnD()
def retranslateUi(self): def retranslateUi(self):
self.onNewPrompt = translate('ImagePlugin.MediaItem', self.onNewPrompt = translate('ImagePlugin.MediaItem',
@ -131,6 +133,7 @@ class ImageMediaItem(MediaManagerItem):
icon = self.iconFromFile(imageFile, thumb) icon = self.iconFromFile(imageFile, thumb)
item_name = QtGui.QListWidgetItem(filename) item_name = QtGui.QListWidgetItem(filename)
item_name.setIcon(icon) item_name.setIcon(icon)
item_name.setToolTip(imageFile)
item_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(imageFile)) item_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(imageFile))
self.listView.addItem(item_name) self.listView.addItem(item_name)
if not initialLoad: if not initialLoad:

View File

@ -39,6 +39,8 @@ from PyQt4.phonon import Phonon
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
CLAPPERBOARD = QtGui.QPixmap(u':/media/media_video.png').toImage()
class MediaMediaItem(MediaManagerItem): class MediaMediaItem(MediaManagerItem):
""" """
This is the custom media manager item for Media Slides. This is the custom media manager item for Media Slides.
@ -48,8 +50,7 @@ class MediaMediaItem(MediaManagerItem):
def __init__(self, parent, plugin, icon): def __init__(self, parent, plugin, icon):
self.IconPath = u'images/image' self.IconPath = u'images/image'
self.background = False self.background = False
self.PreviewFunction = QtGui.QPixmap( self.PreviewFunction = CLAPPERBOARD
u':/media/media_video.png').toImage()
MediaManagerItem.__init__(self, parent, plugin, icon) MediaManagerItem.__init__(self, parent, plugin, icon)
self.singleServiceItem = False self.singleServiceItem = False
self.hasSearch = True self.hasSearch = True
@ -60,6 +61,8 @@ class MediaMediaItem(MediaManagerItem):
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'openlp_phonon_creation'), QtCore.SIGNAL(u'openlp_phonon_creation'),
self.createPhonon) self.createPhonon)
# Allow DnD from the desktop
self.listView.activateDnD()
def retranslateUi(self): def retranslateUi(self):
self.onNewPrompt = translate('MediaPlugin.MediaItem', 'Select Media') self.onNewPrompt = translate('MediaPlugin.MediaItem', 'Select Media')
@ -201,17 +204,17 @@ class MediaMediaItem(MediaManagerItem):
SettingsManager.set_list(self.settingsSection, SettingsManager.set_list(self.settingsSection,
u'media', self.getFileList()) u'media', self.getFileList())
def loadList(self, files): def loadList(self, media):
# Sort the themes by its filename considering language specific # Sort the themes by its filename considering language specific
# characters. lower() is needed for windows! # characters. lower() is needed for windows!
files.sort(cmp=locale.strcoll, media.sort(cmp=locale.strcoll,
key=lambda filename: os.path.split(unicode(filename))[1].lower()) key=lambda filename: os.path.split(unicode(filename))[1].lower())
for file in files: for track in media:
filename = os.path.split(unicode(file))[1] filename = os.path.split(unicode(track))[1]
item_name = QtGui.QListWidgetItem(filename) item_name = QtGui.QListWidgetItem(filename)
img = QtGui.QPixmap(u':/media/media_video.png').toImage() item_name.setIcon(build_icon(CLAPPERBOARD))
item_name.setIcon(build_icon(img)) item_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(track))
item_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(file)) item_name.setToolTip(track)
self.listView.addItem(item_name) self.listView.addItem(item_name)
def createPhonon(self): def createPhonon(self):

View File

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

View File

@ -58,6 +58,8 @@ class PresentationMediaItem(MediaManagerItem):
self.hasSearch = True self.hasSearch = True
QtCore.QObject.connect(Receiver.get_receiver(), QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'mediaitem_presentation_rebuild'), self.rebuild) QtCore.SIGNAL(u'mediaitem_presentation_rebuild'), self.rebuild)
# Allow DnD from the desktop
self.listView.activateDnD()
def retranslateUi(self): def retranslateUi(self):
""" """
@ -205,6 +207,7 @@ class PresentationMediaItem(MediaManagerItem):
item_name = QtGui.QListWidgetItem(filename) item_name = QtGui.QListWidgetItem(filename)
item_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(file)) item_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(file))
item_name.setIcon(icon) item_name.setIcon(icon)
item_name.setToolTip(file)
self.listView.addItem(item_name) self.listView.addItem(item_name)
Receiver.send_message(u'cursor_normal') Receiver.send_message(u'cursor_normal')
if not initialLoad: if not initialLoad:

View File

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

View File

@ -150,13 +150,11 @@ class HttpResponse(object):
class HttpServer(object): class HttpServer(object):
""" """
Ability to control OpenLP via a webbrowser Ability to control OpenLP via a web browser.
e.g. http://localhost:4316/send/slidecontroller_live_next
http://localhost:4316/send/alerts_text?q=your%20alert%20text
""" """
def __init__(self, plugin): def __init__(self, plugin):
""" """
Initialise the httpserver, and start the server Initialise the httpserver, and start the server.
""" """
log.debug(u'Initialise httpserver') log.debug(u'Initialise httpserver')
self.plugin = plugin self.plugin = plugin
@ -170,9 +168,9 @@ class HttpServer(object):
def start_tcp(self): def start_tcp(self):
""" """
Start the http server, use the port in the settings default to 4316 Start the http server, use the port in the settings default to 4316.
Listen out for slide and song changes so they can be broadcast to Listen out for slide and song changes so they can be broadcast to
clients. Listen out for socket connections clients. Listen out for socket connections.
""" """
log.debug(u'Start TCP server') log.debug(u'Start TCP server')
port = QtCore.QSettings().value( port = QtCore.QSettings().value(
@ -195,20 +193,20 @@ class HttpServer(object):
def slide_change(self, row): def slide_change(self, row):
""" """
Slide change listener. Store the item and tell the clients Slide change listener. Store the item and tell the clients.
""" """
self.current_slide = row self.current_slide = row
def item_change(self, items): def item_change(self, items):
""" """
Item (song) change listener. Store the slide and tell the clients Item (song) change listener. Store the slide and tell the clients.
""" """
self.current_item = items[0] self.current_item = items[0]
def new_connection(self): def new_connection(self):
""" """
A new http connection has been made. Create a client object to handle A new http connection has been made. Create a client object to handle
communication communication.
""" """
log.debug(u'new http connection') log.debug(u'new http connection')
socket = self.server.nextPendingConnection() socket = self.server.nextPendingConnection()
@ -225,15 +223,16 @@ class HttpServer(object):
def close(self): def close(self):
""" """
Close down the http server Close down the http server.
""" """
log.debug(u'close http server') log.debug(u'close http server')
self.server.close() self.server.close()
class HttpConnection(object): class HttpConnection(object):
""" """
A single connection, this handles communication between the server A single connection, this handles communication between the server
and the client and the client.
""" """
def __init__(self, parent, socket): def __init__(self, parent, socket):
""" """
@ -287,9 +286,12 @@ class HttpConnection(object):
""" """
self.template_vars = { self.template_vars = {
'app_title': translate('RemotePlugin.Mobile', 'OpenLP 2.0 Remote'), 'app_title': translate('RemotePlugin.Mobile', 'OpenLP 2.0 Remote'),
'stage_title': translate('RemotePlugin.Mobile', 'OpenLP 2.0 Stage View'), 'stage_title': translate('RemotePlugin.Mobile',
'service_manager': translate('RemotePlugin.Mobile', 'Service Manager'), 'OpenLP 2.0 Stage View'),
'slide_controller': translate('RemotePlugin.Mobile', 'Slide Controller'), 'service_manager': translate('RemotePlugin.Mobile',
'Service Manager'),
'slide_controller': translate('RemotePlugin.Mobile',
'Slide Controller'),
'alerts': translate('RemotePlugin.Mobile', 'Alerts'), 'alerts': translate('RemotePlugin.Mobile', 'Alerts'),
'search': translate('RemotePlugin.Mobile', 'Search'), 'search': translate('RemotePlugin.Mobile', 'Search'),
'back': translate('RemotePlugin.Mobile', 'Back'), 'back': translate('RemotePlugin.Mobile', 'Back'),
@ -301,7 +303,8 @@ class HttpConnection(object):
'text': translate('RemotePlugin.Mobile', 'Text'), 'text': translate('RemotePlugin.Mobile', 'Text'),
'show_alert': translate('RemotePlugin.Mobile', 'Show Alert'), 'show_alert': translate('RemotePlugin.Mobile', 'Show Alert'),
'go_live': translate('RemotePlugin.Mobile', 'Go Live'), 'go_live': translate('RemotePlugin.Mobile', 'Go Live'),
'add_to_service': translate('RemotePlugin.Mobile', 'Add To Service'), 'add_to_service': translate('RemotePlugin.Mobile',
'Add to Service'),
'no_results': translate('RemotePlugin.Mobile', 'No Results'), 'no_results': translate('RemotePlugin.Mobile', 'No Results'),
'options': translate('RemotePlugin.Mobile', 'Options') 'options': translate('RemotePlugin.Mobile', 'Options')
} }
@ -397,7 +400,7 @@ class HttpConnection(object):
if self.parent.current_item else u'' if self.parent.current_item else u''
} }
return HttpResponse(json.dumps({u'results': result}), return HttpResponse(json.dumps({u'results': result}),
{u'Content-Type': u'application/json'}) {u'Content-Type': u'application/json'})
def display(self, action): def display(self, action):
""" """
@ -483,10 +486,11 @@ class HttpConnection(object):
def pluginInfo(self, action): def pluginInfo(self, action):
""" """
Return plugin related information, based on the action Return plugin related information, based on the action.
``action`` - The action to perform ``action``
if 'search' return a list of plugin names which support search The action to perform. If *search* return a list of plugin names
which support search.
""" """
if action == u'search': if action == u'search':
searches = [] searches = []
@ -501,10 +505,10 @@ class HttpConnection(object):
def search(self, type): def search(self, type):
""" """
Return a list of items that match the search text Return a list of items that match the search text.
``type`` ``type``
The plugin name to search in. The plugin name to search in.
""" """
text = json.loads(self.url_params[u'data'][0])[u'request'][u'text'] text = json.loads(self.url_params[u'data'][0])[u'request'][u'text']
plugin = self.parent.plugin.pluginManager.get_plugin_by_name(type) plugin = self.parent.plugin.pluginManager.get_plugin_by_name(type)
@ -528,7 +532,7 @@ class HttpConnection(object):
def add_to_service(self, type): def add_to_service(self, type):
""" """
Add item of type ``type`` to the end of the service Add item of type ``type`` to the end of the service.
""" """
id = json.loads(self.url_params[u'data'][0])[u'request'][u'id'] id = json.loads(self.url_params[u'data'][0])[u'request'][u'id']
plugin = self.parent.plugin.pluginManager.get_plugin_by_name(type) plugin = self.parent.plugin.pluginManager.get_plugin_by_name(type)

View File

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

View File

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

View File

@ -28,6 +28,7 @@
The :mod:`songexportform` module provides the wizard for exporting songs to the The :mod:`songexportform` module provides the wizard for exporting songs to the
OpenLyrics format. OpenLyrics format.
""" """
import locale
import logging import logging
from PyQt4 import QtCore, QtGui from PyQt4 import QtCore, QtGui
@ -249,6 +250,7 @@ class SongExportForm(OpenLPWizard):
# Load the list of songs. # Load the list of songs.
Receiver.send_message(u'cursor_busy') Receiver.send_message(u'cursor_busy')
songs = self.plugin.manager.get_all_objects(Song) songs = self.plugin.manager.get_all_objects(Song)
songs.sort(cmp=locale.strcoll, key=lambda song: song.title.lower())
for song in songs: for song in songs:
authors = u', '.join([author.display_name authors = u', '.join([author.display_name
for author in song.authors]) for author in song.authors])

View File

@ -699,7 +699,8 @@ class SongImportForm(OpenLPWizard):
elif source_format == SongFormat.OpenLP1: elif source_format == SongFormat.OpenLP1:
# Import an openlp.org database # Import an openlp.org database
importer = self.plugin.importSongs(SongFormat.OpenLP1, importer = self.plugin.importSongs(SongFormat.OpenLP1,
filename=unicode(self.openLP1FilenameEdit.text()) filename=unicode(self.openLP1FilenameEdit.text()),
plugin=self.plugin
) )
elif source_format == SongFormat.OpenLyrics: elif source_format == SongFormat.OpenLyrics:
# Import OpenLyrics songs # Import OpenLyrics songs

View File

@ -57,6 +57,8 @@ class OpenLP1SongImport(SongImport):
The database providing the data to import. The database providing the data to import.
""" """
SongImport.__init__(self, manager, **kwargs) SongImport.__init__(self, manager, **kwargs)
self.available_themes = \
kwargs[u'plugin'].formparent.themeManagerContents.getThemes()
def do_import(self): def do_import(self):
""" """
@ -70,27 +72,34 @@ class OpenLP1SongImport(SongImport):
encoding = self.get_encoding() encoding = self.get_encoding()
if not encoding: if not encoding:
return return
# Connect to the database # Connect to the database.
connection = sqlite.connect(self.import_source, mode=0444, connection = sqlite.connect(self.import_source, mode=0444,
encoding=(encoding, 'replace')) encoding=(encoding, 'replace'))
cursor = connection.cursor() cursor = connection.cursor()
# Determine if we're using a new or an old DB # Determine if we're using a new or an old DB.
cursor.execute(u'SELECT name FROM sqlite_master ' cursor.execute(u'SELECT name FROM sqlite_master '
u'WHERE type = \'table\' AND name = \'tracks\'') u'WHERE type = \'table\' AND name = \'tracks\'')
new_db = len(cursor.fetchall()) > 0 new_db = len(cursor.fetchall()) > 0
# "cache" our list of authors # "cache" our list of authors.
cursor.execute(u'-- types int, unicode') cursor.execute(u'-- types int, unicode')
cursor.execute(u'SELECT authorid, authorname FROM authors') cursor.execute(u'SELECT authorid, authorname FROM authors')
authors = cursor.fetchall() authors = cursor.fetchall()
if new_db: if new_db:
# "cache" our list of tracks # "cache" our list of tracks.
cursor.execute(u'-- types int, unicode') cursor.execute(u'-- types int, unicode')
cursor.execute(u'SELECT trackid, fulltrackname FROM tracks') cursor.execute(u'SELECT trackid, fulltrackname FROM tracks')
tracks = cursor.fetchall() tracks = cursor.fetchall()
# Import the songs # "cache" our list of themes.
cursor.execute(u'-- types int, unicode, unicode, unicode') cursor.execute(u'-- types int, unicode')
cursor.execute(u'SELECT settingsid, settingsname FROM settings')
themes = {}
for theme_id, theme_name in cursor.fetchall():
if theme_name in self.available_themes:
themes[theme_id] = theme_name
# Import the songs.
cursor.execute(u'-- types int, unicode, unicode, unicode, int')
cursor.execute(u'SELECT songid, songtitle, lyrics || \'\' AS lyrics, ' cursor.execute(u'SELECT songid, songtitle, lyrics || \'\' AS lyrics, '
u'copyrightinfo FROM songs') u'copyrightinfo, settingsid FROM songs')
songs = cursor.fetchall() songs = cursor.fetchall()
self.import_wizard.progressBar.setMaximum(len(songs)) self.import_wizard.progressBar.setMaximum(len(songs))
for song in songs: for song in songs:
@ -101,8 +110,12 @@ class OpenLP1SongImport(SongImport):
self.title = song[1] self.title = song[1]
lyrics = song[2].replace(u'\r\n', u'\n') lyrics = song[2].replace(u'\r\n', u'\n')
self.add_copyright(song[3]) self.add_copyright(song[3])
if themes.has_key(song[4]):
self.theme_name = themes[song[4]]
verses = lyrics.split(u'\n\n') verses = lyrics.split(u'\n\n')
[self.add_verse(verse.strip()) for verse in verses if verse.strip()] for verse in verses:
if verse.strip():
self.add_verse(verse.strip())
cursor.execute(u'-- types int') cursor.execute(u'-- types int')
cursor.execute(u'SELECT authorid FROM songauthors ' cursor.execute(u'SELECT authorid FROM songauthors '
u'WHERE songid = %s' % song_id) u'WHERE songid = %s' % song_id)
@ -137,12 +150,12 @@ class OpenLP1SongImport(SongImport):
""" """
Detect character encoding of an openlp.org 1.x song database. Detect character encoding of an openlp.org 1.x song database.
""" """
# Connect to the database # Connect to the database.
connection = sqlite.connect(self.import_source, mode=0444) connection = sqlite.connect(self.import_source, mode=0444)
cursor = connection.cursor() cursor = connection.cursor()
detector = UniversalDetector() detector = UniversalDetector()
# detect charset by authors # Detect charset by authors.
cursor.execute(u'SELECT authorname FROM authors') cursor.execute(u'SELECT authorname FROM authors')
authors = cursor.fetchall() authors = cursor.fetchall()
for author in authors: for author in authors:
@ -150,7 +163,7 @@ class OpenLP1SongImport(SongImport):
if detector.done: if detector.done:
detector.close() detector.close()
return detector.result[u'encoding'] return detector.result[u'encoding']
# detect charset by songs # Detect charset by songs.
cursor.execute(u'SELECT songtitle, copyrightinfo, ' cursor.execute(u'SELECT songtitle, copyrightinfo, '
u'lyrics || \'\' AS lyrics FROM songs') u'lyrics || \'\' AS lyrics FROM songs')
songs = cursor.fetchall() songs = cursor.fetchall()
@ -160,7 +173,7 @@ class OpenLP1SongImport(SongImport):
if detector.done: if detector.done:
detector.close() detector.close()
return detector.result[u'encoding'] return detector.result[u'encoding']
# detect charset by songs # Detect charset by songs.
cursor.execute(u'SELECT name FROM sqlite_master ' cursor.execute(u'SELECT name FROM sqlite_master '
u'WHERE type = \'table\' AND name = \'tracks\'') u'WHERE type = \'table\' AND name = \'tracks\'')
if len(cursor.fetchall()) > 0: if len(cursor.fetchall()) > 0:

View File

@ -102,7 +102,6 @@ class SongShowPlusImport(SongImport):
if not isinstance(self.import_source, list): if not isinstance(self.import_source, list):
return return
self.import_wizard.progressBar.setMaximum(len(self.import_source)) self.import_wizard.progressBar.setMaximum(len(self.import_source))
for file in self.import_source: for file in self.import_source:
self.sspVerseOrderList = [] self.sspVerseOrderList = []
otherCount = 0 otherCount = 0
@ -111,7 +110,6 @@ class SongShowPlusImport(SongImport):
self.import_wizard.incrementProgressBar( self.import_wizard.incrementProgressBar(
WizardStrings.ImportingType % file_name, 0) WizardStrings.ImportingType % file_name, 0)
songData = open(file, 'rb') songData = open(file, 'rb')
while True: while True:
blockKey, = struct.unpack("I", songData.read(4)) blockKey, = struct.unpack("I", songData.read(4))
# The file ends with 4 NUL's # The file ends with 4 NUL's
@ -126,8 +124,9 @@ class SongShowPlusImport(SongImport):
songData.read(2)) songData.read(2))
verseName = songData.read(verseNameLength) verseName = songData.read(verseNameLength)
lengthDescriptorSize, = struct.unpack("B", songData.read(1)) lengthDescriptorSize, = struct.unpack("B", songData.read(1))
log.debug(lengthDescriptorSize)
# Detect if/how long the length descriptor is # Detect if/how long the length descriptor is
if lengthDescriptorSize == 12: if lengthDescriptorSize == 12 or lengthDescriptorSize == 20:
lengthDescriptor, = struct.unpack("I", songData.read(4)) lengthDescriptor, = struct.unpack("I", songData.read(4))
elif lengthDescriptorSize == 2: elif lengthDescriptorSize == 2:
lengthDescriptor = 1 lengthDescriptor = 1
@ -135,6 +134,7 @@ class SongShowPlusImport(SongImport):
lengthDescriptor = 0 lengthDescriptor = 0
else: else:
lengthDescriptor, = struct.unpack("B", songData.read(1)) lengthDescriptor, = struct.unpack("B", songData.read(1))
log.debug(lengthDescriptorSize)
data = songData.read(lengthDescriptor) data = songData.read(lengthDescriptor)
if blockKey == TITLE: if blockKey == TITLE:
self.title = unicode(data, u'cp1252') self.title = unicode(data, u'cp1252')

View File

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

View File

@ -45,7 +45,7 @@ class SongUsagePlugin(Plugin):
log.info(u'SongUsage Plugin loaded') log.info(u'SongUsage Plugin loaded')
def __init__(self, plugin_helpers): def __init__(self, plugin_helpers):
Plugin.__init__(self, u'SongUsage', plugin_helpers) Plugin.__init__(self, u'songusage', plugin_helpers)
self.weight = -4 self.weight = -4
self.icon = build_icon(u':/plugins/plugin_songusage.png') self.icon = build_icon(u':/plugins/plugin_songusage.png')
self.activeIcon = build_icon(u':/songusage/song_usage_active.png') self.activeIcon = build_icon(u':/songusage/song_usage_active.png')
@ -91,8 +91,8 @@ class SongUsagePlugin(Plugin):
self.toolsMenu.addAction(self.songUsageMenu.menuAction()) self.toolsMenu.addAction(self.songUsageMenu.menuAction())
self.songUsageMenu.addAction(self.songUsageStatus) self.songUsageMenu.addAction(self.songUsageStatus)
self.songUsageMenu.addSeparator() self.songUsageMenu.addSeparator()
self.songUsageMenu.addAction(self.songUsageDelete)
self.songUsageMenu.addAction(self.songUsageReport) self.songUsageMenu.addAction(self.songUsageReport)
self.songUsageMenu.addAction(self.songUsageDelete)
self.songUsageActiveButton = QtGui.QToolButton( self.songUsageActiveButton = QtGui.QToolButton(
self.formparent.statusBar) self.formparent.statusBar)
self.songUsageActiveButton.setCheckable(True) self.songUsageActiveButton.setCheckable(True)

View File

@ -2,6 +2,99 @@
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"> <plist version="1.0">
<dict> <dict>
<key>CFBundleDocumentTypes</key>
<array>
<dict>
<key>CFBundleTypeExtension</key>
<array>
<string>osz</string>
</array>
<key>CFBundleTypeIconFiles</key>
<array>
<string>openlp-logo-with-text.icns</string>
</array>
<key>CFBundleTypeName</key>
<string>OpenLP Service</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
<key>LSHandlerRank</key>
<string>Owner</string>
<key>LSItemContentTypes</key>
<array>
<string>org.openlp.osz</string>
</array>
</dict>
<dict>
<key>CFBundleTypeExtension</key>
<array>
<string>otz</string>
</array>
<key>CFBundleTypeIconFiles</key>
<array>
<string>openlp-logo-with-text.icns</string>
</array>
<key>CFBundleTypeName</key>
<string>OpenLP Theme</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
<key>LSHandlerRank</key>
<string>Owner</string>
<key>LSItemContentTypes</key>
<array>
<string>org.openlp.otz</string>
</array>
</dict>
</array>
<key>UTExportedTypeDeclarations</key>
<array>
<dict>
<key>UTTypeIdentifier</key>
<string>org.openlp.osz</string>
<key>UTTypeDescription</key>
<string>OpenLP Service</string>
<key>UTTypeConformsTo</key>
<array>
<string>public.data</string>
<string>public.content</string>
</array>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>osz</string>
</array>
<key>public.mime-type</key>
<array>
<string>application/x-openlp-service</string>
</array>
</dict>
</dict>
<dict>
<key>UTTypeIdentifier</key>
<string>org.openlp.otz</string>
<key>UTTypeDescription</key>
<string>OpenLP Theme</string>
<key>UTTypeConformsTo</key>
<array>
<string>public.data</string>
<string>public.content</string>
</array>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>otz</string>
</array>
<key>public.mime-type</key>
<array>
<string>application/x-openlp-theme</string>
</array>
</dict>
</dict>
</array>
<key>CFBundleIdentifier</key> <key>CFBundleIdentifier</key>
<string>org.openlp</string> <string>org.openlp</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>

View File

@ -48,7 +48,7 @@ on run
set theViewOptions to the icon view options of container window set theViewOptions to the icon view options of container window
set arrangement of theViewOptions to not arranged set arrangement of theViewOptions to not arranged
set icon size of theViewOptions to 128 set icon size of theViewOptions to 128
set background picture of theViewOptions to file ".installer-background.png" set background picture of theViewOptions to file ".background:installer-background.png"
if not exists file "Applications" then if not exists file "Applications" then
make new alias file at container window to POSIX file "/Applications" with properties {name:"Applications"} make new alias file at container window to POSIX file "/Applications" with properties {name:"Applications"}
end if end if

View File

@ -49,15 +49,19 @@ on run
set theViewOptions to the icon view options of container window set theViewOptions to the icon view options of container window
set arrangement of theViewOptions to not arranged set arrangement of theViewOptions to not arranged
set icon size of theViewOptions to 128 set icon size of theViewOptions to 128
set background picture of theViewOptions to file ".installer-background.png" set background picture of theViewOptions to file ".background:installer-background.png"
make new alias file at container window to POSIX file "/Applications" with properties {name:"Applications"} if not exists file "Applications" then
delay 5 make new alias file at container window to POSIX file "/Applications" with properties {name:"Applications"}
end if
delay 1
set position of item "%s" of container window to {160, 200} set position of item "%s" of container window to {160, 200}
set position of item ".Trashes" of container window to {100, 500} set position of item ".Trashes" of container window to {100, 500}
set position of item ".installer-background.png" of container window to {200, 500} set position of item ".background" of container window to {200, 500}
set position of item ".DS_Store" of container window to {400, 500} set position of item ".DS_Store" of container window to {400, 500}
set position of item "Applications" of container window to {550, 200} set position of item "Applications" of container window to {550, 200}
set position of item ".VolumeIcon.icns" of container window to {500, 500} if exists file ".VolumeIcon.icns" then
set position of item ".VolumeIcon.icns" of container window to {500, 500}
end if
set position of item ".fseventsd" of container window to {300, 500} set position of item ".fseventsd" of container window to {300, 500}
if exists POSIX file ".SymAVx86QSFile" then if exists POSIX file ".SymAVx86QSFile" then
set position of item ".SymAVx86QSFile" of container window to {600, 500} set position of item ".SymAVx86QSFile" of container window to {600, 500}

View File

@ -93,8 +93,12 @@ script_name = "build"
def build_application(settings, app_name_lower, app_dir): def build_application(settings, app_name_lower, app_dir):
logging.info('[%s] now building the app with pyinstaller at "%s"...', logging.info('[%s] now building the app with pyinstaller at "%s"...',
script_name, settings['pyinstaller_basedir']) script_name, settings['pyinstaller_basedir'])
result = os.system('python %s/pyinstaller.py openlp.spec' \ full_python_dir = os.path.join('/opt/local/Library/Frameworks',
% settings['pyinstaller_basedir']) 'Python.framework/Versions/2.6/Resources/',
'Python.app/Contents/MacOS/Python')
result = os.system('arch -i386 %s %s/pyinstaller.py openlp.spec' \
% ( full_python_dir,
settings['pyinstaller_basedir']) )
if (result != 0): if (result != 0):
logging.error('[%s] The pyinstaller build reported an error, cannot \ logging.error('[%s] The pyinstaller build reported an error, cannot \
continue!', script_name) continue!', script_name)
@ -219,10 +223,10 @@ def create_dmg(settings):
sys.exit(1) sys.exit(1)
logging.info('[%s] copying the background image...', script_name) logging.info('[%s] copying the background image...', script_name)
# os.mkdir(volume_basedir + '/.background') os.mkdir(volume_basedir + '/.background')
result = os.system('CpMac %s %s' result = os.system('CpMac %s %s'
% (settings['installer_backgroundimage_file'], % (settings['installer_backgroundimage_file'],
volume_basedir + '/.installer-background.png')) volume_basedir + '/.background/installer-background.png'))
if (result != 0): if (result != 0):
logging.error('[%s] could not copy the background image, dmg creation\ logging.error('[%s] could not copy the background image, dmg creation\
failed!', script_name) failed!', script_name)

0
resources/osx/openlp-logo-with-text.icns Executable file → Normal file
View File

View File

@ -1,8 +1,8 @@
[openlp] [openlp]
openlp_appname = OpenLP openlp_appname = OpenLP
openlp_dmgname = OpenLP-1.9.4-bzrXXXX openlp_dmgname = OpenLP-1.9.6-bzrXXXX
openlp_version = XXXX openlp_version = XXXX
openlp_basedir = /Users/openlp/trunk openlp_basedir = /Users/openlp/repo/trunk
openlp_icon_file = openlp-logo-with-text.icns openlp_icon_file = openlp-logo-with-text.icns
openlp_dmg_icon_file = openlp-logo-420x420.png openlp_dmg_icon_file = openlp-logo-420x420.png
installer_backgroundimage_file = installation-background.png installer_backgroundimage_file = installation-background.png

View File

@ -1,5 +1,5 @@
# -*- mode: python -*- # -*- mode: python -*-
a = Analysis([os.path.join(HOMEPATH,'support/_mountzlib.py'), os.path.join(HOMEPATH,'support/useUnicode.py'), '%(openlp_basedir)s/openlp.pyw'], a = Analysis([os.path.join(HOMEPATH,'support/_mountzlib.py'), os.path.join(CONFIGDIR,'support/useUnicode.py'), '%(openlp_basedir)s/openlp.pyw'],
pathex=['%(pyinstaller_basedir)s'], hookspath=['%(openlp_basedir)s/resources/pyinstaller']) pathex=['%(pyinstaller_basedir)s'], hookspath=['%(openlp_basedir)s/resources/pyinstaller'])
pyz = PYZ(a.pure) pyz = PYZ(a.pure)
exe = EXE(pyz, exe = EXE(pyz,

View File

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