forked from openlp/openlp
r1342
This commit is contained in:
commit
6c310efd52
@ -273,6 +273,9 @@ def main():
|
|||||||
qInitResources()
|
qInitResources()
|
||||||
# Now create and actually run the application.
|
# Now create and actually run the application.
|
||||||
app = OpenLP(qt_args)
|
app = OpenLP(qt_args)
|
||||||
|
if sys.platform == 'darwin':
|
||||||
|
OpenLP.addLibraryPath(QtGui.QApplication.applicationDirPath()
|
||||||
|
+ "/qt4_plugins")
|
||||||
#i18n Set Language
|
#i18n Set Language
|
||||||
language = LanguageManager.get_language()
|
language = LanguageManager.get_language()
|
||||||
appTranslator = LanguageManager.get_translator(language)
|
appTranslator = LanguageManager.get_translator(language)
|
||||||
|
@ -106,8 +106,8 @@ def translate(context, text, comment=None,
|
|||||||
|
|
||||||
def get_text_file_string(text_file):
|
def get_text_file_string(text_file):
|
||||||
"""
|
"""
|
||||||
Open a file and return its content as unicode string. If the supplied file
|
Open a file and return its content as unicode string. If the supplied file
|
||||||
name is not a file then the function returns False. If there is an error
|
name is not a file then the function returns False. If there is an error
|
||||||
loading the file or the content can't be decoded then the function will
|
loading the file or the content can't be decoded then the function will
|
||||||
return None.
|
return None.
|
||||||
|
|
||||||
|
@ -65,7 +65,7 @@ def delete_database(plugin_name, db_file_name=None):
|
|||||||
The name of the plugin to remove the database for
|
The name of the plugin to remove the database for
|
||||||
|
|
||||||
``db_file_name``
|
``db_file_name``
|
||||||
The database file name. Defaults to None resulting in the
|
The database file name. Defaults to None resulting in the
|
||||||
plugin_name being used.
|
plugin_name being used.
|
||||||
"""
|
"""
|
||||||
db_file_path = None
|
db_file_path = None
|
||||||
@ -91,6 +91,7 @@ class BaseModel(object):
|
|||||||
instance.__setattr__(key, kwargs[key])
|
instance.__setattr__(key, kwargs[key])
|
||||||
return instance
|
return instance
|
||||||
|
|
||||||
|
|
||||||
class Manager(object):
|
class Manager(object):
|
||||||
"""
|
"""
|
||||||
Provide generic object persistence management
|
Provide generic object persistence management
|
||||||
@ -107,7 +108,7 @@ class Manager(object):
|
|||||||
The init_schema function for this database
|
The init_schema function for this database
|
||||||
|
|
||||||
``db_file_name``
|
``db_file_name``
|
||||||
The file name to use for this database. Defaults to None resulting
|
The file name to use for this database. Defaults to None resulting
|
||||||
in the plugin_name being used.
|
in the plugin_name being used.
|
||||||
"""
|
"""
|
||||||
settings = QtCore.QSettings()
|
settings = QtCore.QSettings()
|
||||||
@ -211,11 +212,11 @@ class Manager(object):
|
|||||||
The type of objects to return
|
The type of objects to return
|
||||||
|
|
||||||
``filter_clause``
|
``filter_clause``
|
||||||
The filter governing selection of objects to return. Defaults to
|
The filter governing selection of objects to return. Defaults to
|
||||||
None.
|
None.
|
||||||
|
|
||||||
``order_by_ref``
|
``order_by_ref``
|
||||||
Any parameters to order the returned objects by. Defaults to None.
|
Any parameters to order the returned objects by. Defaults to None.
|
||||||
"""
|
"""
|
||||||
query = self.session.query(object_class)
|
query = self.session.query(object_class)
|
||||||
if filter_clause is not None:
|
if filter_clause is not None:
|
||||||
@ -232,7 +233,7 @@ class Manager(object):
|
|||||||
The type of objects to return.
|
The type of objects to return.
|
||||||
|
|
||||||
``filter_clause``
|
``filter_clause``
|
||||||
The filter governing selection of objects to return. Defaults to
|
The filter governing selection of objects to return. Defaults to
|
||||||
None.
|
None.
|
||||||
"""
|
"""
|
||||||
query = self.session.query(object_class)
|
query = self.session.query(object_class)
|
||||||
|
@ -34,6 +34,15 @@ from openlp.core.ui import MainDisplay
|
|||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
VERSE = u'The Lord said to {r}Noah{/r}: \n' \
|
||||||
|
'There\'s gonna be a {su}floody{/su}, {sb}floody{/sb}\n' \
|
||||||
|
'The Lord said to {g}Noah{/g}:\n' \
|
||||||
|
'There\'s gonna be a {st}floody{/st}, {it}floody{/it}\n' \
|
||||||
|
'Get those children out of the muddy, muddy \n' \
|
||||||
|
'{r}C{/r}{b}h{/b}{bl}i{/bl}{y}l{/y}{g}d{/g}{pk}' \
|
||||||
|
'r{/pk}{o}e{/o}{pp}n{/pp} of the Lord\n'
|
||||||
|
FOOTER = [u'Arky Arky (Unknown)', u'Public Domain', u'CCLI 123456']
|
||||||
|
|
||||||
class RenderManager(object):
|
class RenderManager(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
|
||||||
@ -202,28 +211,17 @@ class RenderManager(object):
|
|||||||
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(self.screens.preview[u'size'])
|
||||||
verse = u'The Lord said to {r}Noah{/r}: \n' \
|
|
||||||
'There\'s gonna be a {su}floody{/su}, {sb}floody{/sb}\n' \
|
|
||||||
'The Lord said to {g}Noah{/g}:\n' \
|
|
||||||
'There\'s gonna be a {st}floody{/st}, {it}floody{/it}\n' \
|
|
||||||
'Get those children out of the muddy, muddy \n' \
|
|
||||||
'{r}C{/r}{b}h{/b}{bl}i{/bl}{y}l{/y}{g}d{/g}{pk}' \
|
|
||||||
'r{/pk}{o}e{/o}{pp}n{/pp} of the Lord\n'
|
|
||||||
# make big page for theme edit dialog to get line count
|
|
||||||
if self.force_page:
|
|
||||||
verse = verse + verse + verse
|
|
||||||
else:
|
|
||||||
self.image_manager.del_image(theme_data.theme_name)
|
|
||||||
footer = []
|
|
||||||
footer.append(u'Arky Arky (Unknown)')
|
|
||||||
footer.append(u'Public Domain')
|
|
||||||
footer.append(u'CCLI 123456')
|
|
||||||
# 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
|
||||||
serviceItem.add_from_text(u'', verse, footer)
|
if self.force_page:
|
||||||
|
# make big page for theme edit dialog to get line count
|
||||||
|
serviceItem.add_from_text(u'', VERSE + VERSE + VERSE, FOOTER)
|
||||||
|
else:
|
||||||
|
self.image_manager.del_image(theme_data.theme_name)
|
||||||
|
serviceItem.add_from_text(u'', VERSE, FOOTER)
|
||||||
serviceItem.render_manager = self
|
serviceItem.render_manager = self
|
||||||
serviceItem.raw_footer = footer
|
serviceItem.raw_footer = FOOTER
|
||||||
serviceItem.render(True)
|
serviceItem.render(True)
|
||||||
if not self.force_page:
|
if not self.force_page:
|
||||||
self.display.buildHtml(serviceItem)
|
self.display.buildHtml(serviceItem)
|
||||||
|
@ -64,7 +64,7 @@ class SettingsManager(object):
|
|||||||
Read the last directory used for plugin.
|
Read the last directory used for plugin.
|
||||||
|
|
||||||
``section``
|
``section``
|
||||||
The section of code calling the method. This is used in the
|
The section of code calling the method. This is used in the
|
||||||
settings key.
|
settings key.
|
||||||
|
|
||||||
``num``
|
``num``
|
||||||
@ -84,7 +84,7 @@ class SettingsManager(object):
|
|||||||
Save the last directory used for plugin.
|
Save the last directory used for plugin.
|
||||||
|
|
||||||
``section``
|
``section``
|
||||||
The section of code calling the method. This is used in the
|
The section of code calling the method. This is used in the
|
||||||
settings key.
|
settings key.
|
||||||
|
|
||||||
``directory``
|
``directory``
|
||||||
@ -160,11 +160,11 @@ class SettingsManager(object):
|
|||||||
Get a list of files from the data files path.
|
Get a list of files from the data files path.
|
||||||
|
|
||||||
``section``
|
``section``
|
||||||
Defaults to *None*. The section of code getting the files - used
|
Defaults to *None*. The section of code getting the files - used
|
||||||
to load from a section's data subdirectory.
|
to load from a section's data subdirectory.
|
||||||
|
|
||||||
``extension``
|
``extension``
|
||||||
Defaults to *None*. The extension to search for.
|
Defaults to *None*. The extension to search for.
|
||||||
"""
|
"""
|
||||||
path = AppLocation.get_data_path()
|
path = AppLocation.get_data_path()
|
||||||
if section:
|
if section:
|
||||||
|
@ -91,6 +91,7 @@ class ThemeLevel(object):
|
|||||||
Service = 2
|
Service = 2
|
||||||
Song = 3
|
Song = 3
|
||||||
|
|
||||||
|
|
||||||
class BackgroundType(object):
|
class BackgroundType(object):
|
||||||
"""
|
"""
|
||||||
Type enumeration for backgrounds.
|
Type enumeration for backgrounds.
|
||||||
@ -123,6 +124,7 @@ class BackgroundType(object):
|
|||||||
elif type_string == u'image':
|
elif type_string == u'image':
|
||||||
return BackgroundType.Image
|
return BackgroundType.Image
|
||||||
|
|
||||||
|
|
||||||
class BackgroundGradientType(object):
|
class BackgroundGradientType(object):
|
||||||
"""
|
"""
|
||||||
Type enumeration for background gradients.
|
Type enumeration for background gradients.
|
||||||
@ -200,6 +202,7 @@ INTEGER_LIST = [u'size', u'line_adjustment', u'x', u'height', u'y',
|
|||||||
u'width', u'shadow_size', u'outline_size', u'horizontal_align',
|
u'width', u'shadow_size', u'outline_size', u'horizontal_align',
|
||||||
u'vertical_align', u'wrap_style']
|
u'vertical_align', u'wrap_style']
|
||||||
|
|
||||||
|
|
||||||
class ThemeXML(object):
|
class ThemeXML(object):
|
||||||
"""
|
"""
|
||||||
A class to encapsulate the Theme XML.
|
A class to encapsulate the Theme XML.
|
||||||
|
@ -130,7 +130,7 @@ def create_accept_reject_button_box(parent, okay=False):
|
|||||||
methods to handle the default ``accepted()`` and ``rejected()`` signals.
|
methods to handle the default ``accepted()`` and ``rejected()`` signals.
|
||||||
|
|
||||||
``parent``
|
``parent``
|
||||||
The parent object. This should be a ``QWidget`` descendant.
|
The parent object. This should be a ``QWidget`` descendant.
|
||||||
|
|
||||||
``okay``
|
``okay``
|
||||||
If true creates an okay/cancel combination instead of save/cancel.
|
If true creates an okay/cancel combination instead of save/cancel.
|
||||||
@ -185,15 +185,15 @@ def media_item_combo_box(parent, name):
|
|||||||
|
|
||||||
def create_delete_push_button(parent, icon=None):
|
def create_delete_push_button(parent, icon=None):
|
||||||
"""
|
"""
|
||||||
Creates a standard push button with a delete label and optional icon. The
|
Creates a standard push button with a delete label and optional icon. The
|
||||||
button is connected to the parent's ``onDeleteButtonClicked()`` method to
|
button is connected to the parent's ``onDeleteButtonClicked()`` method to
|
||||||
handle the ``clicked()`` signal.
|
handle the ``clicked()`` signal.
|
||||||
|
|
||||||
``parent``
|
``parent``
|
||||||
The parent object. This should be a ``QWidget`` descendant.
|
The parent object. This should be a ``QWidget`` descendant.
|
||||||
|
|
||||||
``icon``
|
``icon``
|
||||||
An icon to display on the button. This can be either a ``QIcon``, a
|
An icon to display on the button. This can be either a ``QIcon``, a
|
||||||
resource path or a file name.
|
resource path or a file name.
|
||||||
"""
|
"""
|
||||||
delete_button = QtGui.QPushButton(parent)
|
delete_button = QtGui.QPushButton(parent)
|
||||||
@ -210,12 +210,12 @@ def create_delete_push_button(parent, icon=None):
|
|||||||
def create_up_down_push_button_set(parent):
|
def create_up_down_push_button_set(parent):
|
||||||
"""
|
"""
|
||||||
Creates a standard set of two push buttons, one for up and the other for
|
Creates a standard set of two push buttons, one for up and the other for
|
||||||
down, for use with lists. The buttons use arrow icons and no text and are
|
down, for use with lists. The buttons use arrow icons and no text and are
|
||||||
connected to the parent's ``onUpButtonClicked()`` and
|
connected to the parent's ``onUpButtonClicked()`` and
|
||||||
``onDownButtonClicked()`` to handle their respective ``clicked()`` signals.
|
``onDownButtonClicked()`` to handle their respective ``clicked()`` signals.
|
||||||
|
|
||||||
``parent``
|
``parent``
|
||||||
The parent object. This should be a ``QWidget`` descendant.
|
The parent object. This should be a ``QWidget`` descendant.
|
||||||
"""
|
"""
|
||||||
up_button = QtGui.QPushButton(parent)
|
up_button = QtGui.QPushButton(parent)
|
||||||
up_button.setIcon(build_icon(u':/services/service_up.png'))
|
up_button.setIcon(build_icon(u':/services/service_up.png'))
|
||||||
@ -295,7 +295,7 @@ def create_valign_combo(form, parent, layout):
|
|||||||
The UI screen that the label and combo will appear on.
|
The UI screen that the label and combo will appear on.
|
||||||
|
|
||||||
``parent``
|
``parent``
|
||||||
The parent object. This should be a ``QWidget`` descendant.
|
The parent object. This should be a ``QWidget`` descendant.
|
||||||
|
|
||||||
``layout``
|
``layout``
|
||||||
A layout object to add the label and combo widgets to.
|
A layout object to add the label and combo widgets to.
|
||||||
|
@ -92,7 +92,7 @@ class Theme(object):
|
|||||||
* ``solid`` - color
|
* ``solid`` - color
|
||||||
|
|
||||||
``BackgroundParameter2``
|
``BackgroundParameter2``
|
||||||
Extra information about the background. The contents of this attribute
|
Extra information about the background. The contents of this attribute
|
||||||
depend on the BackgroundType:
|
depend on the BackgroundType:
|
||||||
|
|
||||||
* ``image`` - border color
|
* ``image`` - border color
|
||||||
@ -100,7 +100,7 @@ class Theme(object):
|
|||||||
* ``solid`` - N/A
|
* ``solid`` - N/A
|
||||||
|
|
||||||
``BackgroundParameter3``
|
``BackgroundParameter3``
|
||||||
Extra information about the background. The contents of this attribute
|
Extra information about the background. The contents of this attribute
|
||||||
depend on the BackgroundType:
|
depend on the BackgroundType:
|
||||||
|
|
||||||
* ``image`` - N/A
|
* ``image`` - N/A
|
||||||
@ -142,7 +142,7 @@ class Theme(object):
|
|||||||
Color for the outline (or None if Outline is 0)
|
Color for the outline (or None if Outline is 0)
|
||||||
|
|
||||||
``HorizontalAlign``
|
``HorizontalAlign``
|
||||||
The horizontal alignment to apply to text. Valid alignments are:
|
The horizontal alignment to apply to text. Valid alignments are:
|
||||||
|
|
||||||
* ``0`` - left align
|
* ``0`` - left align
|
||||||
* ``1`` - right align
|
* ``1`` - right align
|
||||||
@ -156,7 +156,7 @@ class Theme(object):
|
|||||||
* ``2`` - centre align
|
* ``2`` - centre align
|
||||||
|
|
||||||
``WrapStyle``
|
``WrapStyle``
|
||||||
The wrap style to apply to the text. Valid styles are:
|
The wrap style to apply to the text. Valid styles are:
|
||||||
|
|
||||||
* ``0`` - normal
|
* ``0`` - normal
|
||||||
* ``1`` - lyrics
|
* ``1`` - lyrics
|
||||||
|
@ -72,7 +72,7 @@ class DisplayTagForm(QtGui.QDialog, Ui_DisplayTagDialog):
|
|||||||
def preLoad(self):
|
def preLoad(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
|
||||||
|
@ -45,7 +45,7 @@ class ValidEdit(QtGui.QLineEdit):
|
|||||||
|
|
||||||
def validText(self):
|
def validText(self):
|
||||||
"""
|
"""
|
||||||
Only return Integers. Space is 0
|
Only return Integers. Space is 0
|
||||||
"""
|
"""
|
||||||
if self.text().isEmpty():
|
if self.text().isEmpty():
|
||||||
return QtCore.QString(u'0')
|
return QtCore.QString(u'0')
|
||||||
|
@ -279,7 +279,7 @@ class Ui_MainWindow(object):
|
|||||||
add_actions(self.SettingsLanguageMenu, self.LanguageGroup.actions())
|
add_actions(self.SettingsLanguageMenu, self.LanguageGroup.actions())
|
||||||
add_actions(self.SettingsMenu, (self.settingsPluginListItem,
|
add_actions(self.SettingsMenu, (self.settingsPluginListItem,
|
||||||
self.SettingsLanguageMenu.menuAction(), None,
|
self.SettingsLanguageMenu.menuAction(), None,
|
||||||
self.SettingsShortcutsItem, self.DisplayTagItem,
|
self.DisplayTagItem, 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))
|
||||||
|
@ -266,7 +266,7 @@ class ThemeManager(QtGui.QWidget):
|
|||||||
oldThemeName = unicode(item.data(QtCore.Qt.UserRole).toString())
|
oldThemeName = unicode(item.data(QtCore.Qt.UserRole).toString())
|
||||||
self.fileRenameForm.fileNameEdit.setText(oldThemeName)
|
self.fileRenameForm.fileNameEdit.setText(oldThemeName)
|
||||||
if self.fileRenameForm.exec_():
|
if self.fileRenameForm.exec_():
|
||||||
newThemeName = unicode(self.fileRenameForm.fileNameEdit.text())
|
newThemeName = unicode(self.fileRenameForm.fileNameEdit.text())
|
||||||
if self.checkIfThemeExists(newThemeName):
|
if self.checkIfThemeExists(newThemeName):
|
||||||
oldThemeData = self.getThemeData(oldThemeName)
|
oldThemeData = self.getThemeData(oldThemeName)
|
||||||
self.cloneThemeData(oldThemeData, newThemeName)
|
self.cloneThemeData(oldThemeData, newThemeName)
|
||||||
@ -284,7 +284,7 @@ class ThemeManager(QtGui.QWidget):
|
|||||||
oldThemeName = unicode(item.data(QtCore.Qt.UserRole).toString())
|
oldThemeName = unicode(item.data(QtCore.Qt.UserRole).toString())
|
||||||
self.fileRenameForm.fileNameEdit.setText(oldThemeName)
|
self.fileRenameForm.fileNameEdit.setText(oldThemeName)
|
||||||
if self.fileRenameForm.exec_(True):
|
if self.fileRenameForm.exec_(True):
|
||||||
newThemeName = unicode(self.fileRenameForm.fileNameEdit.text())
|
newThemeName = unicode(self.fileRenameForm.fileNameEdit.text())
|
||||||
if self.checkIfThemeExists(newThemeName):
|
if self.checkIfThemeExists(newThemeName):
|
||||||
themeData = self.getThemeData(oldThemeName)
|
themeData = self.getThemeData(oldThemeName)
|
||||||
self.cloneThemeData(themeData, newThemeName)
|
self.cloneThemeData(themeData, newThemeName)
|
||||||
@ -399,7 +399,7 @@ class ThemeManager(QtGui.QWidget):
|
|||||||
def onImportTheme(self):
|
def onImportTheme(self):
|
||||||
"""
|
"""
|
||||||
Opens a file dialog to select the theme file(s) to import before
|
Opens a file dialog to select the theme file(s) to import before
|
||||||
attempting to extract OpenLP themes from those files. This process
|
attempting to extract OpenLP themes from those files. This process
|
||||||
will load both OpenLP version 1 and version 2 themes.
|
will load both OpenLP version 1 and version 2 themes.
|
||||||
"""
|
"""
|
||||||
files = QtGui.QFileDialog.getOpenFileNames(self,
|
files = QtGui.QFileDialog.getOpenFileNames(self,
|
||||||
|
@ -242,7 +242,7 @@ def add_actions(target, actions):
|
|||||||
The menu or toolbar to add actions to.
|
The menu or toolbar to add actions to.
|
||||||
|
|
||||||
``actions``
|
``actions``
|
||||||
The actions to be added. An action consisting of the keyword 'None'
|
The actions to be added. An action consisting of the keyword 'None'
|
||||||
will result in a separator being inserted into the target.
|
will result in a separator being inserted into the target.
|
||||||
"""
|
"""
|
||||||
for action in actions:
|
for action in actions:
|
||||||
@ -318,7 +318,7 @@ def get_web_page(url, header=None, update_openlp=False):
|
|||||||
Tells OpenLP to update itself if the page is successfully downloaded.
|
Tells OpenLP to update itself if the page is successfully downloaded.
|
||||||
Defaults to False.
|
Defaults to False.
|
||||||
"""
|
"""
|
||||||
# TODO: Add proxy usage. Get proxy info from OpenLP settings, add to a
|
# TODO: Add proxy usage. Get proxy info from OpenLP settings, add to a
|
||||||
# proxy_handler, build into an opener and install the opener into urllib2.
|
# proxy_handler, build into an opener and install the opener into urllib2.
|
||||||
# http://docs.python.org/library/urllib2.html
|
# http://docs.python.org/library/urllib2.html
|
||||||
if not url:
|
if not url:
|
||||||
|
@ -322,7 +322,7 @@ class BibleDB(QtCore.QObject, Manager):
|
|||||||
def get_books(self):
|
def get_books(self):
|
||||||
"""
|
"""
|
||||||
A wrapper so both local and web bibles have a get_books() method that
|
A wrapper so both local and web bibles have a get_books() method that
|
||||||
manager can call. Used in the media manager advanced search tab.
|
manager can call. Used in the media manager advanced search tab.
|
||||||
"""
|
"""
|
||||||
return self.get_all_objects(Book, order_by_ref=Book.id)
|
return self.get_all_objects(Book, order_by_ref=Book.id)
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@ import socket
|
|||||||
import urllib
|
import urllib
|
||||||
from HTMLParser import HTMLParseError
|
from HTMLParser import HTMLParseError
|
||||||
|
|
||||||
from BeautifulSoup import BeautifulSoup, NavigableString
|
from BeautifulSoup import BeautifulSoup, NavigableString, Tag
|
||||||
|
|
||||||
from openlp.core.lib import Receiver, translate
|
from openlp.core.lib import Receiver, translate
|
||||||
from openlp.core.lib.ui import critical_error_message_box
|
from openlp.core.lib.ui import critical_error_message_box
|
||||||
@ -221,25 +221,18 @@ class BGExtract(object):
|
|||||||
crossrefs = soup.findAll(u'sup', u'xref')
|
crossrefs = soup.findAll(u'sup', u'xref')
|
||||||
if crossrefs:
|
if crossrefs:
|
||||||
[crossref.extract() for crossref in crossrefs]
|
[crossref.extract() for crossref in crossrefs]
|
||||||
|
headings = soup.findAll(u'h5')
|
||||||
|
if headings:
|
||||||
|
[heading.extract() for heading in headings]
|
||||||
cleanup = [(re.compile('\s+'), lambda match: ' ')]
|
cleanup = [(re.compile('\s+'), lambda match: ' ')]
|
||||||
verses = BeautifulSoup(str(soup), markupMassage=cleanup)
|
verses = BeautifulSoup(str(soup), markupMassage=cleanup)
|
||||||
content = verses.find(u'div', u'result-text-style-normal')
|
|
||||||
if not content:
|
|
||||||
content = verses.find(u'div', u'result-text-style-rtl-serif')
|
|
||||||
if not content:
|
|
||||||
log.debug(u'No content found in the BibleGateway response.')
|
|
||||||
send_error_message(u'parse')
|
|
||||||
return None
|
|
||||||
verse_count = len(verses.findAll(u'sup', u'versenum'))
|
|
||||||
found_count = 0
|
|
||||||
verse_list = {}
|
verse_list = {}
|
||||||
while found_count < verse_count:
|
for verse in verses(u'sup', u'versenum'):
|
||||||
content = content.findNext(u'sup', u'versenum')
|
raw_verse_num = verse.next
|
||||||
raw_verse_num = content.next
|
|
||||||
clean_verse_num = 0
|
clean_verse_num = 0
|
||||||
# Not all verses exist in all translations and may or may not be
|
# Not all verses exist in all translations and may or may not be
|
||||||
# represented by a verse number. If they are not fine, if they are
|
# represented by a verse number. If they are not fine, if they are
|
||||||
# it will probably be in a format that breaks int(). We will then
|
# it will probably be in a format that breaks int(). We will then
|
||||||
# have no idea what garbage may be sucked in to the verse text so
|
# have no idea what garbage may be sucked in to the verse text so
|
||||||
# if we do not get a clean int() then ignore the verse completely.
|
# if we do not get a clean int() then ignore the verse completely.
|
||||||
try:
|
try:
|
||||||
@ -248,9 +241,22 @@ class BGExtract(object):
|
|||||||
log.exception(u'Illegal verse number in %s %s %s:%s',
|
log.exception(u'Illegal verse number in %s %s %s:%s',
|
||||||
version, bookname, chapter, unicode(raw_verse_num))
|
version, bookname, chapter, unicode(raw_verse_num))
|
||||||
if clean_verse_num:
|
if clean_verse_num:
|
||||||
raw_verse_text = raw_verse_num.next
|
verse_text = raw_verse_num.next
|
||||||
verse_list[clean_verse_num] = unicode(raw_verse_text)
|
part = raw_verse_num.next.next
|
||||||
found_count += 1
|
while not (isinstance(part, Tag) and part.attrMap and
|
||||||
|
part.attrMap[u'class'] == u'versenum'):
|
||||||
|
# While we are still in the same verse grab all the text.
|
||||||
|
if isinstance(part, NavigableString):
|
||||||
|
verse_text = verse_text + part
|
||||||
|
if isinstance(part.next, Tag) and part.next.name == u'div':
|
||||||
|
# Run out of verses so stop.
|
||||||
|
break
|
||||||
|
part = part.next
|
||||||
|
verse_list[clean_verse_num] = unicode(verse_text)
|
||||||
|
if not verse_list:
|
||||||
|
log.debug(u'No content found in the BibleGateway response.')
|
||||||
|
send_error_message(u'parse')
|
||||||
|
return None
|
||||||
return SearchResults(bookname, chapter, verse_list)
|
return SearchResults(bookname, chapter, verse_list)
|
||||||
|
|
||||||
|
|
||||||
@ -384,7 +390,7 @@ class HTTPBible(BibleDB):
|
|||||||
BibleDB.__init__(self, parent, **kwargs)
|
BibleDB.__init__(self, parent, **kwargs)
|
||||||
self.download_source = kwargs[u'download_source']
|
self.download_source = kwargs[u'download_source']
|
||||||
self.download_name = kwargs[u'download_name']
|
self.download_name = kwargs[u'download_name']
|
||||||
# TODO: Clean up proxy stuff. We probably want one global proxy per
|
# TODO: Clean up proxy stuff. We probably want one global proxy per
|
||||||
# connection type (HTTP and HTTPS) at most.
|
# connection type (HTTP and HTTPS) at most.
|
||||||
self.proxy_server = None
|
self.proxy_server = None
|
||||||
self.proxy_username = None
|
self.proxy_username = None
|
||||||
@ -458,8 +464,8 @@ class HTTPBible(BibleDB):
|
|||||||
search_results = self.get_chapter(book, reference[1])
|
search_results = self.get_chapter(book, reference[1])
|
||||||
if search_results and search_results.has_verselist():
|
if search_results and search_results.has_verselist():
|
||||||
## We have found a book of the bible lets check to see
|
## We have found a book of the bible lets check to see
|
||||||
## if it was there. By reusing the returned book name
|
## if it was there. By reusing the returned book name
|
||||||
## we get a correct book. For example it is possible
|
## we get a correct book. For example it is possible
|
||||||
## to request ac and get Acts back.
|
## to request ac and get Acts back.
|
||||||
bookname = search_results.book
|
bookname = search_results.book
|
||||||
Receiver.send_message(u'openlp_process_events')
|
Receiver.send_message(u'openlp_process_events')
|
||||||
|
@ -46,16 +46,6 @@ except ImportError:
|
|||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
class BibleMode(object):
|
|
||||||
"""
|
|
||||||
This is basically an enumeration class which specifies the mode of a Bible.
|
|
||||||
Mode refers to whether or not a Bible in OpenLP is a full Bible or needs to
|
|
||||||
be downloaded from the Internet on an as-needed basis.
|
|
||||||
"""
|
|
||||||
Full = 1
|
|
||||||
Partial = 2
|
|
||||||
|
|
||||||
|
|
||||||
class BibleFormat(object):
|
class BibleFormat(object):
|
||||||
"""
|
"""
|
||||||
This is a special enumeration class that holds the various types of Bibles,
|
This is a special enumeration class that holds the various types of Bibles,
|
||||||
@ -275,7 +265,7 @@ class BibleManager(object):
|
|||||||
'Scripture Reference Error'),
|
'Scripture Reference Error'),
|
||||||
u'message': translate('BiblesPlugin.BibleManager',
|
u'message': translate('BiblesPlugin.BibleManager',
|
||||||
'Your scripture reference is either not supported by OpenLP '
|
'Your scripture reference is either not supported by OpenLP '
|
||||||
'or is invalid. Please make sure your reference conforms to '
|
'or is invalid. Please make sure your reference conforms to '
|
||||||
'one of the following patterns:\n\n'
|
'one of the following patterns:\n\n'
|
||||||
'Book Chapter\n'
|
'Book Chapter\n'
|
||||||
'Book Chapter-Chapter\n'
|
'Book Chapter-Chapter\n'
|
||||||
|
@ -482,7 +482,7 @@ class BibleMediaItem(MediaManagerItem):
|
|||||||
self.listView.clear()
|
self.listView.clear()
|
||||||
if self.listView.count() != 0:
|
if self.listView.count() != 0:
|
||||||
self.__checkSecondBible(bible, second_bible)
|
self.__checkSecondBible(bible, second_bible)
|
||||||
else:
|
elif self.search_results:
|
||||||
self.displayResults(bible, second_bible)
|
self.displayResults(bible, second_bible)
|
||||||
Receiver.send_message(u'cursor_normal')
|
Receiver.send_message(u'cursor_normal')
|
||||||
self.advancedSearchButton.setEnabled(True)
|
self.advancedSearchButton.setEnabled(True)
|
||||||
@ -698,11 +698,7 @@ class BibleMediaItem(MediaManagerItem):
|
|||||||
service_item.add_capability(ItemCapabilities.AllowsPreview)
|
service_item.add_capability(ItemCapabilities.AllowsPreview)
|
||||||
service_item.add_capability(ItemCapabilities.AllowsLoop)
|
service_item.add_capability(ItemCapabilities.AllowsLoop)
|
||||||
# Service Item: Title
|
# Service Item: Title
|
||||||
for title in raw_title:
|
service_item.title = u', '.join(raw_title)
|
||||||
if not service_item.title:
|
|
||||||
service_item.title = title
|
|
||||||
else:
|
|
||||||
service_item.title += u', ' + title
|
|
||||||
# Service Item: Theme
|
# Service Item: Theme
|
||||||
if len(self.settings.bible_theme) == 0:
|
if len(self.settings.bible_theme) == 0:
|
||||||
service_item.theme = None
|
service_item.theme = None
|
||||||
|
@ -63,7 +63,7 @@ class MediaPlugin(Plugin):
|
|||||||
if ext not in list:
|
if ext not in list:
|
||||||
list.append(ext)
|
list.append(ext)
|
||||||
self.serviceManager.supportedSuffixes(extension[1:])
|
self.serviceManager.supportedSuffixes(extension[1:])
|
||||||
log.info(u'MediaPlugin: %s extensions: %s' % (mimetype,
|
log.info(u'MediaPlugin: %s extensions: %s' % (mimetype,
|
||||||
u' '.join(extensions)))
|
u' '.join(extensions)))
|
||||||
|
|
||||||
def about(self):
|
def about(self):
|
||||||
|
@ -211,8 +211,8 @@ class ImpressDocument(PresentationDocument):
|
|||||||
"""
|
"""
|
||||||
Called when a presentation is added to the SlideController.
|
Called when a presentation is added to the SlideController.
|
||||||
It builds the environment, starts communcations with the background
|
It builds the environment, starts communcations with the background
|
||||||
OpenOffice task started earlier. If OpenOffice is not present is is
|
OpenOffice task started earlier. If OpenOffice is not present is is
|
||||||
started. Once the environment is available the presentation is loaded
|
started. Once the environment is available the presentation is loaded
|
||||||
and started.
|
and started.
|
||||||
|
|
||||||
``presentation``
|
``presentation``
|
||||||
|
@ -213,6 +213,7 @@ class Controller(object):
|
|||||||
def poll(self):
|
def poll(self):
|
||||||
self.doc.poll_slidenumber(self.is_live)
|
self.doc.poll_slidenumber(self.is_live)
|
||||||
|
|
||||||
|
|
||||||
class MessageListener(object):
|
class MessageListener(object):
|
||||||
"""
|
"""
|
||||||
This is the Presentation listener who acts on events from the slide
|
This is the Presentation listener who acts on events from the slide
|
||||||
|
@ -357,7 +357,7 @@ class PresentationController(object):
|
|||||||
def __init__(self, plugin=None, name=u'PresentationController',
|
def __init__(self, plugin=None, name=u'PresentationController',
|
||||||
document_class=PresentationDocument):
|
document_class=PresentationDocument):
|
||||||
"""
|
"""
|
||||||
This is the constructor for the presentationcontroller object. This
|
This is the constructor for the presentationcontroller object. This
|
||||||
provides an easy way for descendent plugins to populate common data.
|
provides an easy way for descendent plugins to populate common data.
|
||||||
This method *must* be overridden, like so::
|
This method *must* be overridden, like so::
|
||||||
|
|
||||||
|
@ -43,7 +43,7 @@ log = logging.getLogger(__name__)
|
|||||||
class HttpServer(object):
|
class HttpServer(object):
|
||||||
"""
|
"""
|
||||||
Ability to control OpenLP via a webbrowser
|
Ability to control OpenLP via a webbrowser
|
||||||
e.g. http://localhost:4316/send/slidecontroller_live_next
|
e.g. http://localhost:4316/send/slidecontroller_live_next
|
||||||
http://localhost:4316/send/alerts_text?q=your%20alert%20text
|
http://localhost:4316/send/alerts_text?q=your%20alert%20text
|
||||||
"""
|
"""
|
||||||
def __init__(self, parent):
|
def __init__(self, parent):
|
||||||
|
@ -557,7 +557,7 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
|
|||||||
"""
|
"""
|
||||||
Check the validity of the song.
|
Check the validity of the song.
|
||||||
"""
|
"""
|
||||||
# This checks data in the form *not* self.song. self.song is still
|
# This checks data in the form *not* self.song. self.song is still
|
||||||
# None at this point.
|
# None at this point.
|
||||||
log.debug(u'Validate Song')
|
log.debug(u'Validate Song')
|
||||||
# Lets be nice and assume the data is correct.
|
# Lets be nice and assume the data is correct.
|
||||||
@ -714,14 +714,14 @@ class EditSongForm(QtGui.QDialog, Ui_EditSongDialog):
|
|||||||
def saveSong(self, preview=False):
|
def saveSong(self, preview=False):
|
||||||
"""
|
"""
|
||||||
Get all the data from the widgets on the form, and then save it to the
|
Get all the data from the widgets on the form, and then save it to the
|
||||||
database. The form has been validated and all reference items
|
database. The form has been validated and all reference items
|
||||||
(Authors, Books and Topics) have been saved before this function is
|
(Authors, Books and Topics) have been saved before this function is
|
||||||
called.
|
called.
|
||||||
|
|
||||||
``preview``
|
``preview``
|
||||||
Should be ``True`` if the song is also previewed (boolean).
|
Should be ``True`` if the song is also previewed (boolean).
|
||||||
"""
|
"""
|
||||||
# The Song() assignment. No database calls should be made while a
|
# The Song() assignment. No database calls should be made while a
|
||||||
# Song() is in a partially complete state.
|
# Song() is in a partially complete state.
|
||||||
if not self.song:
|
if not self.song:
|
||||||
self.song = Song()
|
self.song = Song()
|
||||||
|
@ -96,7 +96,7 @@ class EasiSlidesImport(SongImport):
|
|||||||
mandatory=False):
|
mandatory=False):
|
||||||
"""
|
"""
|
||||||
Add imported values to the song model converting them to unicode at the
|
Add imported values to the song model converting them to unicode at the
|
||||||
same time. If the unicode decode fails or a mandatory attribute is not
|
same time. If the unicode decode fails or a mandatory attribute is not
|
||||||
present _success is set to False so the importer can react
|
present _success is set to False so the importer can react
|
||||||
appropriately.
|
appropriately.
|
||||||
|
|
||||||
|
@ -72,7 +72,7 @@ def strip_rtf(blob, encoding):
|
|||||||
elif control_str == 'tab':
|
elif control_str == 'tab':
|
||||||
clear_text.append(u'\t')
|
clear_text.append(u'\t')
|
||||||
# Prefer the encoding specified by the RTF data to that
|
# Prefer the encoding specified by the RTF data to that
|
||||||
# specified by the Paradox table header
|
# specified by the Paradox table header
|
||||||
# West European encoding
|
# West European encoding
|
||||||
elif control_str == 'fcharset0':
|
elif control_str == 'fcharset0':
|
||||||
encoding = u'cp1252'
|
encoding = u'cp1252'
|
||||||
@ -129,6 +129,7 @@ class FieldDescEntry:
|
|||||||
self.type = type
|
self.type = type
|
||||||
self.size = size
|
self.size = size
|
||||||
|
|
||||||
|
|
||||||
class EasyWorshipSongImport(SongImport):
|
class EasyWorshipSongImport(SongImport):
|
||||||
"""
|
"""
|
||||||
The :class:`EasyWorshipSongImport` class provides OpenLP with the
|
The :class:`EasyWorshipSongImport` class provides OpenLP with the
|
||||||
@ -163,7 +164,7 @@ class EasyWorshipSongImport(SongImport):
|
|||||||
if code_page == 852:
|
if code_page == 852:
|
||||||
self.encoding = u'cp1250'
|
self.encoding = u'cp1250'
|
||||||
# The following codepage to actual encoding mappings have not been
|
# The following codepage to actual encoding mappings have not been
|
||||||
# observed, but merely guessed. Actual example files are needed.
|
# observed, but merely guessed. Actual example files are needed.
|
||||||
elif code_page == 737:
|
elif code_page == 737:
|
||||||
self.encoding = u'cp1253'
|
self.encoding = u'cp1253'
|
||||||
elif code_page == 775:
|
elif code_page == 775:
|
||||||
|
@ -133,6 +133,7 @@ class FoilPresenterImport(SongImport):
|
|||||||
log.exception(u'XML syntax error in file %s' % file_path)
|
log.exception(u'XML syntax error in file %s' % file_path)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
class FoilPresenter(object):
|
class FoilPresenter(object):
|
||||||
"""
|
"""
|
||||||
This class represents the converter for Foilpresenter XML from a song.
|
This class represents the converter for Foilpresenter XML from a song.
|
||||||
@ -259,7 +260,6 @@ class FoilPresenter(object):
|
|||||||
copyright = None
|
copyright = None
|
||||||
if copyright:
|
if copyright:
|
||||||
strings = []
|
strings = []
|
||||||
author_temp = []
|
|
||||||
if copyright.find(u'Copyright') != -1:
|
if copyright.find(u'Copyright') != -1:
|
||||||
temp = copyright.partition(u'Copyright')
|
temp = copyright.partition(u'Copyright')
|
||||||
copyright = temp[0]
|
copyright = temp[0]
|
||||||
@ -296,7 +296,7 @@ class FoilPresenter(object):
|
|||||||
u'Text +u\.?n?d? +Musik', u'T & M', u'Melodie und Satz',
|
u'Text +u\.?n?d? +Musik', u'T & M', u'Melodie und Satz',
|
||||||
u'Text[\w\,\. ]*:', u'Melodie', u'Musik', u'Satz',
|
u'Text[\w\,\. ]*:', u'Melodie', u'Musik', u'Satz',
|
||||||
u'Weise', u'[dD]eutsch', u'[dD]t[\.\:]', u'Englisch',
|
u'Weise', u'[dD]eutsch', u'[dD]t[\.\:]', u'Englisch',
|
||||||
u'[oO]riginal', u'Bearbeitung', u'[R|r]efrain']
|
u'[oO]riginal', u'Bearbeitung', u'[R|r]efrain']
|
||||||
for marker in markers:
|
for marker in markers:
|
||||||
copyright = re.compile(marker).sub(u'<marker>', copyright, re.U)
|
copyright = re.compile(marker).sub(u'<marker>', copyright, re.U)
|
||||||
copyright = re.compile(u'(?<=<marker>) *:').sub(u'', copyright)
|
copyright = re.compile(u'(?<=<marker>) *:').sub(u'', copyright)
|
||||||
@ -305,7 +305,7 @@ class FoilPresenter(object):
|
|||||||
while i != 1:
|
while i != 1:
|
||||||
if copyright.find(u'<marker>') != -1:
|
if copyright.find(u'<marker>') != -1:
|
||||||
temp = copyright.partition(u'<marker>')
|
temp = copyright.partition(u'<marker>')
|
||||||
if (temp[0].strip() != u'') & (x > 0):
|
if temp[0].strip() and x > 0:
|
||||||
strings.append(temp[0])
|
strings.append(temp[0])
|
||||||
copyright = temp[2]
|
copyright = temp[2]
|
||||||
x += 1
|
x += 1
|
||||||
@ -314,14 +314,15 @@ class FoilPresenter(object):
|
|||||||
i = 1
|
i = 1
|
||||||
else:
|
else:
|
||||||
i = 1
|
i = 1
|
||||||
|
author_temp = []
|
||||||
for author in strings:
|
for author in strings:
|
||||||
temp = re.split(u',(?=\D{2})|(?<=\D),|\/(?=\D{3,})|(?<=\D);',
|
temp = re.split(u',(?=\D{2})|(?<=\D),|\/(?=\D{3,})|(?<=\D);',
|
||||||
author)
|
author)
|
||||||
for tempx in temp:
|
for tempx in temp:
|
||||||
author_temp.append(tempx)
|
author_temp.append(tempx)
|
||||||
for author in author_temp:
|
for author in author_temp:
|
||||||
regex = u'^[\/,;\-\s]+|[\/,;\-\s]+$|'\
|
regex = u'^[\/,;\-\s\.]+|[\/,;\-\s\.]+$|'\
|
||||||
'\s*[0-9]{4}\s*[\-\/]?\s*([0-9]{4})?[\/,;\-\s]*$'
|
'\s*[0-9]{4}\s*[\-\/]?\s*([0-9]{4})?[\/,;\-\s\.]*$'
|
||||||
author = re.compile(regex).sub(u'', author)
|
author = re.compile(regex).sub(u'', author)
|
||||||
author = re.compile(
|
author = re.compile(
|
||||||
u'[0-9]{1,2}\.\s?J(ahr)?h\.|um\s*$|vor\s*$').sub(u'',
|
u'[0-9]{1,2}\.\s?J(ahr)?h\.|um\s*$|vor\s*$').sub(u'',
|
||||||
@ -330,12 +331,12 @@ class FoilPresenter(object):
|
|||||||
author = author.strip()
|
author = author.strip()
|
||||||
if re.search(
|
if re.search(
|
||||||
u'\w+\.?\s+\w{3,}\s+[a|u]nd\s|\w+\.?\s+\w{3,}\s+&\s',
|
u'\w+\.?\s+\w{3,}\s+[a|u]nd\s|\w+\.?\s+\w{3,}\s+&\s',
|
||||||
author, re.U) != None:
|
author, re.U):
|
||||||
temp = re.split(u'\s[a|u]nd\s|\s&\s', author)
|
temp = re.split(u'\s[a|u]nd\s|\s&\s', author)
|
||||||
for tempx in temp:
|
for tempx in temp:
|
||||||
tempx = tempx.strip()
|
tempx = tempx.strip()
|
||||||
authors.append(tempx)
|
authors.append(tempx)
|
||||||
elif (len(author) > 2):
|
elif len(author) > 2:
|
||||||
authors.append(author)
|
authors.append(author)
|
||||||
for display_name in authors:
|
for display_name in authors:
|
||||||
author = self.manager.get_object_filtered(Author,
|
author = self.manager.get_object_filtered(Author,
|
||||||
@ -411,7 +412,7 @@ class FoilPresenter(object):
|
|||||||
temp_verse_order_backup = []
|
temp_verse_order_backup = []
|
||||||
temp_sortnr_backup = 1
|
temp_sortnr_backup = 1
|
||||||
temp_sortnr_liste = []
|
temp_sortnr_liste = []
|
||||||
versenumber = {u'V': 1, u'C': 1, u'B': 1, u'E': 1, u'O': 1, u'I': 1,
|
versenumber = {u'V': 1, u'C': 1, u'B': 1, u'E': 1, u'O': 1, u'I': 1,
|
||||||
u'P': 1}
|
u'P': 1}
|
||||||
for strophe in foilpresenterfolie.strophen.strophe:
|
for strophe in foilpresenterfolie.strophen.strophe:
|
||||||
text = self._child(strophe.text_)
|
text = self._child(strophe.text_)
|
||||||
|
@ -53,6 +53,7 @@ class SongSearch(object):
|
|||||||
Authors = 4
|
Authors = 4
|
||||||
Themes = 5
|
Themes = 5
|
||||||
|
|
||||||
|
|
||||||
class SongMediaItem(MediaManagerItem):
|
class SongMediaItem(MediaManagerItem):
|
||||||
"""
|
"""
|
||||||
This is the custom media manager item for Songs.
|
This is the custom media manager item for Songs.
|
||||||
@ -199,7 +200,7 @@ class SongMediaItem(MediaManagerItem):
|
|||||||
"""
|
"""
|
||||||
log.debug(u'onSongListLoad')
|
log.debug(u'onSongListLoad')
|
||||||
# Called to redisplay the song list screen edit from a search
|
# Called to redisplay the song list screen edit from a search
|
||||||
# or from the exit of the Song edit dialog. If remote editing is active
|
# or from the exit of the Song edit dialog. If remote editing is active
|
||||||
# Trigger it and clean up so it will not update again.
|
# Trigger it and clean up so it will not update again.
|
||||||
if self.remoteTriggered == u'L':
|
if self.remoteTriggered == u'L':
|
||||||
self.onAddClick()
|
self.onAddClick()
|
||||||
@ -218,13 +219,9 @@ class SongMediaItem(MediaManagerItem):
|
|||||||
self.listView.clear()
|
self.listView.clear()
|
||||||
searchresults.sort(cmp=self.collateSongTitles)
|
searchresults.sort(cmp=self.collateSongTitles)
|
||||||
for song in searchresults:
|
for song in searchresults:
|
||||||
author_list = u''
|
author_list = [author.display_name for author in song.authors]
|
||||||
for author in song.authors:
|
|
||||||
if author_list != u'':
|
|
||||||
author_list = author_list + u', '
|
|
||||||
author_list = author_list + author.display_name
|
|
||||||
song_title = unicode(song.title)
|
song_title = unicode(song.title)
|
||||||
song_detail = u'%s (%s)' % (song_title, author_list)
|
song_detail = u'%s (%s)' % (song_title, u', '.join(author_list))
|
||||||
song_name = QtGui.QListWidgetItem(song_detail)
|
song_name = QtGui.QListWidgetItem(song_detail)
|
||||||
song_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(song.id))
|
song_name.setData(QtCore.Qt.UserRole, QtCore.QVariant(song.id))
|
||||||
self.listView.addItem(song_name)
|
self.listView.addItem(song_name)
|
||||||
@ -334,9 +331,6 @@ class SongMediaItem(MediaManagerItem):
|
|||||||
def generateSlideData(self, service_item, item=None, xmlVersion=False):
|
def generateSlideData(self, service_item, item=None, xmlVersion=False):
|
||||||
log.debug(u'generateSlideData (%s:%s)' % (service_item, item))
|
log.debug(u'generateSlideData (%s:%s)' % (service_item, item))
|
||||||
raw_footer = []
|
raw_footer = []
|
||||||
author_list = u''
|
|
||||||
author_audit = []
|
|
||||||
ccli = u''
|
|
||||||
item_id = self._getIdOfItemToGenerate(item, self.remoteSong)
|
item_id = self._getIdOfItemToGenerate(item, self.remoteSong)
|
||||||
service_item.add_capability(ItemCapabilities.AllowsEdit)
|
service_item.add_capability(ItemCapabilities.AllowsEdit)
|
||||||
service_item.add_capability(ItemCapabilities.AllowsPreview)
|
service_item.add_capability(ItemCapabilities.AllowsPreview)
|
||||||
@ -397,13 +391,9 @@ class SongMediaItem(MediaManagerItem):
|
|||||||
for slide in verses:
|
for slide in verses:
|
||||||
service_item.add_from_text(slide[:30], unicode(slide))
|
service_item.add_from_text(slide[:30], unicode(slide))
|
||||||
service_item.title = song.title
|
service_item.title = song.title
|
||||||
for author in song.authors:
|
author_list = [unicode(author.display_name) for author in song.authors]
|
||||||
if len(author_list) > 1:
|
|
||||||
author_list = author_list + u', '
|
|
||||||
author_list = author_list + unicode(author.display_name)
|
|
||||||
author_audit.append(unicode(author.display_name))
|
|
||||||
raw_footer.append(song.title)
|
raw_footer.append(song.title)
|
||||||
raw_footer.append(author_list)
|
raw_footer.append(u', '.join(author_list))
|
||||||
raw_footer.append(song.copyright)
|
raw_footer.append(song.copyright)
|
||||||
if QtCore.QSettings().value(u'general/ccli number',
|
if QtCore.QSettings().value(u'general/ccli number',
|
||||||
QtCore.QVariant(u'')).toString():
|
QtCore.QVariant(u'')).toString():
|
||||||
@ -413,10 +403,10 @@ class SongMediaItem(MediaManagerItem):
|
|||||||
QtCore.QVariant(u'')).toString()))
|
QtCore.QVariant(u'')).toString()))
|
||||||
service_item.raw_footer = raw_footer
|
service_item.raw_footer = raw_footer
|
||||||
service_item.audit = [
|
service_item.audit = [
|
||||||
song.title, author_audit, song.copyright, unicode(song.ccli_number)
|
song.title, author_list, song.copyright, unicode(song.ccli_number)
|
||||||
]
|
]
|
||||||
service_item.data_string = {u'title': song.search_title,
|
service_item.data_string = {u'title': song.search_title,
|
||||||
u'authors': author_list}
|
u'authors': u', '.join(author_list)}
|
||||||
service_item.xml_version = self.openLyrics.song_to_xml(song)
|
service_item.xml_version = self.openLyrics.song_to_xml(song)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
@ -36,7 +36,6 @@ from openlp.plugins.songs.lib.songimport import SongImport
|
|||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
#TODO: Use lxml for parsing and make sure we use methods of "SongImport" .
|
|
||||||
class OpenSongImport(SongImport):
|
class OpenSongImport(SongImport):
|
||||||
"""
|
"""
|
||||||
Import songs exported from OpenSong
|
Import songs exported from OpenSong
|
||||||
|
@ -347,7 +347,7 @@ class SongImport(QtCore.QObject):
|
|||||||
"""
|
"""
|
||||||
For debugging
|
For debugging
|
||||||
"""
|
"""
|
||||||
print u'========================================' \
|
print u'========================================' \
|
||||||
+ u'========================================'
|
+ u'========================================'
|
||||||
print u'TITLE: ' + self.title
|
print u'TITLE: ' + self.title
|
||||||
print u'ALT TITLE: ' + self.alternate_title
|
print u'ALT TITLE: ' + self.alternate_title
|
||||||
|
32
resources/osx/Info.plist.master
Executable file
32
resources/osx/Info.plist.master
Executable file
@ -0,0 +1,32 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleIdentifier</key>
|
||||||
|
<string>org.openlp</string>
|
||||||
|
<key>CFBundleShortVersionString</key>
|
||||||
|
<string>%(openlp_version)s</string>
|
||||||
|
<key>CFBundleVersion</key>
|
||||||
|
<string>%(openlp_version)s</string>
|
||||||
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
|
<string>6.0</string>
|
||||||
|
<key>CFBundleDisplayName</key>
|
||||||
|
<string>%(openlp_appname)s</string>
|
||||||
|
<key>CFBundleIconFile</key>
|
||||||
|
<string>openlp-logo-with-text.icns</string>
|
||||||
|
<key>CFBundleExecutable</key>
|
||||||
|
<string>MacOS/openlp</string>
|
||||||
|
<key>CFBundleName</key>
|
||||||
|
<string>%(openlp_appname)s</string>
|
||||||
|
<key>CFBundleGetInfoString</string>
|
||||||
|
<string>%(openlp_appname)s %(openlp_version)s</string>
|
||||||
|
<key>LSHasLocalizedDisplayName</string>
|
||||||
|
<false/>
|
||||||
|
<key>NSAppleScriptEnabled</key>
|
||||||
|
<false/>
|
||||||
|
<key>CFBundlePackageType</key>
|
||||||
|
<string>APPL</string>
|
||||||
|
<key>LSBackgroundOnly</key>
|
||||||
|
<false/>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
28
resources/osx/Makefile
Normal file
28
resources/osx/Makefile
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
all:
|
||||||
|
python build.py -c openlp.cfg
|
||||||
|
|
||||||
|
view:
|
||||||
|
python build.py -c openlp.cfg --package-view --compress-view
|
||||||
|
|
||||||
|
package:
|
||||||
|
|
||||||
|
python build.py -c openlp.cfg --package --package-view
|
||||||
|
|
||||||
|
bundle:
|
||||||
|
|
||||||
|
python build.py -c openlp.cfg --compress --compress-view
|
||||||
|
|
||||||
|
clean:
|
||||||
|
# remove old configuration files
|
||||||
|
rm -f openlp.spec
|
||||||
|
rm -f Info.plist
|
||||||
|
rm -f .version
|
||||||
|
|
||||||
|
# remove old build artifacts
|
||||||
|
rm -rf build
|
||||||
|
rm -rf dist
|
||||||
|
rm -rf Macopenlp.app
|
||||||
|
rm -rf OpenLP.app
|
||||||
|
rm -f warnopenlp.txt
|
||||||
|
rm -f *dmg
|
||||||
|
|
74
resources/osx/applescript-adjustview-10-5.master
Executable file
74
resources/osx/applescript-adjustview-10-5.master
Executable file
@ -0,0 +1,74 @@
|
|||||||
|
on saveImageWithItselfAsIcon(icon_image_file)
|
||||||
|
-- save icon_image_file with itself as icon
|
||||||
|
set icon_image_file_string to icon_image_file as string
|
||||||
|
tell application "Image Events"
|
||||||
|
launch
|
||||||
|
set icon_image to open file icon_image_file_string
|
||||||
|
save icon_image with icon
|
||||||
|
close icon_image
|
||||||
|
end tell
|
||||||
|
end saveImageWithItselfAsIcon
|
||||||
|
|
||||||
|
on copyIconOfTo(aFileOrFolderWithIcon, aFileOrFolder)
|
||||||
|
tell application "Finder" to set f to aFileOrFolderWithIcon as alias
|
||||||
|
-- grab the file's icon
|
||||||
|
my CopyOrPaste(f, "c")
|
||||||
|
-- now the icon is in the clipboard
|
||||||
|
tell application "Finder" to set c to aFileOrFolder as alias
|
||||||
|
my CopyOrPaste(result, "v")
|
||||||
|
end copyIconOfTo
|
||||||
|
|
||||||
|
on CopyOrPaste(i, cv)
|
||||||
|
tell application "Finder"
|
||||||
|
activate
|
||||||
|
open information window of i
|
||||||
|
end tell
|
||||||
|
tell application "System Events" to tell process "Finder" to tell window 1
|
||||||
|
keystroke tab -- select icon button
|
||||||
|
keystroke (cv & "w") using command down (* (copy or paste) + close window *)
|
||||||
|
end tell -- window 1 then process Finder then System Events
|
||||||
|
end CopyOrPaste
|
||||||
|
|
||||||
|
on run
|
||||||
|
set icon_image_file to POSIX file "%s" as alias
|
||||||
|
set dmg_file to POSIX file "/Volumes/%s" as alias
|
||||||
|
|
||||||
|
my saveImageWithItselfAsIcon(icon_image_file)
|
||||||
|
-- wait for virus scanner
|
||||||
|
delay 2
|
||||||
|
my copyIconOfTo(icon_image_file, dmg_file)
|
||||||
|
|
||||||
|
tell application "Finder"
|
||||||
|
tell disk "%s"
|
||||||
|
open
|
||||||
|
set current view of container window to icon view
|
||||||
|
set toolbar visible of container window to false
|
||||||
|
set statusbar visible of container window to false
|
||||||
|
set the bounds of container window to {400, 100, 1100, 500}
|
||||||
|
set theViewOptions to the icon view options of container window
|
||||||
|
set arrangement of theViewOptions to not arranged
|
||||||
|
set icon size of theViewOptions to 128
|
||||||
|
set background picture of theViewOptions to file ".installer-background.png"
|
||||||
|
if not exists file "Applications" then
|
||||||
|
make new alias file at container window to POSIX file "/Applications" with properties {name:"Applications"}
|
||||||
|
end if
|
||||||
|
delay 5
|
||||||
|
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 ".installer-background.png" of container window to {200, 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 ".VolumeIcon.icns" of container window to {500, 500}
|
||||||
|
set position of item ".fseventsd" of container window to {300, 500}
|
||||||
|
if exists POSIX file ".SymAVx86QSFile" then
|
||||||
|
set position of item ".SymAVx86QSFile" of container window to {600, 500}
|
||||||
|
end if
|
||||||
|
open
|
||||||
|
close
|
||||||
|
update without registering applications
|
||||||
|
-- wait until the virus scan completes
|
||||||
|
delay 5
|
||||||
|
-- eject
|
||||||
|
end tell
|
||||||
|
end tell
|
||||||
|
end run
|
73
resources/osx/applescript-adjustview-10-6.master
Executable file
73
resources/osx/applescript-adjustview-10-6.master
Executable file
@ -0,0 +1,73 @@
|
|||||||
|
on saveImageWithItselfAsIcon(icon_image_file)
|
||||||
|
-- save icon_image_file with itself as icon
|
||||||
|
set icon_image_file_string to icon_image_file as string
|
||||||
|
tell application "Image Events"
|
||||||
|
launch
|
||||||
|
set icon_image to open file icon_image_file_string
|
||||||
|
save icon_image with icon
|
||||||
|
close icon_image
|
||||||
|
end tell
|
||||||
|
end saveImageWithItselfAsIcon
|
||||||
|
|
||||||
|
on copyIconOfTo(aFileOrFolderWithIcon, aFileOrFolder)
|
||||||
|
tell application "Finder" to set f to aFileOrFolderWithIcon as alias
|
||||||
|
-- grab the file's icon
|
||||||
|
my CopyOrPaste(f, "c")
|
||||||
|
-- now the icon is in the clipboard
|
||||||
|
tell application "Finder" to set c to aFileOrFolder as alias
|
||||||
|
my CopyOrPaste(result, "v")
|
||||||
|
end copyIconOfTo
|
||||||
|
|
||||||
|
on CopyOrPaste(i, cv)
|
||||||
|
tell application "Finder"
|
||||||
|
activate
|
||||||
|
set infoWindow to open information window of i
|
||||||
|
set infoWindowName to name of infoWindow
|
||||||
|
end tell
|
||||||
|
tell application "System Events" to tell process "Finder" to tell window infoWindowName
|
||||||
|
keystroke tab -- select icon button
|
||||||
|
keystroke (cv & "w") using command down (* (copy or paste) + close window *)
|
||||||
|
end tell -- window 1 then process Finder then System Events
|
||||||
|
end CopyOrPaste
|
||||||
|
|
||||||
|
on run
|
||||||
|
set icon_image_file to POSIX file "%s" as alias
|
||||||
|
set dmg_file to POSIX file "/Volumes/%s" as alias
|
||||||
|
|
||||||
|
my saveImageWithItselfAsIcon(icon_image_file)
|
||||||
|
-- wait for virus scanner
|
||||||
|
delay 2
|
||||||
|
my copyIconOfTo(icon_image_file, dmg_file)
|
||||||
|
|
||||||
|
tell application "Finder"
|
||||||
|
tell disk "%s"
|
||||||
|
open
|
||||||
|
set current view of container window to icon view
|
||||||
|
set toolbar visible of container window to false
|
||||||
|
set statusbar visible of container window to false
|
||||||
|
set the bounds of container window to {400, 100, 1100, 500}
|
||||||
|
set theViewOptions to the icon view options of container window
|
||||||
|
set arrangement of theViewOptions to not arranged
|
||||||
|
set icon size of theViewOptions to 128
|
||||||
|
set background picture of theViewOptions to file ".installer-background.png"
|
||||||
|
make new alias file at container window to POSIX file "/Applications" with properties {name:"Applications"}
|
||||||
|
delay 5
|
||||||
|
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 ".installer-background.png" of container window to {200, 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 ".VolumeIcon.icns" of container window to {500, 500}
|
||||||
|
set position of item ".fseventsd" of container window to {300, 500}
|
||||||
|
if exists POSIX file ".SymAVx86QSFile" then
|
||||||
|
set position of item ".SymAVx86QSFile" of container window to {600, 500}
|
||||||
|
end if
|
||||||
|
open
|
||||||
|
close
|
||||||
|
update without registering applications
|
||||||
|
-- wait until the virus scan completes
|
||||||
|
delay 5
|
||||||
|
-- eject
|
||||||
|
end tell
|
||||||
|
end tell
|
||||||
|
end run
|
40
resources/osx/applescript-seticon-10-5.master
Executable file
40
resources/osx/applescript-seticon-10-5.master
Executable file
@ -0,0 +1,40 @@
|
|||||||
|
on saveImageWithItselfAsIcon(icon_image_file)
|
||||||
|
-- save icon_image_file with itself as icon
|
||||||
|
set icon_image_file_string to icon_image_file as string
|
||||||
|
tell application "Image Events"
|
||||||
|
launch
|
||||||
|
set icon_image to open file icon_image_file_string
|
||||||
|
save icon_image with icon
|
||||||
|
close icon_image
|
||||||
|
end tell
|
||||||
|
end saveImageWithItselfAsIcon
|
||||||
|
|
||||||
|
on copyIconOfTo(aFileOrFolderWithIcon, aFileOrFolder)
|
||||||
|
tell application "Finder" to set f to aFileOrFolderWithIcon as alias
|
||||||
|
-- grab the file's icon
|
||||||
|
my CopyOrPaste(f, "c")
|
||||||
|
-- now the icon is in the clipboard
|
||||||
|
tell application "Finder" to set c to aFileOrFolder as alias
|
||||||
|
my CopyOrPaste(result, "v")
|
||||||
|
end copyIconOfTo
|
||||||
|
|
||||||
|
on CopyOrPaste(i, cv)
|
||||||
|
tell application "Finder"
|
||||||
|
activate
|
||||||
|
open information window of i
|
||||||
|
end tell
|
||||||
|
tell application "System Events" to tell process "Finder" to tell window 1
|
||||||
|
keystroke tab -- select icon button
|
||||||
|
keystroke (cv & "w") using command down (* (copy or paste) + close window *)
|
||||||
|
end tell -- window 1 then process Finder then System Events
|
||||||
|
end CopyOrPaste
|
||||||
|
|
||||||
|
on run
|
||||||
|
set icon_image_file to POSIX file "%s" as alias
|
||||||
|
set dmg_file to POSIX file "%s" as alias
|
||||||
|
|
||||||
|
my saveImageWithItselfAsIcon(icon_image_file)
|
||||||
|
-- wait for virus scanner
|
||||||
|
delay 2
|
||||||
|
my copyIconOfTo(icon_image_file, dmg_file)
|
||||||
|
end run
|
41
resources/osx/applescript-seticon-10-6.master
Executable file
41
resources/osx/applescript-seticon-10-6.master
Executable file
@ -0,0 +1,41 @@
|
|||||||
|
on saveImageWithItselfAsIcon(icon_image_file)
|
||||||
|
-- save icon_image_file with itself as icon
|
||||||
|
set icon_image_file_string to icon_image_file as string
|
||||||
|
tell application "Image Events"
|
||||||
|
launch
|
||||||
|
set icon_image to open file icon_image_file_string
|
||||||
|
save icon_image with icon
|
||||||
|
close icon_image
|
||||||
|
end tell
|
||||||
|
end saveImageWithItselfAsIcon
|
||||||
|
|
||||||
|
on copyIconOfTo(aFileOrFolderWithIcon, aFileOrFolder)
|
||||||
|
tell application "Finder" to set f to aFileOrFolderWithIcon as alias
|
||||||
|
-- grab the file's icon
|
||||||
|
my CopyOrPaste(f, "c")
|
||||||
|
-- now the icon is in the clipboard
|
||||||
|
tell application "Finder" to set c to aFileOrFolder as alias
|
||||||
|
my CopyOrPaste(result, "v")
|
||||||
|
end copyIconOfTo
|
||||||
|
|
||||||
|
on CopyOrPaste(i, cv)
|
||||||
|
tell application "Finder"
|
||||||
|
activate
|
||||||
|
set infoWindow to open information window of i
|
||||||
|
set infoWindowName to name of infoWindow
|
||||||
|
end tell
|
||||||
|
tell application "System Events" to tell process "Finder" to tell window infoWindowName
|
||||||
|
keystroke tab -- select icon button
|
||||||
|
keystroke (cv & "w") using command down (* (copy or paste) + close window *)
|
||||||
|
end tell -- window 1 then process Finder then System Events
|
||||||
|
end CopyOrPaste
|
||||||
|
|
||||||
|
on run
|
||||||
|
set icon_image_file to POSIX file "%s" as alias
|
||||||
|
set dmg_file to POSIX file "%s" as alias
|
||||||
|
|
||||||
|
my saveImageWithItselfAsIcon(icon_image_file)
|
||||||
|
-- wait for virus scanner
|
||||||
|
delay 2
|
||||||
|
my copyIconOfTo(icon_image_file, dmg_file)
|
||||||
|
end run
|
412
resources/osx/build.py
Normal file
412
resources/osx/build.py
Normal file
@ -0,0 +1,412 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
# -*- encoding: utf-8 -*-
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# OpenLP - Open Source Lyrics Projection #
|
||||||
|
# --------------------------------------------------------------------------- #
|
||||||
|
# Copyright (c) 2008-2011 Raoul Snyman #
|
||||||
|
# Portions copyright (c) 2008-2011 Tim Bentley, Jonathan Corwin, Michael #
|
||||||
|
# Gorven, Scott Guerrieri, Meinert Jordan, Armin Köhler, Andreas Preikschat, #
|
||||||
|
# Christian Richter, Philip Ridout, Maikel Stuivenberg, Martin Thompson, Jon #
|
||||||
|
# Tibble, Carsten Tinggaard, Frode Woldsund #
|
||||||
|
# --------------------------------------------------------------------------- #
|
||||||
|
# This program is free software; you can redistribute it and/or modify it #
|
||||||
|
# under the terms of the GNU General Public License as published by the Free #
|
||||||
|
# Software Foundation; version 2 of the License. #
|
||||||
|
# #
|
||||||
|
# This program is distributed in the hope that it will be useful, but WITHOUT #
|
||||||
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
|
||||||
|
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
|
||||||
|
# more details. #
|
||||||
|
# #
|
||||||
|
# You should have received a copy of the GNU General Public License along #
|
||||||
|
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
|
||||||
|
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
"""
|
||||||
|
Mac OS X Build Script
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
This script is used to build the OS X binary and the accompanying installer.
|
||||||
|
For this script to work out of the box, it depends on a number of things:
|
||||||
|
|
||||||
|
Python 2.6
|
||||||
|
This build script only works with Python 2.6.
|
||||||
|
|
||||||
|
PyQt4
|
||||||
|
You should already have this installed, OpenLP doesn't work without it.
|
||||||
|
The version the script expects is the packaged one available from River
|
||||||
|
Bank Computing.
|
||||||
|
|
||||||
|
PyInstaller
|
||||||
|
PyInstaller should be a checkout of revision 1355 of trunk, and in a
|
||||||
|
directory which is configured in the openlp.cfg. The revision is very
|
||||||
|
important as there is just included a fix for builds on OS X.
|
||||||
|
|
||||||
|
To install PyInstaller, first checkout trunk from Subversion. The
|
||||||
|
easiest way is to do a
|
||||||
|
|
||||||
|
svn co http://svn.pyinstaller.org/trunk
|
||||||
|
|
||||||
|
Then you need to copy the two hook-*.py files from the "pyinstaller"
|
||||||
|
subdirectory in OpenLP's "resources" directory into PyInstaller's
|
||||||
|
"hooks" directory.
|
||||||
|
|
||||||
|
openlp.cfg
|
||||||
|
The configuration file contains settings of the version string to include
|
||||||
|
in the bundle as well as directory and file settings for different
|
||||||
|
purposes (e.g. PyInstaller location or installer background image)
|
||||||
|
|
||||||
|
To start the build process do a
|
||||||
|
|
||||||
|
make
|
||||||
|
|
||||||
|
inside the resources/osx directory. The result should be a {openlp_dmgname}.dmg
|
||||||
|
file in the same directory. If something went wrong - this sometimes happen
|
||||||
|
with the graphical commands in the Apple script - do a
|
||||||
|
|
||||||
|
make clean
|
||||||
|
|
||||||
|
and start the build process again. If you want to execute only parts of the
|
||||||
|
build process you can specify different make targets
|
||||||
|
|
||||||
|
make view -- runs the Apple scripts to set the icons
|
||||||
|
make package -- creates the dmg file and copies the application files
|
||||||
|
make bundle -- compresses the dmg file and sets the dmg file icon
|
||||||
|
"""
|
||||||
|
|
||||||
|
import time
|
||||||
|
import os
|
||||||
|
import ConfigParser
|
||||||
|
import logging
|
||||||
|
import optparse
|
||||||
|
import sys
|
||||||
|
import platform
|
||||||
|
import re
|
||||||
|
import subprocess as subp
|
||||||
|
|
||||||
|
# set the script name
|
||||||
|
script_name = "build"
|
||||||
|
|
||||||
|
def build_application(settings, app_name_lower, app_dir):
|
||||||
|
logging.info('[%s] now building the app with pyinstaller at "%s"...',
|
||||||
|
script_name, settings['pyinstaller_basedir'])
|
||||||
|
result = os.system('python %s/pyinstaller.py openlp.spec' \
|
||||||
|
% settings['pyinstaller_basedir'])
|
||||||
|
if (result != 0):
|
||||||
|
logging.error('[%s] The pyinstaller build reported an error, cannot \
|
||||||
|
continue!', script_name)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
logging.info('[%s] copying the qt_menu files...', script_name)
|
||||||
|
# see http://www.pyinstaller.org/ticket/157
|
||||||
|
result = os.system('cp -R %(qt_menu_directory)s \
|
||||||
|
%(application_directory)s/Contents/Resources' \
|
||||||
|
% { 'qt_menu_directory' : settings['qt_menu_basedir'],
|
||||||
|
'application_directory' : app_dir })
|
||||||
|
if (result != 0):
|
||||||
|
logging.error('[%s] could not copy the qt_menu files, cannot \
|
||||||
|
continue!', script_name)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
dist_folder = os.getcwd() + '/dist/' + app_name_lower
|
||||||
|
|
||||||
|
logging.info('[%s] copying the new plugins...', script_name)
|
||||||
|
result = os.system('cp -R %(openlp_directory)s/openlp/plugins \
|
||||||
|
%(application_directory)s/Contents/MacOS' \
|
||||||
|
% { 'openlp_directory' : settings['openlp_basedir'],
|
||||||
|
'application_directory' : app_dir })
|
||||||
|
if (result != 0):
|
||||||
|
logging.error('[%s] could not copy plugins, dmg creation failed!',
|
||||||
|
script_name)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
logging.info('[%s] copying the icons to the resource directory...',
|
||||||
|
script_name)
|
||||||
|
result = os.system('cp %(icon_file)s \
|
||||||
|
%(application_directory)s/Contents/Resources' \
|
||||||
|
% { 'icon_file' : settings['openlp_icon_file'],
|
||||||
|
'application_directory' : app_dir })
|
||||||
|
if (result != 0):
|
||||||
|
logging.error('[%s] could not copy the icon, dmg creation failed!',
|
||||||
|
script_name)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
logging.info('[%s] copying the version file...', script_name)
|
||||||
|
result = os.system('CpMac %s/.version %s/Contents/MacOS' % (os.getcwd(),
|
||||||
|
app_dir))
|
||||||
|
if (result != 0):
|
||||||
|
logging.error('[%s] could not copy the version file, dmg creation \
|
||||||
|
failed!', script_name)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
logging.info('[%s] copying the new Info.plist...', script_name)
|
||||||
|
result = os.system('cp %(target_directory)s/Info.plist \
|
||||||
|
%(application_directory)s/Contents' \
|
||||||
|
% { 'target_directory' : os.getcwd(),
|
||||||
|
'application_directory' : app_dir })
|
||||||
|
if (result != 0):
|
||||||
|
logging.error('[%s] could not copy the info file, dmg creation \
|
||||||
|
failed!', script_name)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
def deploy_qt(settings):
|
||||||
|
logging.info('[%s] running mac deploy qt on %s.app...', script_name,
|
||||||
|
settings['openlp_appname']);
|
||||||
|
|
||||||
|
result = os.system('macdeployqt %s.app' % settings['openlp_appname']);
|
||||||
|
if (result != 0):
|
||||||
|
logging.error('[%s] could not create dmg file!', script_name)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
def create_dmg(settings):
|
||||||
|
logging.info('[%s] creating the dmg...', script_name)
|
||||||
|
dmg_file = os.getcwd() + '/' + settings['openlp_dmgname'] + '.dmg'
|
||||||
|
result = os.system('hdiutil create %(dmg_file)s~ -ov -megabytes \
|
||||||
|
%(vol_size)s -fs HFS+ -volname %(vol_name)s' \
|
||||||
|
% { 'dmg_file' : dmg_file,
|
||||||
|
'vol_size' : '250',
|
||||||
|
'vol_name' : settings['openlp_appname'] })
|
||||||
|
if (result != 0):
|
||||||
|
logging.error('[%s] could not create dmg file!', script_name)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
logging.info('[%s] mounting the dmg file...', script_name)
|
||||||
|
output = subp.Popen(["hdiutil", "attach", dmg_file + "~.dmg"],
|
||||||
|
stdout=subp.PIPE).communicate()[0]
|
||||||
|
logging.debug(output)
|
||||||
|
|
||||||
|
p = re.compile('Apple_HFS\s+(.+?)\s*$')
|
||||||
|
result = p.search(output, re.M)
|
||||||
|
volume_basedir = ''
|
||||||
|
if result:
|
||||||
|
volume_basedir = result.group(1)
|
||||||
|
else:
|
||||||
|
logging.error('could not mount dmg file, cannot continue!')
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
logging.info('[%s] copying the app (from %s) to the dmg (at %s)...',
|
||||||
|
script_name, app_dir, volume_basedir)
|
||||||
|
result = os.system('CpMac -r %s %s' \
|
||||||
|
% ( app_dir, volume_basedir ))
|
||||||
|
if (result != 0):
|
||||||
|
logging.error('[%s] could not copy application, dmg creation failed!',
|
||||||
|
script_name)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
logging.info('[%s] copying the background image...', script_name)
|
||||||
|
# os.mkdir(volume_basedir + '/.background')
|
||||||
|
result = os.system('CpMac %s %s'
|
||||||
|
% (settings['installer_backgroundimage_file'],
|
||||||
|
volume_basedir + '/.installer-background.png'))
|
||||||
|
if (result != 0):
|
||||||
|
logging.error('[%s] could not copy the background image, dmg creation\
|
||||||
|
failed!', script_name)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
return (volume_basedir, dmg_file)
|
||||||
|
|
||||||
|
def unmount_dmg(settings, volume_basedir):
|
||||||
|
logging.info('[%s] unmounting the dmg...', script_name)
|
||||||
|
result = os.system('hdiutil detach %s' % volume_basedir)
|
||||||
|
if (result != 0):
|
||||||
|
logging.error('[%s] could not unmount the dmg file, dmg creation \
|
||||||
|
failed!', script_name)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
def compress_view(settings, seticon_scriptname, dmg_file):
|
||||||
|
logging.info('[%s] setting icon of the dmg file...', script_name)
|
||||||
|
try:
|
||||||
|
f = open(seticon_scriptname)
|
||||||
|
p = subp.Popen(["osascript"], stdin=subp.PIPE)
|
||||||
|
p.communicate(f.read() % ((os.getcwd() + '/' +
|
||||||
|
settings['openlp_dmg_icon_file']), dmg_file))
|
||||||
|
f.close()
|
||||||
|
result = p.returncode
|
||||||
|
if (result != 0):
|
||||||
|
logging.error('[%s] could not set the icon to the dmg file, \
|
||||||
|
dmg creation failed!', script_name)
|
||||||
|
sys.exit(1)
|
||||||
|
except IOError, e:
|
||||||
|
logging.error('[%s] could not adjust the view (%s), dmg creation \
|
||||||
|
failed!', script_name, e)
|
||||||
|
sys.exit(1)
|
||||||
|
except OSError, e:
|
||||||
|
logging.error('[%s] could not set the icon to the dmg file(%s), \
|
||||||
|
dmg creation failed!', script_name, e)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
def adjust_package_view(settings, adjustview_scriptname):
|
||||||
|
logging.info('[%s] making adjustments to the view...', script_name)
|
||||||
|
try:
|
||||||
|
f = open(adjustview_scriptname)
|
||||||
|
p = subp.Popen(["osascript"], stdin=subp.PIPE)
|
||||||
|
p.communicate(f.read() % ((os.getcwd() + '/' + \
|
||||||
|
settings['openlp_dmg_icon_file']),
|
||||||
|
settings['openlp_appname'],
|
||||||
|
settings['openlp_appname'],
|
||||||
|
settings['openlp_appname']))
|
||||||
|
f.close()
|
||||||
|
result = p.returncode
|
||||||
|
if (result != 0):
|
||||||
|
logging.error('[%s] could not adjust the view, dmg creation \
|
||||||
|
failed!', script_name)
|
||||||
|
sys.exit(1)
|
||||||
|
except IOError, e:
|
||||||
|
logging.error('[%s] could not adjust the view (%s), dmg creation \
|
||||||
|
failed!', script_name, e)
|
||||||
|
sys.exit(1)
|
||||||
|
except OSError, e:
|
||||||
|
logging.error('[%s] could not adjust the view (%s), dmg creation \
|
||||||
|
failed!', script_name, e)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
def compress_dmg(settings):
|
||||||
|
logging.info('[%s] compress the dmg file...', script_name)
|
||||||
|
result = os.system('hdiutil convert %s~.dmg -format UDZO \
|
||||||
|
-imagekey zlib-level=9 -o %s' \
|
||||||
|
% (dmg_file, dmg_file))
|
||||||
|
if (result != 0):
|
||||||
|
logging.error('[%s] could not compress the dmg file, dmg creation \
|
||||||
|
failed!', script_name)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
|
||||||
|
# set default actions
|
||||||
|
do_build = True
|
||||||
|
do_compress_view = True
|
||||||
|
do_package_view = True
|
||||||
|
do_create_dmg = True
|
||||||
|
do_compress_dmg = True
|
||||||
|
do_deploy_qt = True
|
||||||
|
|
||||||
|
parser = optparse.OptionParser()
|
||||||
|
parser.add_option('-c', '--config', dest='config', help='config file',
|
||||||
|
metavar='CONFIG')
|
||||||
|
parser.add_option('-v', '--package-view', dest='package_view',
|
||||||
|
help='triggers view adjustment scripts for package',
|
||||||
|
metavar='PACKAGEVIEWONLY', action='store_true', default=False)
|
||||||
|
parser.add_option('-y', '--compress-view', dest='compress_view',
|
||||||
|
help='triggers view adjustment scripts for dmg',
|
||||||
|
metavar='COMPRESSVIEWONLY', action='store_true', default=False)
|
||||||
|
parser.add_option('-p', '--package', dest='package',
|
||||||
|
help='package application folder to dmg', metavar='PACKAGE',
|
||||||
|
action='store_true', default=False)
|
||||||
|
parser.add_option('-z', '--compress', dest='compress',
|
||||||
|
help='compresses the existing dmg', metavar='COMPRESS',
|
||||||
|
action='store_true', default=False)
|
||||||
|
parser.add_option('-b', '--basedir', dest='basedir',
|
||||||
|
help='volume basedir like /Volumes/OpenLP', metavar='BASEDIR',
|
||||||
|
default='/Volumes/OpenLP')
|
||||||
|
|
||||||
|
(options, args) = parser.parse_args()
|
||||||
|
|
||||||
|
# if an option is set, false all
|
||||||
|
if (options.package_view is True or options.compress_view is True
|
||||||
|
or options.package is True or options.compress is True):
|
||||||
|
do_build = False
|
||||||
|
do_deploy_qt = False
|
||||||
|
do_package_view = options.package_view
|
||||||
|
do_compress_view = options.compress_view
|
||||||
|
do_create_dmg = options.package
|
||||||
|
do_compress_dmg = options.compress
|
||||||
|
|
||||||
|
if not options.config:
|
||||||
|
parser.error('option --config|-c is required')
|
||||||
|
|
||||||
|
logHandler = logging.StreamHandler()
|
||||||
|
logHandler.setFormatter(logging.Formatter(
|
||||||
|
'%(asctime)s %(levelname)-8s %(message)s',
|
||||||
|
'%a, %d %b %Y %H:%M:%S'))
|
||||||
|
logging.getLogger().addHandler(logHandler)
|
||||||
|
logging.getLogger().setLevel(logging.DEBUG)
|
||||||
|
|
||||||
|
config = ConfigParser.RawConfigParser()
|
||||||
|
config.readfp(open(options.config, 'r'))
|
||||||
|
|
||||||
|
if not config.has_section('openlp'):
|
||||||
|
logging.error('[%s] config file "%s" lacks an [openlp] section',
|
||||||
|
script_name, options.config)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
if not sys.platform == "darwin":
|
||||||
|
logging.error('[%s] this script only works on Macintosh OS X systems,'
|
||||||
|
+ 'not on %s', script_name, sys.platform)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
version = platform.mac_ver()[0]
|
||||||
|
# we only need the differenciation between leopard and snow leopard
|
||||||
|
if version.startswith("10.6"):
|
||||||
|
SNOWLEOPARD = True
|
||||||
|
logging.info('[%s] using snow leopard scripts (version = %s)',
|
||||||
|
script_name, version)
|
||||||
|
adjustview_scriptname = "applescript-adjustview-10-6.master"
|
||||||
|
seticon_scriptname = "applescript-seticon-10-6.master"
|
||||||
|
else:
|
||||||
|
SNOWLEOPARD = False
|
||||||
|
logging.info('[%s] using leopard scripts (version = %s)', script_name,
|
||||||
|
version)
|
||||||
|
adjustview_scriptname = "applescript-adjustview-10-5.master"
|
||||||
|
seticon_scriptname = "applescript-seticon-10-5.master"
|
||||||
|
|
||||||
|
if not os.path.isfile(adjustview_scriptname) \
|
||||||
|
or not os.path.isfile(seticon_scriptname):
|
||||||
|
logging.error('[%s] could not find apple scripts for given OS X '
|
||||||
|
+ 'version %s', script_name, version)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
settings = dict()
|
||||||
|
for k in config.options('openlp'):
|
||||||
|
settings[k] = config.get('openlp', k)
|
||||||
|
|
||||||
|
# prepare the configuration files
|
||||||
|
os.system('python expander.py --config %(config_file)s \
|
||||||
|
--template openlp.spec.master \
|
||||||
|
--expandto %(target_directory)s/openlp.spec' \
|
||||||
|
% { 'config_file' : options.config, 'target_directory' : os.getcwd() })
|
||||||
|
os.system('python expander.py --config %(config_file)s \
|
||||||
|
--template Info.plist.master \
|
||||||
|
--expandto %(target_directory)s/Info.plist' \
|
||||||
|
% { 'config_file' : options.config, 'target_directory' : os.getcwd() })
|
||||||
|
os.system('python expander.py --config %(config_file)s \
|
||||||
|
--template version.master \
|
||||||
|
--expandto %(target_directory)s/.version' \
|
||||||
|
% { 'config_file' : options.config, 'target_directory' : os.getcwd() })
|
||||||
|
|
||||||
|
# prepare variables
|
||||||
|
app_name_lower = settings['openlp_appname'].lower()
|
||||||
|
app_dir = os.getcwd() + '/' + settings['openlp_appname'] + '.app'
|
||||||
|
|
||||||
|
# if the view option is set, skip the building steps
|
||||||
|
if (do_build is True):
|
||||||
|
build_application(settings, app_name_lower, app_dir)
|
||||||
|
|
||||||
|
if (do_deploy_qt is True):
|
||||||
|
deploy_qt(settings)
|
||||||
|
|
||||||
|
if (do_create_dmg is True):
|
||||||
|
(volume_basedir, dmg_file) = create_dmg(settings)
|
||||||
|
else:
|
||||||
|
# setting base dir
|
||||||
|
volume_basedir = options.basedir
|
||||||
|
dmg_file = os.getcwd() + '/' + settings['openlp_dmgname'] + '.dmg'
|
||||||
|
|
||||||
|
if (do_package_view is True):
|
||||||
|
adjust_package_view(settings, adjustview_scriptname)
|
||||||
|
|
||||||
|
if (do_create_dmg is True):
|
||||||
|
unmount_dmg(settings, volume_basedir)
|
||||||
|
|
||||||
|
if (do_compress_dmg is True):
|
||||||
|
compress_dmg(settings)
|
||||||
|
|
||||||
|
if (do_compress_view is True):
|
||||||
|
compress_view(settings, seticon_scriptname, dmg_file)
|
||||||
|
|
||||||
|
if (do_compress_dmg is True):
|
||||||
|
logging.info('[%s] finished creating dmg file, resulting file is "%s"',
|
||||||
|
script_name, dmg_file)
|
||||||
|
|
202
resources/osx/expander.py
Executable file
202
resources/osx/expander.py
Executable file
@ -0,0 +1,202 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
# -*- encoding: utf-8 -*-
|
||||||
|
|
||||||
|
# TODOs:
|
||||||
|
# - defaults for non-supplied expansions:
|
||||||
|
# template contains
|
||||||
|
|
||||||
|
import ConfigParser
|
||||||
|
import logging
|
||||||
|
import optparse
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
|
||||||
|
# variable expansion:
|
||||||
|
# - %(dog)s --- normal python expansion
|
||||||
|
# - %(dog%)s --- no python expansion, leave as is (stripping the trailing %)
|
||||||
|
# - %(dog:cat) --- if there is an expansion for dog, dog will be used;
|
||||||
|
# otherwise if cat exists cat will be used
|
||||||
|
# - %(dog=cat) --- if there is an expansion for dog, dog will be used;
|
||||||
|
# otherwise "cat" will be used
|
||||||
|
# re_conf = re.compile(r'(?<!%)%\((?P<key>[^\(]+?)\)s')
|
||||||
|
re_conf = re.compile(r'(?P<verbatim>%?)%\((?P<key>[^+=:&\)]+?)'
|
||||||
|
+ '(?:(?P<kind>[+=:&])(?P<default>[^\)]+))?\)(?P<type>s|d)')
|
||||||
|
|
||||||
|
def expand_variable(match, expansions, errors):
|
||||||
|
key = match.group('key')
|
||||||
|
kind = match.group('kind')
|
||||||
|
default = match.group('default')
|
||||||
|
typ = match.group('type')
|
||||||
|
verbatim = match.group('verbatim')
|
||||||
|
|
||||||
|
if verbatim:
|
||||||
|
return match.group(0)[1:]
|
||||||
|
|
||||||
|
# literal default
|
||||||
|
if kind == '=':
|
||||||
|
if key in expansions:
|
||||||
|
return expansions[key]
|
||||||
|
return default
|
||||||
|
|
||||||
|
# variable default
|
||||||
|
if kind == ':' and default in expansions:
|
||||||
|
return expansions[default]
|
||||||
|
|
||||||
|
if kind == '+' and default in expansions:
|
||||||
|
if key in expansions:
|
||||||
|
key = expansions[key]
|
||||||
|
if typ == 's':
|
||||||
|
return '%s%s' % (key, expansions[default])
|
||||||
|
if typ == 'd':
|
||||||
|
try:
|
||||||
|
return str(int(key) + int(expansions[default]))
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
if kind == '&' and default in expansions:
|
||||||
|
if typ == 's':
|
||||||
|
return '%s%s' % (key, expansions[default])
|
||||||
|
if typ == 'd':
|
||||||
|
try:
|
||||||
|
return str(int(key) + int(expansions[default]))
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
if key in expansions:
|
||||||
|
return expansions[key]
|
||||||
|
|
||||||
|
if not match.group(0) in errors:
|
||||||
|
errors.append(match.group(0))
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
options = None
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
|
||||||
|
# get config file
|
||||||
|
parser = optparse.OptionParser()
|
||||||
|
parser.add_option('-c', '--config', dest='config',
|
||||||
|
help='config file', metavar='CONFIG')
|
||||||
|
parser.add_option('-t', '--template', dest='template',
|
||||||
|
help='template file', metavar='TEMPLATE')
|
||||||
|
parser.add_option('-x', '--expandto', dest='expanded',
|
||||||
|
help='expanded file', metavar='EXPANDED')
|
||||||
|
parser.add_option('-e', '--echo', dest='echo',
|
||||||
|
help='echo variable', metavar='ECHOVAR')
|
||||||
|
|
||||||
|
(options, args) = parser.parse_args()
|
||||||
|
|
||||||
|
if not options.config:
|
||||||
|
parser.error('option --config|-c is required')
|
||||||
|
if not os.path.exists(options.config):
|
||||||
|
parser.error('config file "%s" does not exist' % options.config)
|
||||||
|
if not options.echo:
|
||||||
|
if not options.template:
|
||||||
|
parser.error('option --template|-t is required')
|
||||||
|
if not os.path.exists(options.template):
|
||||||
|
parser.error('template file "%s" does not exist' \
|
||||||
|
% options.template)
|
||||||
|
if not options.expanded:
|
||||||
|
parser.error('option --expandto|-e is required')
|
||||||
|
|
||||||
|
logHandler = logging.StreamHandler()
|
||||||
|
logHandler.setFormatter(logging.Formatter('%(asctime)s %(levelname)-8s '
|
||||||
|
+ ' %(message)s', '%a, %d %b %Y %H:%M:%S'))
|
||||||
|
logging.getLogger().addHandler(logHandler)
|
||||||
|
logging.getLogger().setLevel(logging.DEBUG)
|
||||||
|
|
||||||
|
config = ConfigParser.RawConfigParser()
|
||||||
|
config.readfp(open(options.config, 'r'))
|
||||||
|
|
||||||
|
if not config.has_section('openlp'):
|
||||||
|
logging.error('[expander] %s: config file "%s" lacks an [openlp] '
|
||||||
|
+ 'section', options.template, options.config)
|
||||||
|
|
||||||
|
expansions = dict()
|
||||||
|
for k in config.options('openlp'):
|
||||||
|
expansions[k] = config.get('openlp', k)
|
||||||
|
|
||||||
|
# commandline overrides?
|
||||||
|
for override in args:
|
||||||
|
if not '=' in override:
|
||||||
|
continue
|
||||||
|
|
||||||
|
(k, v) = override.split('=', 2)
|
||||||
|
expansions[k] = v
|
||||||
|
|
||||||
|
if options.echo:
|
||||||
|
if options.echo in expansions:
|
||||||
|
print expansions[options.echo]
|
||||||
|
sys.exit(0)
|
||||||
|
else:
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# closure to capture expansions and errors variable
|
||||||
|
errors = []
|
||||||
|
expanded = []
|
||||||
|
|
||||||
|
try:
|
||||||
|
# try to expand the template
|
||||||
|
line = 0
|
||||||
|
faulty = False
|
||||||
|
|
||||||
|
template = open(options.template, 'r')
|
||||||
|
raw = template.readlines()
|
||||||
|
template.close()
|
||||||
|
|
||||||
|
def _expand(m):
|
||||||
|
return expand_variable(m, expansions = expansions, errors = errors)
|
||||||
|
|
||||||
|
for l in raw:
|
||||||
|
line += 1
|
||||||
|
exp = re_conf.sub(_expand, l)
|
||||||
|
if errors:
|
||||||
|
for key in errors:
|
||||||
|
logging.error('[expander] %s: line %d: could not expand '
|
||||||
|
+ 'key "%s"', options.template, line, key)
|
||||||
|
faulty = True
|
||||||
|
errors = []
|
||||||
|
else:
|
||||||
|
expanded.append(exp)
|
||||||
|
|
||||||
|
if faulty:
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# successfully expanded template, now backup potentially existing
|
||||||
|
# target file
|
||||||
|
targetFile = options.expanded % expansions
|
||||||
|
if os.path.exists(targetFile):
|
||||||
|
if os.path.exists('%s~' % targetFile):
|
||||||
|
os.unlink('%s~' % targetFile)
|
||||||
|
os.rename(options.expanded, '%s~' % targetFile)
|
||||||
|
logging.info('[expander] %s: backed up existing target file "%s" '
|
||||||
|
+ 'to "%s"', options.template, targetFile,
|
||||||
|
'%s~' % options.expanded)
|
||||||
|
|
||||||
|
# make sure that target directory exists
|
||||||
|
targetDir = os.path.dirname(targetFile)
|
||||||
|
if not os.path.exists(targetDir):
|
||||||
|
os.makedirs(targetDir)
|
||||||
|
|
||||||
|
# write target file
|
||||||
|
try:
|
||||||
|
target = open(targetFile, 'w')
|
||||||
|
for exp in expanded:
|
||||||
|
target.write(exp)
|
||||||
|
target.close()
|
||||||
|
except Exception, e:
|
||||||
|
logging.error('[expander] %s: could not expand to "%s"',
|
||||||
|
options.template, options.expaned, e)
|
||||||
|
|
||||||
|
# copy over file access mode from template
|
||||||
|
mode = os.stat(options.template)
|
||||||
|
os.chmod(options.expanded, mode.st_mode)
|
||||||
|
|
||||||
|
logging.info('[expander] expanded "%s" to "%s"',
|
||||||
|
options.template, options.expanded)
|
||||||
|
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
BIN
resources/osx/installation-background.png
Executable file
BIN
resources/osx/installation-background.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 48 KiB |
BIN
resources/osx/openlp-logo-420x420-background.png
Executable file
BIN
resources/osx/openlp-logo-420x420-background.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 76 KiB |
BIN
resources/osx/openlp-logo-420x420.png
Normal file
BIN
resources/osx/openlp-logo-420x420.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 97 KiB |
BIN
resources/osx/openlp-logo-with-text.icns
Executable file
BIN
resources/osx/openlp-logo-with-text.icns
Executable file
Binary file not shown.
BIN
resources/osx/openlp-splash-screen.png
Executable file
BIN
resources/osx/openlp-splash-screen.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 56 KiB |
11
resources/osx/openlp.cfg
Executable file
11
resources/osx/openlp.cfg
Executable file
@ -0,0 +1,11 @@
|
|||||||
|
[openlp]
|
||||||
|
openlp_appname = OpenLP
|
||||||
|
openlp_dmgname = OpenLP-1.9.4-bzrXXXX
|
||||||
|
openlp_version = XXXX
|
||||||
|
openlp_full_version = 1.9.4-latest
|
||||||
|
openlp_basedir = /Users/openlp/trunk
|
||||||
|
openlp_icon_file = openlp-logo-with-text.icns
|
||||||
|
openlp_dmg_icon_file = openlp-logo-420x420.png
|
||||||
|
installer_backgroundimage_file = installation-background.png
|
||||||
|
pyinstaller_basedir = /Users/openlp/pyinstaller/trunk
|
||||||
|
qt_menu_basedir = /Library/Frameworks/QtGui.framework/Versions/4/Resources/qt_menu.nib
|
24
resources/osx/openlp.spec.master
Executable file
24
resources/osx/openlp.spec.master
Executable file
@ -0,0 +1,24 @@
|
|||||||
|
# -*- mode: python -*-
|
||||||
|
a = Analysis([os.path.join(HOMEPATH,'support/_mountzlib.py'), os.path.join(HOMEPATH,'support/useUnicode.py'), '%(openlp_basedir)s/openlp.pyw'],
|
||||||
|
pathex=['%(pyinstaller_basedir)s'], hookspath=['%(openlp_basedir)s/resources/pyinstaller'])
|
||||||
|
pyz = PYZ(a.pure)
|
||||||
|
exe = EXE(pyz,
|
||||||
|
a.scripts,
|
||||||
|
exclude_binaries=1,
|
||||||
|
name=os.path.join('build/pyi.darwin/openlp', 'openlp'),
|
||||||
|
debug=False,
|
||||||
|
strip=False,
|
||||||
|
upx=True,
|
||||||
|
console=1 )
|
||||||
|
coll = COLLECT( exe,
|
||||||
|
a.binaries,
|
||||||
|
a.zipfiles,
|
||||||
|
a.datas,
|
||||||
|
strip=False,
|
||||||
|
upx=True,
|
||||||
|
name=os.path.join('dist', 'openlp'))
|
||||||
|
import sys
|
||||||
|
if sys.platform.startswith("darwin"):
|
||||||
|
app = BUNDLE(coll,
|
||||||
|
name='%(openlp_appname)s.app',
|
||||||
|
version='%(openlp_version)s')
|
1
resources/osx/version.master
Executable file
1
resources/osx/version.master
Executable file
@ -0,0 +1 @@
|
|||||||
|
%(openlp_full_version)s
|
Loading…
Reference in New Issue
Block a user