This commit is contained in:
Andreas Preikschat 2011-09-18 12:28:27 +02:00
commit d62876b411
30 changed files with 933 additions and 769 deletions

View File

@ -236,7 +236,6 @@ def main(args=None):
logfile.setFormatter(logging.Formatter(
u'%(asctime)s %(name)-55s %(levelname)-8s %(message)s'))
log.addHandler(logfile)
logging.addLevelName(15, u'Timer')
# Parse command line options and deal with them.
# Use args supplied programatically if possible.
(options, args) = parser.parse_args(args) if args else parser.parse_args()

View File

@ -376,18 +376,23 @@ class MediaManagerItem(QtGui.QWidget):
The files to be loaded
"""
names = []
fullList = []
for count in range(0, self.listView.count()):
names.append(unicode(self.listView.item(count).text()))
newFiles = []
fullList.append(unicode(self.listView.item(count).
data(QtCore.Qt.UserRole).toString()))
duplicatesFound = False
filesAdded = 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)
filesAdded = True
fullList.append(file)
if fullList and filesAdded:
self.listView.clear()
self.loadList(fullList)
lastDir = os.path.split(unicode(files[0]))[0]
SettingsManager.set_last_dir(self.settingsSection, lastDir)
SettingsManager.set_list(self.settingsSection,
@ -485,7 +490,8 @@ class MediaManagerItem(QtGui.QWidget):
"""
pass
def generateSlideData(self, serviceItem, item=None, xmlVersion=False):
def generateSlideData(self, serviceItem, item=None, xmlVersion=False,
remote=False):
raise NotImplementedError(u'MediaManagerItem.generateSlideData needs '
u'to be defined by the plugin')
@ -539,12 +545,12 @@ class MediaManagerItem(QtGui.QWidget):
else:
self.goLive()
def goLive(self, item_id=None):
def goLive(self, item_id=None, remote=False):
log.debug(u'%s Live requested', self.plugin.name)
item = None
if item_id:
item = self.createItemFromId(item_id)
serviceItem = self.buildServiceItem(item)
serviceItem = self.buildServiceItem(item, remote=remote)
if serviceItem:
if not item_id:
serviceItem.from_plugin = True
@ -574,8 +580,8 @@ class MediaManagerItem(QtGui.QWidget):
for item in items:
self.addToService(item)
def addToService(self, item=None, replace=None):
serviceItem = self.buildServiceItem(item, True)
def addToService(self, item=None, replace=None, remote=False):
serviceItem = self.buildServiceItem(item, True, remote=remote)
if serviceItem:
serviceItem.from_plugin = False
self.plugin.serviceManager.addServiceItem(serviceItem,
@ -608,13 +614,13 @@ class MediaManagerItem(QtGui.QWidget):
unicode(translate('OpenLP.MediaManagerItem',
'You must select a %s service item.')) % self.title)
def buildServiceItem(self, item=None, xmlVersion=False):
def buildServiceItem(self, item=None, xmlVersion=False, remote=False):
"""
Common method for generating a service item
"""
serviceItem = ServiceItem(self.plugin)
serviceItem.add_icon(self.plugin.icon_path)
if self.generateSlideData(serviceItem, item, xmlVersion):
if self.generateSlideData(serviceItem, item, xmlVersion, remote):
return serviceItem
else:
return None

View File

@ -28,7 +28,9 @@
import io
import logging
import os
import sys
import urllib
import urllib2
from tempfile import gettempdir
from ConfigParser import SafeConfigParser
@ -60,8 +62,13 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
files = self.webAccess.read()
self.config.readfp(io.BytesIO(files))
self.updateScreenListCombo()
self.downloadCanceled = False
self.downloading = unicode(translate('OpenLP.FirstTimeWizard',
'Downloading %s...'))
QtCore.QObject.connect(self.cancelButton,QtCore.SIGNAL('clicked()'),
self.onCancelButtonClicked)
QtCore.QObject.connect(self.noInternetFinishButton,
QtCore.SIGNAL('clicked()'), self.onNoInternetFinishButtonClicked)
QtCore.QObject.connect(self,
QtCore.SIGNAL(u'currentIdChanged(int)'), self.onCurrentIdChanged)
QtCore.QObject.connect(Receiver.get_receiver(),
@ -80,6 +87,10 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
"""
self.restart()
check_directory_exists(os.path.join(gettempdir(), u'openlp'))
self.noInternetFinishButton.setVisible(False)
# Check if this is a re-run of the wizard.
self.hasRunWizard = QtCore.QSettings().value(
u'general/has run wizard', QtCore.QVariant(False)).toBool()
# Sort out internet access for downloads
if self.webAccess:
songs = self.config.get(u'songs', u'languages')
@ -120,7 +131,7 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
title = self.config.get(u'theme_%s' % theme, u'title')
filename = self.config.get(u'theme_%s' % theme, u'filename')
screenshot = self.config.get(u'theme_%s' % theme, u'screenshot')
urllib.urlretrieve(u'%s/%s' % (self.web, screenshot),
urllib.urlretrieve(u'%s%s' % (self.web, screenshot),
os.path.join(gettempdir(), u'openlp', screenshot))
item = QtGui.QListWidgetItem(title, self.themesListWidget)
item.setData(QtCore.Qt.UserRole,
@ -152,16 +163,24 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
"""
Detects Page changes and updates as approprate.
"""
if pageId == FirstTimePage.Defaults:
# Keep track of the page we are at. Pressing "Cancel" causes pageId
# to be a -1.
if pageId != -1:
self.lastId = pageId
if pageId == FirstTimePage.Plugins:
# Set the no internet page text.
if self.hasRunWizard:
self.noInternetLabel.setText(self.noInternetText)
else:
self.noInternetLabel.setText(self.noInternetText +
self.cancelWizardText)
elif pageId == FirstTimePage.Defaults:
self.themeComboBox.clear()
for iter in xrange(self.themesListWidget.count()):
item = self.themesListWidget.item(iter)
if item.checkState() == QtCore.Qt.Checked:
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:
if self.hasRunWizard:
# Add any existing themes to list.
for theme in self.parent().themeManagerContents.getThemes():
index = self.themeComboBox.findText(theme)
@ -173,6 +192,12 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
# Pre-select the current default theme.
index = self.themeComboBox.findText(default_theme)
self.themeComboBox.setCurrentIndex(index)
elif pageId == FirstTimePage.NoInternet:
self.backButton.setVisible(False)
self.nextButton.setVisible(False)
self.noInternetFinishButton.setVisible(True)
if self.hasRunWizard:
self.cancelButton.setVisible(False)
elif pageId == FirstTimePage.Progress:
Receiver.send_message(u'cursor_busy')
self._preWizard()
@ -192,6 +217,53 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
self.displayComboBox.addItems(self.screens.get_screen_list())
self.displayComboBox.setCurrentIndex(self.displayComboBox.count() - 1)
def onCancelButtonClicked(self):
"""
Process the pressing of the cancel button.
"""
if self.lastId == FirstTimePage.NoInternet or \
(self.lastId <= FirstTimePage.Plugins and \
not self.hasRunWizard):
QtCore.QCoreApplication.exit()
sys.exit()
self.downloadCanceled = True
Receiver.send_message(u'cursor_normal')
def onNoInternetFinishButtonClicked(self):
"""
Process the pressing of the "Finish" button on the No Internet page.
"""
Receiver.send_message(u'cursor_busy')
self._performWizard()
Receiver.send_message(u'openlp_process_events')
Receiver.send_message(u'cursor_normal')
QtCore.QSettings().setValue(u'general/has run wizard',
QtCore.QVariant(True))
self.close()
def urlGetFile(self, url, fpath):
""""
Download a file given a URL. The file is retrieved in chunks, giving
the ability to cancel the download at any point.
"""
block_count = 0
block_size = 4096
urlfile = urllib2.urlopen(url)
filesize = urlfile.headers["Content-Length"]
filename = open(fpath, "wb")
# Download until finished or canceled.
while not self.downloadCanceled:
data = urlfile.read(block_size)
if not data:
break
filename.write(data)
block_count += 1
self._downloadProgress(block_count, block_size, filesize)
filename.close()
# Delete file if canceled, it may be a partial file.
if self.downloadCanceled:
os.remove(fpath)
def _getFileSize(self, url):
site = urllib.urlopen(url)
meta = site.info()
@ -201,7 +273,7 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
increment = (count * block_size) - self.previous_size
self._incrementProgressBar(None, increment)
self.previous_size = count * block_size
def _incrementProgressBar(self, status_text, increment=1):
"""
Update the wizard progress page.
@ -271,7 +343,7 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
"""
if self.max_progress:
self.progressBar.setValue(self.progressBar.maximum())
if self.has_run_wizard:
if self.hasRunWizard:
self.progressLabel.setText(translate('OpenLP.FirstTimeWizard',
'Download complete.'
' Click the finish button to return to OpenLP.'))
@ -280,7 +352,7 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
'Download complete.'
' Click the finish button to start OpenLP.'))
else:
if self.has_run_wizard:
if self.hasRunWizard:
self.progressLabel.setText(translate('OpenLP.FirstTimeWizard',
'Click the finish button to return to OpenLP.'))
else:
@ -309,42 +381,42 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
self._setPluginStatus(self.customCheckBox, u'custom/status')
self._setPluginStatus(self.songUsageCheckBox, u'songusage/status')
self._setPluginStatus(self.alertCheckBox, u'alerts/status')
# Build directories for downloads
songs_destination = os.path.join(unicode(gettempdir()), u'openlp')
bibles_destination = AppLocation.get_section_data_path(u'bibles')
themes_destination = AppLocation.get_section_data_path(u'themes')
# Download songs
for i in xrange(self.songsListWidget.count()):
item = self.songsListWidget.item(i)
if item.checkState() == QtCore.Qt.Checked:
filename = item.data(QtCore.Qt.UserRole).toString()
self._incrementProgressBar(self.downloading % filename, 0)
self.previous_size = 0
destination = os.path.join(songs_destination, unicode(filename))
urllib.urlretrieve(u'%s%s' % (self.web, filename), destination,
self._downloadProgress)
# Download Bibles
bibles_iterator = QtGui.QTreeWidgetItemIterator(self.biblesTreeWidget)
while bibles_iterator.value():
item = bibles_iterator.value()
if item.parent() and item.checkState(0) == QtCore.Qt.Checked:
bible = unicode(item.data(0, QtCore.Qt.UserRole).toString())
self._incrementProgressBar(self.downloading % bible, 0)
self.previous_size = 0
urllib.urlretrieve(u'%s%s' % (self.web, bible),
os.path.join(bibles_destination, bible),
self._downloadProgress)
bibles_iterator += 1
# Download themes
for i in xrange(self.themesListWidget.count()):
item = self.themesListWidget.item(i)
if item.checkState() == QtCore.Qt.Checked:
theme = unicode(item.data(QtCore.Qt.UserRole).toString())
self._incrementProgressBar(self.downloading % theme, 0)
self.previous_size = 0
urllib.urlretrieve(u'%s%s' % (self.web, theme),
os.path.join(themes_destination, theme),
self._downloadProgress)
if self.webAccess:
# Build directories for downloads
songs_destination = os.path.join(unicode(gettempdir()), u'openlp')
bibles_destination = AppLocation.get_section_data_path(u'bibles')
themes_destination = AppLocation.get_section_data_path(u'themes')
# Download songs
for i in xrange(self.songsListWidget.count()):
item = self.songsListWidget.item(i)
if item.checkState() == QtCore.Qt.Checked:
filename = item.data(QtCore.Qt.UserRole).toString()
self._incrementProgressBar(self.downloading % filename, 0)
self.previous_size = 0
destination = os.path.join(songs_destination,
unicode(filename))
self.urlGetFile(u'%s%s' % (self.web, filename), destination)
# Download Bibles
bibles_iterator = QtGui.QTreeWidgetItemIterator(
self.biblesTreeWidget)
while bibles_iterator.value():
item = bibles_iterator.value()
if item.parent() and item.checkState(0) == QtCore.Qt.Checked:
bible = unicode(item.data(0, QtCore.Qt.UserRole).toString())
self._incrementProgressBar(self.downloading % bible, 0)
self.previous_size = 0
self.urlGetFile(u'%s%s' % (self.web, bible),
os.path.join(bibles_destination, bible))
bibles_iterator += 1
# Download themes
for i in xrange(self.themesListWidget.count()):
item = self.themesListWidget.item(i)
if item.checkState() == QtCore.Qt.Checked:
theme = unicode(item.data(QtCore.Qt.UserRole).toString())
self._incrementProgressBar(self.downloading % theme, 0)
self.previous_size = 0
self.urlGetFile(u'%s%s' % (self.web, theme),
os.path.join(themes_destination, theme))
# Set Default Display
if self.displayComboBox.currentIndex() != -1:
QtCore.QSettings().setValue(u'General/monitor',

View File

@ -51,8 +51,10 @@ class Ui_FirstTimeWizard(object):
FirstTimeWizard.setWizardStyle(QtGui.QWizard.ModernStyle)
FirstTimeWizard.setOptions(QtGui.QWizard.IndependentPages |
QtGui.QWizard.NoBackButtonOnStartPage |
QtGui.QWizard.NoBackButtonOnLastPage)
QtGui.QWizard.NoBackButtonOnLastPage |
QtGui.QWizard.HaveCustomButton1)
self.finishButton = self.button(QtGui.QWizard.FinishButton)
self.noInternetFinishButton = self.button(QtGui.QWizard.CustomButton1)
self.cancelButton = self.button(QtGui.QWizard.CancelButton)
self.nextButton = self.button(QtGui.QWizard.NextButton)
self.backButton = self.button(QtGui.QWizard.BackButton)
@ -189,9 +191,7 @@ class Ui_FirstTimeWizard(object):
self.progressBar.setObjectName(u'progressBar')
self.progressLayout.addWidget(self.progressBar)
FirstTimeWizard.setPage(FirstTimePage.Progress, self.progressPage)
self.retranslateUi(FirstTimeWizard)
QtCore.QMetaObject.connectSlotsByName(FirstTimeWizard)
def retranslateUi(self, FirstTimeWizard):
FirstTimeWizard.setWindowTitle(translate(
@ -230,14 +230,17 @@ class Ui_FirstTimeWizard(object):
self.noInternetPage.setSubTitle(translate(
'OpenLP.FirstTimeWizard',
'Unable to detect an Internet connection.'))
self.noInternetLabel.setText(translate('OpenLP.FirstTimeWizard',
self.noInternetText = translate('OpenLP.FirstTimeWizard',
'No Internet connection was found. The First Time Wizard needs an '
'Internet connection in order to be able to download sample '
'songs, Bibles and themes.\n\nTo re-run the First Time Wizard and '
'import this sample data at a later stage, press the cancel '
'button now, check your Internet connection, and restart OpenLP.'
'\n\nTo cancel the First Time Wizard completely, press the finish '
'button now.'))
'songs, Bibles and themes. Press the Finish button now to start '
'OpenLP with initial settings and no sample data.\n\nTo re-run the '
'First Time Wizard and import this sample data at a later time, '
'check your Internet connection and re-run this wizard by '
'selecting "Tools/Re-run First Time Wizard" from OpenLP.')
self.cancelWizardText = translate('OpenLP.FirstTimeWizard',
'\n\nTo cancel the First Time Wizard completely (and not start '
'OpenLP), press the Cancel button now.')
self.songsPage.setTitle(translate('OpenLP.FirstTimeWizard',
'Sample Songs'))
self.songsPage.setSubTitle(translate('OpenLP.FirstTimeWizard',
@ -260,3 +263,5 @@ class Ui_FirstTimeWizard(object):
'Select default theme:'))
self.progressLabel.setText(translate('OpenLP.FirstTimeWizard',
'Starting configuration process...'))
FirstTimeWizard.setButtonText(QtGui.QWizard.CustomButton1,
translate('OpenLP.FirstTimeWizard', 'Finish'))

View File

@ -170,6 +170,15 @@ class GeneralTab(SettingsTab):
self.customHeightValueEdit.setMaximum(9999)
self.displayLayout.addWidget(self.customHeightValueEdit, 4, 3)
self.rightLayout.addWidget(self.displayGroupBox)
# Background audio
self.audioGroupBox = QtGui.QGroupBox(self.rightColumn)
self.audioGroupBox.setObjectName(u'audioGroupBox')
self.audioLayout = QtGui.QVBoxLayout(self.audioGroupBox)
self.audioLayout.setObjectName(u'audioLayout')
self.startPausedCheckBox = QtGui.QCheckBox(self.audioGroupBox)
self.startPausedCheckBox.setObjectName(u'startPausedCheckBox')
self.audioLayout.addWidget(self.startPausedCheckBox)
self.rightLayout.addWidget(self.audioGroupBox)
self.rightLayout.addStretch()
# Signals and slots
QtCore.QObject.connect(self.overrideCheckBox,
@ -243,6 +252,10 @@ class GeneralTab(SettingsTab):
self.customYLabel.setText(translate('OpenLP.GeneralTab', 'Y'))
self.customHeightLabel.setText(translate('OpenLP.GeneralTab', 'Height'))
self.customWidthLabel.setText(translate('OpenLP.GeneralTab', 'Width'))
self.audioGroupBox.setTitle(
translate('OpenLP.GeneralTab', 'Background Audio'))
self.startPausedCheckBox.setText(
translate('OpenLP.GeneralTab', 'Start background audio paused'))
def load(self):
"""
@ -290,6 +303,8 @@ class GeneralTab(SettingsTab):
QtCore.QVariant(self.screens.current[u'size'].height())).toInt()[0])
self.customWidthValueEdit.setValue(settings.value(u'width',
QtCore.QVariant(self.screens.current[u'size'].width())).toInt()[0])
self.startPausedCheckBox.setChecked(settings.value(
u'audio start paused', QtCore.QVariant(True)).toBool())
settings.endGroup()
self.customXValueEdit.setEnabled(self.overrideCheckBox.isChecked())
self.customYValueEdit.setEnabled(self.overrideCheckBox.isChecked())
@ -341,6 +356,8 @@ class GeneralTab(SettingsTab):
QtCore.QVariant(self.customWidthValueEdit.value()))
settings.setValue(u'override position',
QtCore.QVariant(self.overrideCheckBox.isChecked()))
settings.setValue(u'audio start paused',
QtCore.QVariant(self.startPausedCheckBox.isChecked()))
settings.endGroup()
# On save update the screens as well
self.postSetUp(True)

View File

@ -540,6 +540,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
self.uiSettingsSection = u'user interface'
self.generalSettingsSection = u'general'
self.advancedlSettingsSection = u'advanced'
self.shortcutsSettingsSection = u'shortcuts'
self.servicemanagerSettingsSection = u'servicemanager'
self.songsSettingsSection = u'songs'
self.themesSettingsSection = u'themes'
@ -775,25 +776,25 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
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)
# Check if any Bibles downloaded. If there are, they will be
# processed.
Receiver.send_message(u'bibles_load_list', True)
FirstTimeForm(screens, self).exec_()
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)
# Check if any Bibles downloaded. If there are, they will be
# processed.
Receiver.send_message(u'bibles_load_list', True)
def blankCheck(self):
"""
@ -913,42 +914,43 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
QtGui.QMessageBox.No)
if answer == QtGui.QMessageBox.No:
return
importFileName = unicode(QtGui.QFileDialog.getOpenFileName(self,
import_file_name = unicode(QtGui.QFileDialog.getOpenFileName(self,
translate('OpenLP.MainWindow', 'Open File'),
'',
translate('OpenLP.MainWindow',
'OpenLP Export Settings Files (*.conf)')))
if not importFileName:
if not import_file_name:
return
settingSections = []
setting_sections = []
# Add main sections.
settingSections.extend([self.generalSettingsSection])
settingSections.extend([self.advancedlSettingsSection])
settingSections.extend([self.uiSettingsSection])
settingSections.extend([self.servicemanagerSettingsSection])
settingSections.extend([self.themesSettingsSection])
settingSections.extend([self.displayTagsSection])
settingSections.extend([self.headerSection])
setting_sections.extend([self.generalSettingsSection])
setting_sections.extend([self.advancedlSettingsSection])
setting_sections.extend([self.uiSettingsSection])
setting_sections.extend([self.shortcutsSettingsSection])
setting_sections.extend([self.servicemanagerSettingsSection])
setting_sections.extend([self.themesSettingsSection])
setting_sections.extend([self.displayTagsSection])
setting_sections.extend([self.headerSection])
# Add plugin sections.
for plugin in self.pluginManager.plugins:
settingSections.extend([plugin.name])
setting_sections.extend([plugin.name])
settings = QtCore.QSettings()
importSettings = QtCore.QSettings(importFileName,
import_settings = QtCore.QSettings(import_file_name,
QtCore.QSettings.IniFormat)
importKeys = importSettings.allKeys()
for sectionKey in importKeys:
import_keys = import_settings.allKeys()
for section_key in import_keys:
# We need to handle the really bad files.
try:
section, key = sectionKey.split(u'/')
section, key = section_key.split(u'/')
except ValueError:
section = u'unknown'
key = u''
# Switch General back to lowercase.
if section == u'General':
section = u'general'
sectionKey = section + "/" + key
section_key = section + "/" + key
# Make sure it's a valid section for us.
if not section in settingSections:
if not section in setting_sections:
QtGui.QMessageBox.critical(self,
translate('OpenLP.MainWindow', 'Import settings'),
translate('OpenLP.MainWindow',
@ -961,13 +963,13 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
QtGui.QMessageBox.Ok))
return
# We have a good file, import it.
for sectionKey in importKeys:
value = importSettings.value(sectionKey)
settings.setValue(u'%s' % (sectionKey) ,
for section_key in import_keys:
value = import_settings.value(section_key)
settings.setValue(u'%s' % (section_key) ,
QtCore.QVariant(value))
now = datetime.now()
settings.beginGroup(self.headerSection)
settings.setValue( u'file_imported' , QtCore.QVariant(importFileName))
settings.setValue( u'file_imported' , QtCore.QVariant(import_file_name))
settings.setValue(u'file_date_imported',
now.strftime("%Y-%m-%d %H:%M"))
settings.endGroup()
@ -986,78 +988,76 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
self.cleanUp()
QtCore.QCoreApplication.exit()
def onSettingsExportItemClicked(self, exportFileName=None):
def onSettingsExportItemClicked(self):
"""
Export settings to an INI file
Export settings to a .conf file in INI format
"""
if not exportFileName:
exportFileName = unicode(QtGui.QFileDialog.getSaveFileName(self,
translate('OpenLP.MainWindow', 'Export Settings File'), '',
translate('OpenLP.MainWindow',
'OpenLP Export Settings File (*.conf)')))
if not exportFileName:
export_file_name = unicode(QtGui.QFileDialog.getSaveFileName(self,
translate('OpenLP.MainWindow', 'Export Settings File'), '',
translate('OpenLP.MainWindow',
'OpenLP Export Settings File (*.conf)')))
if not export_file_name:
return
# Make sure it's an .ini file.
if not exportFileName.endswith(u'conf'):
exportFileName = exportFileName + u'.conf'
# Make sure it's a .conf file.
if not export_file_name.endswith(u'conf'):
export_file_name = export_file_name + u'.conf'
temp_file = os.path.join(unicode(gettempdir()),
u'openlp', u'exportIni.tmp')
u'openlp', u'exportConf.tmp')
self.saveSettings()
settingSections = []
setting_sections = []
# Add main sections.
settingSections.extend([self.generalSettingsSection])
settingSections.extend([self.advancedlSettingsSection])
settingSections.extend([self.uiSettingsSection])
settingSections.extend([self.servicemanagerSettingsSection])
settingSections.extend([self.themesSettingsSection])
settingSections.extend([self.displayTagsSection])
setting_sections.extend([self.generalSettingsSection])
setting_sections.extend([self.advancedlSettingsSection])
setting_sections.extend([self.uiSettingsSection])
setting_sections.extend([self.shortcutsSettingsSection])
setting_sections.extend([self.servicemanagerSettingsSection])
setting_sections.extend([self.themesSettingsSection])
setting_sections.extend([self.displayTagsSection])
# Add plugin sections.
for plugin in self.pluginManager.plugins:
settingSections.extend([plugin.name])
setting_sections.extend([plugin.name])
# Delete old files if found.
if os.path.exists(temp_file):
os.remove(temp_file)
if os.path.exists(exportFileName):
os.remove(exportFileName)
if os.path.exists(export_file_name):
os.remove(export_file_name)
settings = QtCore.QSettings()
settings.remove(self.headerSection)
# Get the settings.
keys = settings.allKeys()
exportSettings = QtCore.QSettings(temp_file,
export_settings = QtCore.QSettings(temp_file,
QtCore.QSettings.IniFormat)
# Add a header section.
# This is to insure it's our ini file for import.
# This is to insure it's our conf file for import.
now = datetime.now()
applicationVersion = get_application_version()
application_version = get_application_version()
# Write INI format using Qsettings.
# Write our header.
exportSettings.beginGroup(self.headerSection)
exportSettings.setValue(u'Make_Changes', u'At_Own_RISK')
exportSettings.setValue(u'type', u'OpenLP_settings_export')
exportSettings.setValue(u'file_date_created',
export_settings.beginGroup(self.headerSection)
export_settings.setValue(u'Make_Changes', u'At_Own_RISK')
export_settings.setValue(u'type', u'OpenLP_settings_export')
export_settings.setValue(u'file_date_created',
now.strftime("%Y-%m-%d %H:%M"))
exportSettings.setValue(u'version', applicationVersion[u'full'])
exportSettings.endGroup()
export_settings.setValue(u'version', application_version[u'full'])
export_settings.endGroup()
# Write all the sections and keys.
for sectionKey in keys:
section, key = sectionKey.split(u'/')
keyValue = settings.value(sectionKey)
sectionKey = section + u"/" + key
# Change the service section to servicemanager.
if section == u'service':
sectionKey = u'servicemanager/' + key
exportSettings.setValue(sectionKey, keyValue)
exportSettings.sync()
# Temp INI file has been written. Blanks in keys are now '%20'.
# Read the temp file and output the user's INI file with blanks to
for section_key in keys:
section, key = section_key.split(u'/')
key_value = settings.value(section_key)
export_settings.setValue(section_key, key_value)
export_settings.sync()
# Temp CONF file has been written. Blanks in keys are now '%20'.
# Read the temp file and output the user's CONF file with blanks to
# make it more readable.
tempIni = open(temp_file, u'r')
exportIni = open(exportFileName, u'w')
for fileRecord in tempIni:
fileRecord = fileRecord.replace(u'%20', u' ')
exportIni.write(fileRecord)
tempIni.close()
exportIni.close()
temp_conf = open(temp_file, u'r')
export_conf = open(export_file_name, u'w')
for file_record in temp_conf:
# Get rid of any invalid entries.
if file_record.find(u'@Invalid()') == -1:
file_record = file_record.replace(u'%20', u' ')
export_conf.write(file_record)
temp_conf.close()
export_conf.close()
os.remove(temp_file)
return
@ -1291,6 +1291,9 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
"""
log.debug(u'Loading QSettings')
settings = QtCore.QSettings()
# Remove obsolete entries.
settings.remove(u'custom slide')
settings.remove(u'service')
settings.beginGroup(self.generalSettingsSection)
self.recentFiles = settings.value(u'recent files').toStringList()
settings.endGroup()

View File

@ -633,7 +633,14 @@ class SlideController(QtGui.QWidget):
log.debug(u'Starting to play...')
self.display.audioPlayer.addToPlaylist(
self.serviceItem.background_audio)
self.display.audioPlayer.play()
if QtCore.QSettings().value(
self.parent().generalSettingsSection + \
u'/audio start paused',
QtCore.QVariant(True)).toBool():
self.audioPauseItem.setChecked(True)
self.display.audioPlayer.pause()
else:
self.display.audioPlayer.play()
self.setAudioItemsVisibility(True)
row = 0
text = []
@ -784,6 +791,8 @@ class SlideController(QtGui.QWidget):
self.onBlankDisplay(True)
else:
Receiver.send_message(u'maindisplay_show')
else:
Receiver.send_message(u'maindisplay_hide', HideMode.Screen)
def onSlideBlank(self):
"""

View File

@ -788,7 +788,8 @@ class BibleMediaItem(MediaManagerItem):
items.append(bible_verse)
return items
def generateSlideData(self, service_item, item=None, xmlVersion=False):
def generateSlideData(self, service_item, item=None, xmlVersion=False,
remote=False):
"""
Generates and formats the slides for the service item as well as the
service item's title.

View File

@ -222,7 +222,8 @@ class CustomMediaItem(MediaManagerItem):
def onFocus(self):
self.searchTextEdit.setFocus()
def generateSlideData(self, service_item, item=None, xmlVersion=False):
def generateSlideData(self, service_item, item=None, xmlVersion=False,
remote=False):
raw_footer = []
slide = None
theme = None

View File

@ -99,6 +99,8 @@ class ImageMediaItem(MediaManagerItem):
"""
Remove an image item from the list
"""
# Turn off auto preview triggers.
self.listView.blockSignals(True)
if check_item_selected(self.listView, translate('ImagePlugin.MediaItem',
'You must select an image to delete.')):
row_list = [item.row() for item in self.listView.selectedIndexes()]
@ -111,6 +113,7 @@ class ImageMediaItem(MediaManagerItem):
self.listView.takeItem(row)
SettingsManager.set_list(self.settingsSection,
u'images', self.getFileList())
self.listView.blockSignals(False)
def loadList(self, images, initialLoad=False):
if not initialLoad:
@ -139,7 +142,8 @@ class ImageMediaItem(MediaManagerItem):
if not initialLoad:
self.plugin.formparent.finishedProgressBar()
def generateSlideData(self, service_item, item=None, xmlVersion=False):
def generateSlideData(self, service_item, item=None, xmlVersion=False,
remote=False):
background = QtGui.QColor(QtCore.QSettings().value(self.settingsSection
+ u'/background color', QtCore.QVariant(u'#000000')))
if item:
@ -166,11 +170,12 @@ class ImageMediaItem(MediaManagerItem):
items.remove(item)
# We cannot continue, as all images do not exist.
if not items:
critical_error_message_box(
translate('ImagePlugin.MediaItem', 'Missing Image(s)'),
unicode(translate('ImagePlugin.MediaItem',
'The following image(s) no longer exist: %s')) %
u'\n'.join(missing_items_filenames))
if not remote:
critical_error_message_box(
translate('ImagePlugin.MediaItem', 'Missing Image(s)'),
unicode(translate('ImagePlugin.MediaItem',
'The following image(s) no longer exist: %s')) %
u'\n'.join(missing_items_filenames))
return False
# We have missing as well as existing images. We ask what to do.
elif missing_items and QtGui.QMessageBox.question(self,

View File

@ -129,18 +129,20 @@ class MediaMediaItem(MediaManagerItem):
'There was a problem replacing your background, '
'the media file "%s" no longer exists.')) % filename)
def generateSlideData(self, service_item, item=None, xmlVersion=False):
def generateSlideData(self, service_item, item=None, xmlVersion=False,
remote=False):
if item is None:
item = self.listView.currentItem()
if item is None:
return False
filename = unicode(item.data(QtCore.Qt.UserRole).toString())
if not os.path.exists(filename):
# File is no longer present
critical_error_message_box(
translate('MediaPlugin.MediaItem', 'Missing Media File'),
unicode(translate('MediaPlugin.MediaItem',
'The file %s no longer exists.')) % filename)
if not remote:
# File is no longer present
critical_error_message_box(
translate('MediaPlugin.MediaItem', 'Missing Media File'),
unicode(translate('MediaPlugin.MediaItem',
'The file %s no longer exists.')) % filename)
return False
self.mediaObject.stop()
self.mediaObject.clearQueue()

View File

@ -233,7 +233,8 @@ class PresentationMediaItem(MediaManagerItem):
SettingsManager.set_list(self.settingsSection,
u'presentations', self.getFileList())
def generateSlideData(self, service_item, item=None, xmlVersion=False):
def generateSlideData(self, service_item, item=None, xmlVersion=False,
remote=False):
"""
Load the relevant information for displaying the presentation
in the slidecontroller. In the case of powerpoints, an image
@ -275,12 +276,13 @@ class PresentationMediaItem(MediaManagerItem):
return True
else:
# File is no longer present
critical_error_message_box(
translate('PresentationPlugin.MediaItem',
'Missing Presentation'),
unicode(translate('PresentationPlugin.MediaItem',
'The Presentation %s is incomplete,'
' please reload.')) % filename)
if not remote:
critical_error_message_box(
translate('PresentationPlugin.MediaItem',
'Missing Presentation'),
unicode(translate('PresentationPlugin.MediaItem',
'The Presentation %s is incomplete,'
' please reload.')) % filename)
return False
else:
# File is no longer present

View File

@ -528,7 +528,7 @@ class HttpConnection(object):
id = json.loads(self.url_params[u'data'][0])[u'request'][u'id']
plugin = self.parent.plugin.pluginManager.get_plugin_by_name(type)
if plugin.status == PluginStatus.Active and plugin.mediaItem:
plugin.mediaItem.goLive(id)
plugin.mediaItem.goLive(id, remote=True)
def add_to_service(self, type):
"""
@ -538,7 +538,7 @@ class HttpConnection(object):
plugin = self.parent.plugin.pluginManager.get_plugin_by_name(type)
if plugin.status == PluginStatus.Active and plugin.mediaItem:
item_id = plugin.mediaItem.createItemFromId(id)
plugin.mediaItem.addToService(item_id)
plugin.mediaItem.addToService(item_id, remote=True)
def send_response(self, response):
http = u'HTTP/1.1 %s\r\n' % response.code

View File

@ -686,7 +686,7 @@ class SongImportForm(OpenLPWizard):
def performWizard(self):
"""
Perform the actual import. This method pulls in the correct importer
class, and then runs the ``do_import`` method of the importer to do
class, and then runs the ``doImport`` method of the importer to do
the actual importing.
"""
source_format = self.formatComboBox.currentIndex()
@ -759,8 +759,8 @@ class SongImportForm(OpenLPWizard):
importer = self.plugin.importSongs(SongFormat.FoilPresenter,
filenames=self.getListOfFiles(self.foilPresenterFileListWidget)
)
importer.do_import()
if importer.error_log:
importer.doImport()
if importer.errorLog:
self.progressLabel.setText(translate(
'SongsPlugin.SongImportForm', 'Your song import failed.'))
else:

View File

@ -55,13 +55,13 @@ class CCLIFileImport(SongImport):
"""
SongImport.__init__(self, manager, **kwargs)
def do_import(self):
def doImport(self):
"""
Import either a ``.usr`` or a ``.txt`` SongSelect file.
"""
log.debug(u'Starting CCLI File Import')
self.import_wizard.progressBar.setMaximum(len(self.import_source))
for filename in self.import_source:
self.importWizard.progressBar.setMaximum(len(self.importSource))
for filename in self.importSource:
filename = unicode(filename)
log.debug(u'Importing CCLI File: %s', filename)
lines = []
@ -80,23 +80,23 @@ class CCLIFileImport(SongImport):
ext = os.path.splitext(filename)[1]
if ext.lower() == u'.usr':
log.info(u'SongSelect .usr format file found: %s', filename)
if not self.do_import_usr_file(lines):
self.log_error(filename)
if not self.doImportUsrFile(lines):
self.logError(filename)
elif ext.lower() == u'.txt':
log.info(u'SongSelect .txt format file found: %s', filename)
if not self.do_import_txt_file(lines):
self.log_error(filename)
if not self.doImportTxtFile(lines):
self.logError(filename)
else:
self.log_error(filename,
self.logError(filename,
translate('SongsPlugin.CCLIFileImport',
'The file does not have a valid extension.'))
log.info(u'Extension %s is not valid', filename)
if self.stop_import_flag:
if self.stopImportFlag:
return
def do_import_usr_file(self, textList):
def doImportUsrFile(self, textList):
"""
The :func:`do_import_usr_file` method provides OpenLP with the ability
The :func:`doImport_usr_file` method provides OpenLP with the ability
to import CCLI SongSelect songs in *USR* file format.
``textList``
@ -165,7 +165,7 @@ class CCLIFileImport(SongImport):
elif line.startswith(u'Themes='):
song_topics = line[7:].strip()
elif line.startswith(u'[S A'):
self.ccli_number = line[4:-3].strip()
self.ccliNumber = line[4:-3].strip()
elif line.startswith(u'Fields='):
# Fields contain single line indicating verse, chorus, etc,
# /t delimited, same as with words field. store seperately
@ -204,7 +204,7 @@ class CCLIFileImport(SongImport):
verse_type = VerseType.Tags[VerseType.Other]
verse_text = verse_lines[1]
if len(verse_text) > 0:
self.add_verse(verse_text, verse_type)
self.addVerse(verse_text, verse_type)
check_first_verse_line = False
# Handle multiple authors
author_list = song_author.split(u'/')
@ -213,15 +213,15 @@ class CCLIFileImport(SongImport):
for author in author_list:
separated = author.split(u',')
if len(separated) > 1:
self.add_author(u' '.join(reversed(separated)))
self.addAuthor(u' '.join(reversed(separated)))
else:
self.add_author(author)
self.addAuthor(author)
self.topics = [topic.strip() for topic in song_topics.split(u'/t')]
return self.finish()
def do_import_txt_file(self, textList):
def doImportTxtFile(self, textList):
"""
The :func:`do_import_txt_file` method provides OpenLP with the ability
The :func:`doImport_txt_file` method provides OpenLP with the ability
to import CCLI SongSelect songs in *TXT* file format.
``textList``
@ -264,7 +264,7 @@ class CCLIFileImport(SongImport):
continue
elif verse_start:
if verse_text:
self.add_verse(verse_text, verse_type)
self.addVerse(verse_text, verse_type)
verse_text = u''
verse_start = False
else:
@ -278,7 +278,7 @@ class CCLIFileImport(SongImport):
if clean_line.startswith(u'CCLI'):
line_number += 1
ccli_parts = clean_line.split(' ')
self.ccli_number = ccli_parts[len(ccli_parts) - 1]
self.ccliNumber = ccli_parts[len(ccli_parts) - 1]
elif not verse_start:
# We have the verse descriptor
verse_desc_parts = clean_line.split(u' ')
@ -333,5 +333,5 @@ class CCLIFileImport(SongImport):
if len(author_list) < 2:
author_list = song_author.split(u'|')
# Clean spaces before and after author names.
[self.add_author(author_name.strip()) for author_name in author_list]
[self.addAuthor(author_name.strip()) for author_name in author_list]
return self.finish()

View File

@ -49,50 +49,50 @@ class EasiSlidesImport(SongImport):
SongImport.__init__(self, manager, **kwargs)
self.commit = True
def do_import(self):
def doImport(self):
"""
Import either each of the files in self.import_sources - each element of
Import either each of the files in self.importSources - each element of
which can be either a single opensong file, or a zipfile containing
multiple opensong files. If `self.commit` is set False, the
import will not be committed to the database (useful for test scripts).
"""
log.info(u'Importing EasiSlides XML file %s', self.import_source)
log.info(u'Importing EasiSlides XML file %s', self.importSource)
parser = etree.XMLParser(remove_blank_text=True)
parsed_file = etree.parse(self.import_source, parser)
parsed_file = etree.parse(self.importSource, parser)
xml = unicode(etree.tostring(parsed_file))
song_xml = objectify.fromstring(xml)
self.import_wizard.progressBar.setMaximum(len(song_xml.Item))
self.importWizard.progressBar.setMaximum(len(song_xml.Item))
for song in song_xml.Item:
if self.stop_import_flag:
if self.stopImportFlag:
return
self._parse_song(song)
self._parseSong(song)
def _parse_song(self, song):
def _parseSong(self, song):
self._success = True
self._add_unicode_attribute(u'title', song.Title1, True)
self._addUnicodeAttribute(u'title', song.Title1, True)
if hasattr(song, u'Title2'):
self._add_unicode_attribute(u'alternate_title', song.Title2)
self._addUnicodeAttribute(u'alternateTitle', song.Title2)
if hasattr(song, u'SongNumber'):
self._add_unicode_attribute(u'song_number', song.SongNumber)
if self.song_number == u'0':
self.song_number = u''
self._add_authors(song)
self._addUnicodeAttribute(u'songNumber', song.SongNumber)
if self.songNumber == u'0':
self.songNumber = u''
self._addAuthors(song)
if hasattr(song, u'Copyright'):
self._add_copyright(song.Copyright)
self._addCopyright(song.Copyright)
if hasattr(song, u'LicenceAdmin1'):
self._add_copyright(song.LicenceAdmin1)
self._addCopyright(song.LicenceAdmin1)
if hasattr(song, u'LicenceAdmin2'):
self._add_copyright(song.LicenceAdmin2)
self._addCopyright(song.LicenceAdmin2)
if hasattr(song, u'BookReference'):
self._add_unicode_attribute(u'song_book_name', song.BookReference)
self._parse_and_add_lyrics(song)
self._addUnicodeAttribute(u'songBookName', song.BookReference)
self._parseAndAddLyrics(song)
if self._success:
if not self.finish():
self.log_error(song.Title1 if song.Title1 else u'')
self.logError(song.Title1 if song.Title1 else u'')
else:
self.set_defaults()
self.setDefaults()
def _add_unicode_attribute(self, self_attribute, import_attribute,
def _addUnicodeAttribute(self, self_attribute, import_attribute,
mandatory=False):
"""
Add imported values to the song model converting them to unicode at the
@ -119,7 +119,7 @@ class EasiSlidesImport(SongImport):
if mandatory:
self._success = False
def _add_authors(self, song):
def _addAuthors(self, song):
try:
authors = unicode(song.Writer).split(u',')
self.authors = \
@ -130,7 +130,7 @@ class EasiSlidesImport(SongImport):
except AttributeError:
pass
def _add_copyright(self, element):
def _addCopyright(self, element):
"""
Add a piece of copyright to the total copyright information for the
song.
@ -139,14 +139,14 @@ class EasiSlidesImport(SongImport):
The imported variable to get the data from.
"""
try:
self.add_copyright(unicode(element).strip())
self.addCopyright(unicode(element).strip())
except UnicodeDecodeError:
log.exception(u'Unicode error on decoding copyright: %s' % element)
self._success = False
except AttributeError:
pass
def _parse_and_add_lyrics(self, song):
def _parseAndAddLyrics(self, song):
try:
lyrics = unicode(song.Contents).strip()
except UnicodeDecodeError:
@ -295,7 +295,7 @@ class EasiSlidesImport(SongImport):
else:
continue
if tag in versetags:
self.verse_order_list.append(tag)
self.verseOrderList.append(tag)
else:
log.info(u'Got order item %s, which is not in versetags,'
u'dropping item from presentation order', tag)

View File

@ -49,15 +49,15 @@ def strip_rtf(blob, encoding):
control = False
clear_text = []
control_word = []
# workaround for \tx bug: remove one pair of curly braces
# workaround for \tx bug: remove one pair of curly braces
# if \tx is encountered
match = RTF_STRIPPING_REGEX.search(blob)
if match:
# start and end indices of match are curly braces - filter them out
blob = ''.join([blob[i] for i in xrange(len(blob))
blob = ''.join([blob[i] for i in xrange(len(blob))
if i != match.start() and i !=match.end()])
for c in blob:
if control:
# for delimiters, set control to False
@ -155,24 +155,24 @@ class EasyWorshipSongImport(SongImport):
def __init__(self, manager, **kwargs):
SongImport.__init__(self, manager, **kwargs)
def do_import(self):
def doImport(self):
# Open the DB and MB files if they exist
import_source_mb = self.import_source.replace('.DB', '.MB')
if not os.path.isfile(self.import_source):
import_source_mb = self.importSource.replace('.DB', '.MB')
if not os.path.isfile(self.importSource):
return
if not os.path.isfile(import_source_mb):
return
db_size = os.path.getsize(self.import_source)
db_size = os.path.getsize(self.importSource)
if db_size < 0x800:
return
db_file = open(self.import_source, 'rb')
self.memo_file = open(import_source_mb, 'rb')
db_file = open(self.importSource, 'rb')
self.memoFile = open(import_source_mb, 'rb')
# Don't accept files that are clearly not paradox files
record_size, header_size, block_size, first_block, num_fields \
= struct.unpack('<hhxb8xh17xh', db_file.read(35))
if header_size != 0x800 or block_size < 1 or block_size > 4:
db_file.close()
self.memo_file.close()
self.memoFile.close()
return
# Take a stab at how text is encoded
self.encoding = u'cp1252'
@ -204,7 +204,7 @@ class EasyWorshipSongImport(SongImport):
# There does not appear to be a _reliable_ way of getting the number
# of songs/records, so let's use file blocks for measuring progress.
total_blocks = (db_size - header_size) / (block_size * 1024)
self.import_wizard.progressBar.setMaximum(total_blocks)
self.importWizard.progressBar.setMaximum(total_blocks)
# Read the field description information
db_file.seek(120)
field_info = db_file.read(num_fields * 2)
@ -218,16 +218,16 @@ class EasyWorshipSongImport(SongImport):
field_info, i * 2)
field_descs.append(FieldDescEntry(field_name, field_type,
field_size))
self.set_record_struct(field_descs)
self.setRecordStruct(field_descs)
# Pick out the field description indexes we will need
try:
success = True
fi_title = self.find_field(u'Title')
fi_author = self.find_field(u'Author')
fi_copy = self.find_field(u'Copyright')
fi_admin = self.find_field(u'Administrator')
fi_words = self.find_field(u'Words')
fi_ccli = self.find_field(u'Song Number')
fi_title = self.findField(u'Title')
fi_author = self.findField(u'Author')
fi_copy = self.findField(u'Copyright')
fi_admin = self.findField(u'Administrator')
fi_words = self.findField(u'Words')
fi_ccli = self.findField(u'Song Number')
except IndexError:
# This is the wrong table
success = False
@ -239,18 +239,18 @@ class EasyWorshipSongImport(SongImport):
rec_count = (rec_count + record_size) / record_size
# Loop through each record within the current block
for i in range(rec_count):
if self.stop_import_flag:
if self.stopImportFlag:
break
raw_record = db_file.read(record_size)
self.fields = self.record_struct.unpack(raw_record)
self.set_defaults()
self.title = self.get_field(fi_title)
self.setDefaults()
self.title = self.getField(fi_title)
# Get remaining fields.
copy = self.get_field(fi_copy)
admin = self.get_field(fi_admin)
ccli = self.get_field(fi_ccli)
authors = self.get_field(fi_author)
words = self.get_field(fi_words)
copy = self.getField(fi_copy)
admin = self.getField(fi_admin)
ccli = self.getField(fi_ccli)
authors = self.getField(fi_author)
words = self.getField(fi_words)
# Set the SongImport object members.
if copy:
self.copyright = copy
@ -261,7 +261,7 @@ class EasyWorshipSongImport(SongImport):
unicode(translate('SongsPlugin.EasyWorshipSongImport',
'Administered by %s')) % admin
if ccli:
self.ccli_number = ccli
self.ccliNumber = ccli
if authors:
# Split up the authors
author_list = authors.split(u'/')
@ -270,7 +270,7 @@ class EasyWorshipSongImport(SongImport):
if len(author_list) < 2:
author_list = authors.split(u',')
for author_name in author_list:
self.add_author(author_name.strip())
self.addAuthor(author_name.strip())
if words:
# Format the lyrics
words = strip_rtf(words, self.encoding)
@ -281,9 +281,9 @@ class EasyWorshipSongImport(SongImport):
continue
verse_split = verse.split(u'\n', 1)
first_line_is_tag = False
# EW tags: verse, chorus, pre-chorus, bridge, tag,
# EW tags: verse, chorus, pre-chorus, bridge, tag,
# intro, ending, slide
for type in VerseType.Names+[u'tag', u'slide']:
for type in VerseType.Names+[u'tag', u'slide']:
type = type.lower()
ew_tag = verse_split[0].strip().lower()
if ew_tag.startswith(type):
@ -293,7 +293,7 @@ class EasyWorshipSongImport(SongImport):
first_line_is_tag = True
number_found = False
# check if tag is followed by number and/or note
if len(ew_tag) > len(type):
if len(ew_tag) > len(type):
match = NUMBER_REGEX.search(ew_tag)
if match:
number = match.group()
@ -305,23 +305,24 @@ class EasyWorshipSongImport(SongImport):
if not number_found:
verse_type += u'1'
break
self.add_verse(
verse_split[-1].strip() if first_line_is_tag else verse,
self.addVerse(
verse_split[-1].strip() \
if first_line_is_tag else verse,
verse_type)
if len(self.comments) > 5:
self.comments += unicode(
translate('SongsPlugin.EasyWorshipSongImport',
'\n[above are Song Tags with notes imported from \
EasyWorship]'))
if self.stop_import_flag:
if self.stopImportFlag:
break
if not self.finish():
self.log_error(self.import_source)
self.logError(self.importSource)
db_file.close()
self.memo_file.close()
self.memoFile.close()
def find_field(self, field_name):
return [i for i, x in enumerate(self.field_descs)
return [i for i, x in enumerate(self.fieldDescs)
if x.name == field_name][0]
def set_record_struct(self, field_descs):
@ -351,12 +352,12 @@ class EasyWorshipSongImport(SongImport):
fsl.append('Q')
else:
fsl.append('%ds' % field_desc.size)
self.record_struct = struct.Struct(''.join(fsl))
self.field_descs = field_descs
self.recordStruct = struct.Struct(''.join(fsl))
self.fieldDescs = field_descs
def get_field(self, field_desc_index):
field = self.fields[field_desc_index]
field_desc = self.field_descs[field_desc_index]
field_desc = self.fieldDescs[field_desc_index]
# Return None in case of 'blank' entries
if isinstance(field, str):
if len(field.rstrip('\0')) == 0:
@ -382,18 +383,18 @@ class EasyWorshipSongImport(SongImport):
struct.unpack_from('<II', field, len(field)-10)
sub_block = block_start & 0xff
block_start &= ~0xff
self.memo_file.seek(block_start)
memo_block_type, = struct.unpack('b', self.memo_file.read(1))
self.memoFile.seek(block_start)
memo_block_type, = struct.unpack('b', self.memoFile.read(1))
if memo_block_type == 2:
self.memo_file.seek(8, os.SEEK_CUR)
self.memoFile.seek(8, os.SEEK_CUR)
elif memo_block_type == 3:
if sub_block > 63:
return u''
self.memo_file.seek(11 + (5 * sub_block), os.SEEK_CUR)
sub_block_start, = struct.unpack('B', self.memo_file.read(1))
self.memo_file.seek(block_start + (sub_block_start * 16))
self.memoFile.seek(11 + (5 * sub_block), os.SEEK_CUR)
sub_block_start, = struct.unpack('B', self.memoFile.read(1))
self.memoFile.seek(block_start + (sub_block_start * 16))
else:
return u''
return self.memo_file.read(blob_size)
return self.memoFile.read(blob_size)
else:
return 0

View File

@ -115,23 +115,23 @@ class FoilPresenterImport(SongImport):
SongImport.__init__(self, manager, **kwargs)
self.FoilPresenter = FoilPresenter(self.manager)
def do_import(self):
def doImport(self):
"""
Imports the songs.
"""
self.import_wizard.progressBar.setMaximum(len(self.import_source))
self.importWizard.progressBar.setMaximum(len(self.importSource))
parser = etree.XMLParser(remove_blank_text=True)
for file_path in self.import_source:
if self.stop_import_flag:
for file_path in self.importSource:
if self.stopImportFlag:
return
self.import_wizard.incrementProgressBar(
self.importWizard.incrementProgressBar(
WizardStrings.ImportingType % os.path.basename(file_path))
try:
parsed_file = etree.parse(file_path, parser)
xml = unicode(etree.tostring(parsed_file))
self.FoilPresenter.xml_to_song(xml)
except etree.XMLSyntaxError:
self.log_error(file_path, SongStrings.XMLSyntaxError)
self.logError(file_path, SongStrings.XMLSyntaxError)
log.exception(u'XML syntax error in file %s' % file_path)

View File

@ -69,11 +69,11 @@ class SongMediaItem(MediaManagerItem):
def __init__(self, parent, plugin, icon):
self.IconPath = u'songs/song'
MediaManagerItem.__init__(self, parent, plugin, icon)
self.edit_song_form = EditSongForm(self, self.plugin.formparent,
self.editSongForm = EditSongForm(self, self.plugin.formparent,
self.plugin.manager)
self.openLyrics = OpenLyrics(self.plugin.manager)
self.singleServiceItem = False
self.song_maintenance_form = SongMaintenanceForm(
self.songMaintenanceForm = SongMaintenanceForm(
self.plugin.manager, self)
# Holds information about whether the edit is remotly triggered and
# which Song is required.
@ -316,25 +316,26 @@ class SongMediaItem(MediaManagerItem):
self.onClearTextButtonClick()
def onImportClick(self):
if not hasattr(self, u'import_wizard'):
self.import_wizard = SongImportForm(self, self.plugin)
if self.import_wizard.exec_() == QtGui.QDialog.Accepted:
if not hasattr(self, u'importWizard'):
self.importWizard = SongImportForm(self, self.plugin)
if self.importWizard.exec_() == QtGui.QDialog.Accepted:
Receiver.send_message(u'songs_load_list')
def onExportClick(self):
export_wizard = SongExportForm(self, self.plugin)
export_wizard.exec_()
if not hasattr(self, u'exportWizard'):
self.exportWizard = SongExportForm(self, self.plugin)
self.exportWizard.exec_()
def onNewClick(self):
log.debug(u'onNewClick')
self.edit_song_form.newSong()
self.edit_song_form.exec_()
self.editSongForm.newSong()
self.editSongForm.exec_()
self.onClearTextButtonClick()
self.onSelectionChange()
self.autoSelectId = -1
def onSongMaintenanceClick(self):
self.song_maintenance_form.exec_()
self.songMaintenanceForm.exec_()
def onRemoteEditClear(self):
log.debug(u'onRemoteEditClear')
@ -354,8 +355,8 @@ class SongMediaItem(MediaManagerItem):
if valid:
self.remoteSong = song_id
self.remoteTriggered = remote_type
self.edit_song_form.loadSong(song_id, remote_type == u'P')
self.edit_song_form.exec_()
self.editSongForm.loadSong(song_id, remote_type == u'P')
self.editSongForm.exec_()
self.autoSelectId = -1
self.onSongListLoad()
@ -367,8 +368,8 @@ class SongMediaItem(MediaManagerItem):
if check_item_selected(self.listView, UiStrings().SelectEdit):
self.editItem = self.listView.currentItem()
item_id = (self.editItem.data(QtCore.Qt.UserRole)).toInt()[0]
self.edit_song_form.loadSong(item_id, False)
self.edit_song_form.exec_()
self.editSongForm.loadSong(item_id, False)
self.editSongForm.exec_()
self.autoSelectId = -1
self.onSongListLoad()
self.editItem = None
@ -390,6 +391,20 @@ class SongMediaItem(MediaManagerItem):
return
for item in items:
item_id = (item.data(QtCore.Qt.UserRole)).toInt()[0]
media_files = self.plugin.manager.get_all_objects(MediaFile,
MediaFile.song_id == item_id)
for media_file in media_files:
try:
os.remove(media_file.file_name)
except:
log.exception('Could not remove file: %s', audio)
try:
save_path = os.path.join(AppLocation.get_section_data_path(
self.plugin.name), 'audio', str(item_id))
if os.path.exists(save_path):
os.rmdir(save_path)
except OSError:
log.exception(u'Could not remove directory: %s', save_path)
self.plugin.manager.delete_object(Song, item_id)
self.onSearchTextButtonClick()
@ -411,7 +426,8 @@ class SongMediaItem(MediaManagerItem):
self.plugin.manager.save_object(new_song)
self.onSongListLoad()
def generateSlideData(self, service_item, item=None, xmlVersion=False):
def generateSlideData(self, service_item, item=None, xmlVersion=False,
remote=False):
log.debug(u'generateSlideData (%s:%s)' % (service_item, item))
item_id = self._getIdOfItemToGenerate(item, self.remoteSong)
service_item.add_capability(ItemCapabilities.CanEdit)

View File

@ -32,6 +32,8 @@ openlp.org 1.x song databases into the current installation database.
import logging
from chardet.universaldetector import UniversalDetector
import sqlite
import sys
import os
from openlp.core.lib import translate
from openlp.plugins.songs.lib import retrieve_windows_encoding
@ -44,7 +46,7 @@ class OpenLP1SongImport(SongImport):
The :class:`OpenLP1SongImport` class provides OpenLP with the ability to
import song databases from installations of openlp.org 1.x.
"""
last_encoding = u'windows-1252'
lastEncoding = u'windows-1252'
def __init__(self, manager, **kwargs):
"""
@ -57,23 +59,23 @@ class OpenLP1SongImport(SongImport):
The database providing the data to import.
"""
SongImport.__init__(self, manager, **kwargs)
self.available_themes = \
self.availableThemes = \
kwargs[u'plugin'].formparent.themeManagerContents.getThemes()
def do_import(self):
def doImport(self):
"""
Run the import for an openlp.org 1.x song database.
"""
if not self.import_source.endswith(u'.olp'):
self.log_error(self.import_source,
if not self.importSource.endswith(u'.olp'):
self.logError(self.importSource,
translate('SongsPlugin.OpenLP1SongImport',
'Not a valid openlp.org 1.x song database.'))
return
encoding = self.get_encoding()
encoding = self.getEncoding()
if not encoding:
return
# Connect to the database.
connection = sqlite.connect(self.import_source, mode=0444,
connection = sqlite.connect(self.importSource, mode=0444,
encoding=(encoding, 'replace'))
cursor = connection.cursor()
# Determine if we're using a new or an old DB.
@ -94,64 +96,66 @@ class OpenLP1SongImport(SongImport):
cursor.execute(u'SELECT settingsid, settingsname FROM settings')
themes = {}
for theme_id, theme_name in cursor.fetchall():
if theme_name in self.available_themes:
if theme_name in self.availableThemes:
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, '
u'copyrightinfo, settingsid FROM songs')
songs = cursor.fetchall()
self.import_wizard.progressBar.setMaximum(len(songs))
self.importWizard.progressBar.setMaximum(len(songs))
for song in songs:
self.set_defaults()
if self.stop_import_flag:
self.setDefaults()
if self.stopImportFlag:
break
song_id = song[0]
self.title = song[1]
lyrics = song[2].replace(u'\r\n', u'\n')
self.add_copyright(song[3])
self.addCopyright(song[3])
if themes.has_key(song[4]):
self.theme_name = themes[song[4]]
self.themeName = themes[song[4]]
verses = lyrics.split(u'\n\n')
for verse in verses:
if verse.strip():
self.add_verse(verse.strip())
self.addVerse(verse.strip())
cursor.execute(u'-- types int')
cursor.execute(u'SELECT authorid FROM songauthors '
u'WHERE songid = %s' % song_id)
author_ids = cursor.fetchall()
for author_id in author_ids:
if self.stop_import_flag:
if self.stopImportFlag:
break
for author in authors:
if author[0] == author_id[0]:
self.parse_author(author[1])
self.parseAuthor(author[1])
break
if self.stop_import_flag:
if self.stopImportFlag:
break
if new_db:
cursor.execute(u'-- types int')
cursor.execute(u'SELECT trackid FROM songtracks '
cursor.execute(u'-- types int, int')
cursor.execute(u'SELECT trackid, listindex '
u'FROM songtracks '
u'WHERE songid = %s ORDER BY listindex' % song_id)
track_ids = cursor.fetchall()
for track_id in track_ids:
if self.stop_import_flag:
for track_id, listindex in track_ids:
if self.stopImportFlag:
break
for track in tracks:
if track[0] == track_id[0]:
self.add_media_file(track[1])
if track[0] == track_id:
media_file = self.expandMediaFile(track[1])
self.addMediaFile(media_file, listindex)
break
if self.stop_import_flag:
if self.stopImportFlag:
break
if not self.finish():
self.log_error(self.import_source)
self.logError(self.importSource)
def get_encoding(self):
def getEncoding(self):
"""
Detect character encoding of an openlp.org 1.x song database.
"""
# Connect to the database.
connection = sqlite.connect(self.import_source, mode=0444)
connection = sqlite.connect(self.importSource, mode=0444)
cursor = connection.cursor()
detector = UniversalDetector()
@ -186,3 +190,22 @@ class OpenLP1SongImport(SongImport):
return detector.result[u'encoding']
detector.close()
return retrieve_windows_encoding(detector.result[u'encoding'])
def expandMediaFile(self, filename):
"""
When you're on Windows, this function expands the file name to include
the path to OpenLP's application data directory. If you are not on
Windows, it returns the original file name.
``filename``
The filename to expand.
"""
if sys.platform != u'win32' and \
not os.environ.get(u'ALLUSERSPROFILE') and \
not os.environ.get(u'APPDATA'):
return filename
common_app_data = os.path.join(os.environ[u'ALLUSERSPROFILE'],
os.path.split(os.environ[u'APPDATA'])[1])
if not common_app_data:
return filename
return os.path.join(common_app_data, u'openlp.org', 'Audio', filename)

View File

@ -95,22 +95,22 @@ class OpenLPSongImport(SongImport):
The database providing the data to import.
"""
SongImport.__init__(self, manager, **kwargs)
self.source_session = None
self.sourceSession = None
def do_import(self):
def doImport(self):
"""
Run the import for an OpenLP version 2 song database.
"""
if not self.import_source.endswith(u'.sqlite'):
self.log_error(self.import_source,
if not self.importSource.endswith(u'.sqlite'):
self.logError(self.importSource,
translate('SongsPlugin.OpenLPSongImport',
'Not a valid OpenLP 2.0 song database.'))
return
self.import_source = u'sqlite:///%s' % self.import_source
engine = create_engine(self.import_source)
self.importSource = u'sqlite:///%s' % self.importSource
engine = create_engine(self.importSource)
source_meta = MetaData()
source_meta.reflect(engine)
self.source_session = scoped_session(sessionmaker(bind=engine))
self.sourceSession = scoped_session(sessionmaker(bind=engine))
if u'media_files' in source_meta.tables.keys():
has_media_files = True
else:
@ -156,9 +156,9 @@ class OpenLPSongImport(SongImport):
except UnmappedClassError:
mapper(OldTopic, source_topics_table)
source_songs = self.source_session.query(OldSong).all()
if self.import_wizard:
self.import_wizard.progressBar.setMaximum(len(source_songs))
source_songs = self.sourceSession.query(OldSong).all()
if self.importWizard:
self.importWizard.progressBar.setMaximum(len(source_songs))
for song in source_songs:
new_song = Song()
new_song.title = song.title
@ -201,22 +201,22 @@ class OpenLPSongImport(SongImport):
if existing_topic is None:
existing_topic = Topic.populate(name=topic.name)
new_song.topics.append(existing_topic)
# if has_media_files:
# if song.media_files:
# for media_file in song.media_files:
# existing_media_file = \
# self.manager.get_object_filtered(MediaFile,
# MediaFile.file_name == media_file.file_name)
# if existing_media_file:
# new_song.media_files.append(existing_media_file)
# else:
# new_song.media_files.append(MediaFile.populate(
# file_name=media_file.file_name))
if has_media_files:
if song.media_files:
for media_file in song.media_files:
existing_media_file = \
self.manager.get_object_filtered(MediaFile,
MediaFile.file_name == media_file.file_name)
if existing_media_file:
new_song.media_files.append(existing_media_file)
else:
new_song.media_files.append(MediaFile.populate(
file_name=media_file.file_name))
clean_song(self.manager, new_song)
self.manager.save_object(new_song)
if self.import_wizard:
self.import_wizard.incrementProgressBar(
if self.importWizard:
self.importWizard.incrementProgressBar(
WizardStrings.ImportingType % new_song.title)
if self.stop_import_flag:
if self.stopImportFlag:
break
engine.dispose()

View File

@ -59,58 +59,58 @@ class OooImport(SongImport):
"""
SongImport.__init__(self, manager, **kwargs)
self.document = None
self.process_started = False
self.processStarted = False
def do_import(self):
if not isinstance(self.import_source, list):
def doImport(self):
if not isinstance(self.importSource, list):
return
try:
self.start_ooo()
except NoConnectException as exc:
self.log_error(
self.import_source[0],
self.logError(
self.importSource[0],
translate('SongsPlugin.SongImport',
'Cannot access OpenOffice or LibreOffice'))
log.error(exc)
return
self.import_wizard.progressBar.setMaximum(len(self.import_source))
for filename in self.import_source:
if self.stop_import_flag:
self.importWizard.progressBar.setMaximum(len(self.importSource))
for filename in self.importSource:
if self.stopImportFlag:
break
filename = unicode(filename)
if os.path.isfile(filename):
self.open_ooo_file(filename)
self.openOooFile(filename)
if self.document:
self.process_ooo_document()
self.close_ooo_file()
self.processOooDocument()
self.closeOooFile()
else:
self.log_error(self.filepath,
self.logError(self.filepath,
translate('SongsPlugin.SongImport',
'Unable to open file'))
else:
self.log_error(self.filepath,
self.logError(self.filepath,
translate('SongsPlugin.SongImport', 'File not found'))
self.close_ooo()
self.closeOoo()
def process_ooo_document(self):
def processOooDocument(self):
"""
Handle the import process for OpenOffice files. This method facilitates
allowing subclasses to handle specific types of OpenOffice files.
"""
if self.document.supportsService(
"com.sun.star.presentation.PresentationDocument"):
self.process_pres()
self.processPres()
if self.document.supportsService("com.sun.star.text.TextDocument"):
self.process_doc()
self.processDoc()
def start_ooo(self):
def startOoo(self):
"""
Start OpenOffice.org process
TODO: The presentation/Impress plugin may already have it running
"""
if os.name == u'nt':
self.start_ooo_process()
self.desktop = self.ooo_manager.createInstance(
self.startOooProcess()
self.desktop = self.oooManager.createInstance(
u'com.sun.star.frame.Desktop')
else:
context = uno.getComponentContext()
@ -123,7 +123,7 @@ class OooImport(SongImport):
uno_instance = get_uno_instance(resolver)
except NoConnectException:
log.exception("Failed to resolve uno connection")
self.start_ooo_process()
self.startOooProcess()
loop += 1
else:
manager = uno_instance.ServiceManager
@ -132,22 +132,22 @@ class OooImport(SongImport):
return
raise
def start_ooo_process(self):
def startOooProcess(self):
try:
if os.name == u'nt':
self.ooo_manager = Dispatch(u'com.sun.star.ServiceManager')
self.ooo_manager._FlagAsMethod(u'Bridge_GetStruct')
self.ooo_manager._FlagAsMethod(u'Bridge_GetValueObject')
self.oooManager = Dispatch(u'com.sun.star.ServiceManager')
self.oooManager._FlagAsMethod(u'Bridge_GetStruct')
self.oooManager._FlagAsMethod(u'Bridge_GetValueObject')
else:
cmd = get_uno_command()
process = QtCore.QProcess()
process.startDetached(cmd)
process.waitForStarted()
self.process_started = True
self.processStarted = True
except:
log.exception("start_ooo_process failed")
def open_ooo_file(self, filepath):
def openOooFile(self, filepath):
"""
Open the passed file in OpenOffice.org Impress
"""
@ -166,29 +166,29 @@ class OooImport(SongImport):
if not self.document.supportsService(
"com.sun.star.presentation.PresentationDocument") and not \
self.document.supportsService("com.sun.star.text.TextDocument"):
self.close_ooo_file()
self.closeOooFile()
else:
self.import_wizard.incrementProgressBar(
self.importWizard.incrementProgressBar(
u'Processing file ' + filepath, 0)
except AttributeError:
log.exception("open_ooo_file failed: %s", url)
return
def close_ooo_file(self):
def closeOooFile(self):
"""
Close file.
"""
self.document.close(True)
self.document = None
def close_ooo(self):
def closeOoo(self):
"""
Close OOo. But only if we started it and not on windows
"""
if self.process_started:
if self.processStarted:
self.desktop.terminate()
def process_pres(self):
def processPres(self):
"""
Process the file
"""
@ -196,8 +196,8 @@ class OooImport(SongImport):
slides = doc.getDrawPages()
text = u''
for slide_no in range(slides.getCount()):
if self.stop_import_flag:
self.import_wizard.incrementProgressBar(u'Import cancelled', 0)
if self.stopImportFlag:
self.importWizard.incrementProgressBar(u'Import cancelled', 0)
return
slide = slides.getByIndex(slide_no)
slidetext = u''
@ -209,10 +209,10 @@ class OooImport(SongImport):
if slidetext.strip() == u'':
slidetext = u'\f'
text += slidetext
self.process_songs_text(text)
self.processSongsText(text)
return
def process_doc(self):
def processDoc(self):
"""
Process the doc file, a paragraph at a time
"""
@ -231,16 +231,16 @@ class OooImport(SongImport):
if textportion.BreakType in (PAGE_AFTER, PAGE_BOTH):
paratext += u'\f'
text += paratext + u'\n'
self.process_songs_text(text)
self.processSongsText(text)
def process_songs_text(self, text):
songtexts = self.tidy_text(text).split(u'\f')
self.set_defaults()
def processSongsText(self, text):
songtexts = self.tidyText(text).split(u'\f')
self.setDefaults()
for songtext in songtexts:
if songtext.strip():
self.process_song_text(songtext.strip())
if self.check_complete():
self.processSongText(songtext.strip())
if self.checkComplete():
self.finish()
self.set_defaults()
if self.check_complete():
self.setDefaults()
if self.checkComplete():
self.finish()

View File

@ -53,16 +53,16 @@ class OpenLyricsImport(SongImport):
SongImport.__init__(self, manager, **kwargs)
self.openLyrics = OpenLyrics(self.manager)
def do_import(self):
def doImport(self):
"""
Imports the songs.
"""
self.import_wizard.progressBar.setMaximum(len(self.import_source))
self.importWizard.progressBar.setMaximum(len(self.importSource))
parser = etree.XMLParser(remove_blank_text=True)
for file_path in self.import_source:
if self.stop_import_flag:
for file_path in self.importSource:
if self.stopImportFlag:
return
self.import_wizard.incrementProgressBar(
self.importWizard.incrementProgressBar(
WizardStrings.ImportingType % os.path.basename(file_path))
try:
# Pass a file object, because lxml does not cope with some
@ -72,4 +72,4 @@ class OpenLyricsImport(SongImport):
self.openLyrics.xml_to_song(xml)
except etree.XMLSyntaxError:
log.exception(u'XML syntax error in file %s' % file_path)
self.log_error(file_path, SongStrings.XMLSyntaxError)
self.logError(file_path, SongStrings.XMLSyntaxError)

View File

@ -107,32 +107,32 @@ class OpenSongImport(SongImport):
"""
SongImport.__init__(self, manager, **kwargs)
def do_import(self):
self.import_wizard.progressBar.setMaximum(len(self.import_source))
for filename in self.import_source:
if self.stop_import_flag:
def doImport(self):
self.importWizard.progressBar.setMaximum(len(self.importSource))
for filename in self.importSource:
if self.stopImportFlag:
return
song_file = open(filename)
self.do_import_file(song_file)
self.doImportFile(song_file)
song_file.close()
def do_import_file(self, file):
def doImportFile(self, file):
"""
Process the OpenSong file - pass in a file-like object, not a file path.
"""
self.set_defaults()
self.setDefaults()
try:
tree = objectify.parse(file)
except (Error, LxmlError):
self.log_error(file.name, SongStrings.XMLSyntaxError)
self.logError(file.name, SongStrings.XMLSyntaxError)
log.exception(u'Error parsing XML')
return
root = tree.getroot()
fields = dir(root)
decode = {
u'copyright': self.add_copyright,
u'copyright': self.addCopyright,
u'ccli': u'ccli_number',
u'author': self.parse_author,
u'author': self.parseAuthor,
u'title': u'title',
u'aka': u'alternate_title',
u'hymn_number': u'song_number'
@ -214,7 +214,7 @@ class OpenSongImport(SongImport):
verses[verse_tag][verse_num][inst] = []
our_verse_order.append([verse_tag, verse_num, inst])
# Tidy text and remove the ____s from extended words
this_line = self.tidy_text(this_line)
this_line = self.tidyText(this_line)
this_line = this_line.replace(u'_', u'')
this_line = this_line.replace(u'|', u'\n')
verses[verse_tag][verse_num][inst].append(this_line)
@ -223,9 +223,9 @@ class OpenSongImport(SongImport):
for (verse_tag, verse_num, inst) in our_verse_order:
verse_def = u'%s%s' % (verse_tag, verse_num)
lines = u'\n'.join(verses[verse_tag][verse_num][inst])
self.add_verse(lines, verse_def)
self.addVerse(lines, verse_def)
if not self.verses:
self.add_verse('')
self.addVerse('')
# figure out the presentation order, if present
if u'presentation' in fields and root.presentation:
order = unicode(root.presentation)
@ -246,9 +246,9 @@ class OpenSongImport(SongImport):
verse_def = u'%s%s' % (verse_tag, verse_num)
if verses.has_key(verse_tag) and \
verses[verse_tag].has_key(verse_num):
self.verse_order_list.append(verse_def)
self.verseOrderList.append(verse_def)
else:
log.info(u'Got order %s but not in verse tags, dropping'
u'this item from presentation order', verse_def)
if not self.finish():
self.log_error(file.name)
self.logError(file.name)

View File

@ -83,32 +83,32 @@ class SofImport(OooImport):
OooImport.__init__(self, manager, **kwargs)
self.song = False
def process_ooo_document(self):
def processOooDocument(self):
"""
Handle the import process for SoF files.
"""
self.process_sof_file()
self.processSofFile()
def process_sof_file(self):
def processSofFile(self):
"""
Process the RTF file, a paragraph at a time
"""
self.blanklines = 0
self.new_song()
self.blankLines = 0
self.newSong()
try:
paragraphs = self.document.getText().createEnumeration()
while paragraphs.hasMoreElements():
if self.stop_import_flag:
if self.stopImportFlag:
return
paragraph = paragraphs.nextElement()
if paragraph.supportsService("com.sun.star.text.Paragraph"):
self.process_paragraph(paragraph)
self.processParagraph(paragraph)
except RuntimeException as exc:
log.exception(u'Error processing file: %s', exc)
if not self.finish():
self.log_error(self.filepath)
self.logError(self.filepath)
def process_paragraph(self, paragraph):
def processParagraph(self, paragraph):
"""
Process a paragraph.
In the first book, a paragraph is a single line. In the latter ones
@ -124,26 +124,26 @@ class SofImport(OooImport):
while textportions.hasMoreElements():
textportion = textportions.nextElement()
if textportion.BreakType in (PAGE_BEFORE, PAGE_BOTH):
self.process_paragraph_text(text)
self.new_song()
self.processParagraphText(text)
self.newSong()
text = u''
text += self.process_textportion(textportion)
if textportion.BreakType in (PAGE_AFTER, PAGE_BOTH):
self.process_paragraph_text(text)
self.new_song()
self.processParagraphText(text)
self.newSong()
text = u''
self.process_paragraph_text(text)
self.processParagraphText(text)
def process_paragraph_text(self, text):
def processParagraphText(self, text):
"""
Split the paragraph text into multiple lines and process
"""
for line in text.split(u'\n'):
self.process_paragraph_line(line)
if self.blanklines > 2:
self.new_song()
self.processParagraphLine(line)
if self.blankLines > 2:
self.newSong()
def process_paragraph_line(self, text):
def processParagraphLine(self, text):
"""
Process a single line. Throw away that text which isn't relevant, i.e.
stuff that appears at the end of the song.
@ -151,16 +151,16 @@ class SofImport(OooImport):
"""
text = text.strip()
if text == u'':
self.blanklines += 1
if self.blanklines > 1:
self.blankLines += 1
if self.blankLines > 1:
return
if self.title != u'':
self.finish_verse()
self.finishVerse()
return
self.blanklines = 0
if self.skip_to_close_bracket:
self.blankLines = 0
if self.skipToCloseBracket:
if text.endswith(u')'):
self.skip_to_close_bracket = False
self.skipToCloseBracket = False
return
if text.startswith(u'CCL Licence'):
self.italics = False
@ -169,24 +169,24 @@ class SofImport(OooImport):
return
if text.startswith(u'(NB.') or text.startswith(u'(Regrettably') \
or text.startswith(u'(From'):
self.skip_to_close_bracket = True
self.skipToCloseBracket = True
return
if text.startswith(u'Copyright'):
self.add_copyright(text)
self.addCopyright(text)
return
if text == u'(Repeat)':
self.finish_verse()
self.repeat_verse()
self.finishVerse()
self.repeatVerse()
return
if self.title == u'':
if self.copyright == u'':
self.add_sof_author(text)
self.addSofAuthor(text)
else:
self.add_copyright(text)
self.addCopyright(text)
return
self.add_verse_line(text)
self.addVerseLine(text)
def process_textportion(self, textportion):
def processTextPortion(self, textportion):
"""
Process a text portion. Here we just get the text and detect if
it's bold or italics. If it's bold then its a song number or song title.
@ -199,53 +199,53 @@ class SofImport(OooImport):
return text
if textportion.CharWeight == BOLD:
boldtext = text.strip()
if boldtext.isdigit() and self.song_number == '':
self.add_songnumber(boldtext)
if boldtext.isdigit() and self.songNumber == '':
self.addSongNumber(boldtext)
return u''
if self.title == u'':
text = self.uncap_text(text)
self.add_title(text)
self.addTitle(text)
return text
if text.strip().startswith(u'('):
return text
self.italics = (textportion.CharPosture == ITALIC)
return text
def new_song(self):
def newSong(self):
"""
A change of song. Store the old, create a new
... but only if the last song was complete. If not, stick with it
"""
if self.song:
self.finish_verse()
if not self.check_complete():
self.finishVerse()
if not self.checkComplete():
return
self.finish()
self.song = True
self.set_defaults()
self.skip_to_close_bracket = False
self.is_chorus = False
self.setDefaults()
self.skipToCloseBracket = False
self.isChorus = False
self.italics = False
self.currentverse = u''
self.currentVerse = u''
def add_songnumber(self, song_no):
def addSongNumber(self, song_no):
"""
Add a song number, store as alternate title. Also use the song
number to work out which songbook we're in
"""
self.song_number = song_no
self.alternate_title = song_no + u'.'
self.song_book_pub = u'Kingsway Publications'
self.songNumber = song_no
self.alternateTitle = song_no + u'.'
self.songBook_pub = u'Kingsway Publications'
if int(song_no) <= 640:
self.song_book = u'Songs of Fellowship 1'
self.songBook = u'Songs of Fellowship 1'
elif int(song_no) <= 1150:
self.song_book = u'Songs of Fellowship 2'
self.songBook = u'Songs of Fellowship 2'
elif int(song_no) <= 1690:
self.song_book = u'Songs of Fellowship 3'
self.songBook = u'Songs of Fellowship 3'
else:
self.song_book = u'Songs of Fellowship 4'
self.songBook = u'Songs of Fellowship 4'
def add_title(self, text):
def addTitle(self, text):
"""
Add the title to the song. Strip some leading/trailing punctuation that
we don't want in a title
@ -256,9 +256,9 @@ class SofImport(OooImport):
if title.endswith(u','):
title = title[:-1]
self.title = title
self.import_wizard.incrementProgressBar(u'Processing song ' + title, 0)
self.importWizard.incrementProgressBar(u'Processing song ' + title, 0)
def add_sof_author(self, text):
def addSofAuthor(self, text):
"""
Add the author. OpenLP stores them individually so split by 'and', '&'
and comma.
@ -266,42 +266,42 @@ class SofImport(OooImport):
"Mr Smith" and "Mrs Smith".
"""
text = text.replace(u' and ', u' & ')
self.parse_author(text)
self.parseAuthor(text)
def add_verse_line(self, text):
def addVerseLine(self, text):
"""
Add a line to the current verse. If the formatting has changed and
we're beyond the second line of first verse, then this indicates
a change of verse. Italics are a chorus
"""
if self.italics != self.is_chorus and ((len(self.verses) > 0) or
(self.currentverse.count(u'\n') > 1)):
self.finish_verse()
if self.italics != self.isChorus and ((len(self.verses) > 0) or
(self.currentVerse.count(u'\n') > 1)):
self.finishVerse()
if self.italics:
self.is_chorus = True
self.currentverse += text + u'\n'
self.isChorus = True
self.currentVerse += text + u'\n'
def finish_verse(self):
def finishVerse(self):
"""
Verse is finished, store it. Note in book 1+2, some songs are formatted
incorrectly. Here we try and split songs with missing line breaks into
the correct number of verses.
"""
if self.currentverse.strip() == u'':
if self.currentVerse.strip() == u'':
return
if self.is_chorus:
if self.isChorus:
versetag = u'C'
splitat = None
else:
versetag = u'V'
splitat = self.verse_splits(self.song_number)
splitat = self.verseSplits(self.songNumber)
if splitat:
ln = 0
verse = u''
for line in self.currentverse.split(u'\n'):
for line in self.currentVerse.split(u'\n'):
ln += 1
if line == u'' or ln > splitat:
self.add_sof_verse(verse, versetag)
self.addSofVerse(verse, versetag)
ln = 0
if line:
verse = line + u'\n'
@ -310,19 +310,19 @@ class SofImport(OooImport):
else:
verse += line + u'\n'
if verse:
self.add_sof_verse(verse, versetag)
self.addSofVerse(verse, versetag)
else:
self.add_sof_verse(self.currentverse, versetag)
self.currentverse = u''
self.is_chorus = False
self.addSofVerse(self.currentVerse, versetag)
self.currentVerse = u''
self.isChorus = False
def add_sof_verse(self, lyrics, tag):
self.add_verse(lyrics, tag)
if not self.is_chorus and u'C1' in self.verse_order_list_generated:
self.verse_order_list_generated.append(u'C1')
self.verse_order_list_generated_useful = True
def addSofVerse(self, lyrics, tag):
self.addVerse(lyrics, tag)
if not self.isChorus and u'C1' in self.verseOrderListGenerated:
self.verseOrderListGenerated.append(u'C1')
self.verseOrderListGenerated_useful = True
def uncap_text(self, text):
def uncapText(self, text):
"""
Words in the title are in all capitals, so we lowercase them.
However some of these words, e.g. referring to God need a leading
@ -348,7 +348,7 @@ class SofImport(OooImport):
text = u''.join(textarr)
return text
def verse_splits(self, song_number):
def verseSplits(self, song_number):
"""
Because someone at Kingsway forgot to check the 1+2 RTF file,
some verses were not formatted correctly.

View File

@ -91,27 +91,27 @@ class SongBeamerImport(SongImport):
(re.compile(u'<align.*?>'), u''),
(re.compile(u'<valign.*?>'), u'')
]
def __init__(self, manager, **kwargs):
"""
Initialise the Song Beamer importer.
"""
SongImport.__init__(self, manager, **kwargs)
def do_import(self):
def doImport(self):
"""
Receive a single file or a list of files to import.
"""
self.import_wizard.progressBar.setMaximum(len(self.import_source))
if not isinstance(self.import_source, list):
self.importWizard.progressBar.setMaximum(len(self.importSource))
if not isinstance(self.importSource, list):
return
for file in self.import_source:
for file in self.importSource:
# TODO: check that it is a valid SongBeamer file
if self.stop_import_flag:
if self.stopImportFlag:
return
self.set_defaults()
self.current_verse = u''
self.current_verse_type = VerseType.Tags[VerseType.Verse]
self.setDefaults()
self.currentVerse = u''
self.currentVerseType = VerseType.Tags[VerseType.Verse]
read_verses = False
file_name = os.path.split(file)[1]
if os.path.isfile(file):
@ -119,48 +119,48 @@ class SongBeamerImport(SongImport):
details = chardet.detect(detect_file.read())
detect_file.close()
infile = codecs.open(file, u'r', details['encoding'])
songData = infile.readlines()
song_data = infile.readlines()
infile.close()
else:
continue
self.title = file_name.split('.sng')[0]
read_verses = False
for line in songData:
for line in song_data:
# Just make sure that the line is of the type 'Unicode'.
line = unicode(line).strip()
if line.startswith(u'#') and not read_verses:
self.parse_tags(line)
self.parseTags(line)
elif line.startswith(u'---'):
if self.current_verse:
self.replace_html_tags()
self.add_verse(self.current_verse,
self.current_verse_type)
self.current_verse = u''
self.current_verse_type = VerseType.Tags[VerseType.Verse]
if self.currentVerse:
self.replaceHtmlTags()
self.addVerse(self.currentVerse,
self.currentVerseType)
self.currentVerse = u''
self.currentVerseType = VerseType.Tags[VerseType.Verse]
read_verses = True
verse_start = True
elif read_verses:
if verse_start:
verse_start = False
if not self.check_verse_marks(line):
self.current_verse = line + u'\n'
if not self.checkVerseMarks(line):
self.currentVerse = line + u'\n'
else:
self.current_verse += line + u'\n'
if self.current_verse:
self.replace_html_tags()
self.add_verse(self.current_verse, self.current_verse_type)
self.currentVerse += line + u'\n'
if self.currentVerse:
self.replaceHtmlTags()
self.addVerse(self.currentVerse, self.currentVerseType)
if not self.finish():
self.log_error(file)
self.logError(file)
def replace_html_tags(self):
def replaceHtmlTags(self):
"""
This can be called to replace SongBeamer's specific (html) tags with
OpenLP's specific (html) tags.
"""
for pair in SongBeamerImport.HTML_TAG_PAIRS:
self.current_verse = pair[0].sub(pair[1], self.current_verse)
self.currentVerse = pair[0].sub(pair[1], self.currentVerse)
def parse_tags(self, line):
def parseTags(self, line):
"""
Parses a meta data line.
@ -176,11 +176,11 @@ class SongBeamerImport(SongImport):
if not tag_val[0] or not tag_val[1]:
return
if tag_val[0] == u'#(c)':
self.add_copyright(tag_val[1])
self.addCopyright(tag_val[1])
elif tag_val[0] == u'#AddCopyrightInfo':
pass
elif tag_val[0] == u'#Author':
self.parse_author(tag_val[1])
self.parseAuthor(tag_val[1])
elif tag_val[0] == u'#BackgroundImage':
pass
elif tag_val[0] == u'#Bible':
@ -188,7 +188,7 @@ class SongBeamerImport(SongImport):
elif tag_val[0] == u'#Categories':
self.topics = tag_val[1].split(',')
elif tag_val[0] == u'#CCLI':
self.ccli_number = tag_val[1]
self.ccliNumber = tag_val[1]
elif tag_val[0] == u'#Chords':
pass
elif tag_val[0] == u'#ChurchSongID':
@ -220,7 +220,7 @@ class SongBeamerImport(SongImport):
elif tag_val[0] == u'#LangCount':
pass
elif tag_val[0] == u'#Melody':
self.parse_author(tag_val[1])
self.parseAuthor(tag_val[1])
elif tag_val[0] == u'#NatCopyright':
pass
elif tag_val[0] == u'#OTitle':
@ -235,10 +235,10 @@ class SongBeamerImport(SongImport):
song_book_pub = tag_val[1]
elif tag_val[0] == u'#Songbook' or tag_val[0] == u'#SongBook':
book_data = tag_val[1].split(u'/')
self.song_book_name = book_data[0].strip()
self.songBookName = book_data[0].strip()
if len(book_data) == 2:
number = book_data[1].strip()
self.song_number = number if number.isdigit() else u''
self.songNumber = number if number.isdigit() else u''
elif tag_val[0] == u'#Speed':
pass
elif tag_val[0] == u'Tempo':
@ -269,7 +269,7 @@ class SongBeamerImport(SongImport):
# TODO: add the verse order.
pass
def check_verse_marks(self, line):
def checkVerseMarks(self, line):
"""
Check and add the verse's MarkType. Returns ``True`` if the given line
contains a correct verse mark otherwise ``False``.
@ -279,10 +279,10 @@ class SongBeamerImport(SongImport):
"""
marks = line.split(u' ')
if len(marks) <= 2 and marks[0] in SongBeamerTypes.MarkTypes:
self.current_verse_type = SongBeamerTypes.MarkTypes[marks[0]]
self.currentVerseType = SongBeamerTypes.MarkTypes[marks[0]]
if len(marks) == 2:
# If we have a digit, we append it to current_verse_type.
if marks[1].isdigit():
self.current_verse_type += marks[1]
self.currentVerseType += marks[1]
return True
return False

View File

@ -26,11 +26,14 @@
###############################################################################
import logging
import re
import shutil
import os
from PyQt4 import QtCore
from openlp.core.lib import Receiver, translate
from openlp.core.ui.wizard import WizardStrings
from openlp.core.utils import AppLocation
from openlp.plugins.songs.lib import clean_song, VerseType
from openlp.plugins.songs.lib.db import Song, Author, Topic, Book, MediaFile
from openlp.plugins.songs.lib.ui import SongStrings
@ -58,51 +61,51 @@ class SongImport(QtCore.QObject):
self.manager = manager
QtCore.QObject.__init__(self)
if kwargs.has_key(u'filename'):
self.import_source = kwargs[u'filename']
self.importSource = kwargs[u'filename']
elif kwargs.has_key(u'filenames'):
self.import_source = kwargs[u'filenames']
self.importSource = kwargs[u'filenames']
else:
raise KeyError(u'Keyword arguments "filename[s]" not supplied.')
log.debug(self.import_source)
self.import_wizard = None
log.debug(self.importSource)
self.importWizard = None
self.song = None
self.stop_import_flag = False
self.set_defaults()
self.error_log = []
self.stopImportFlag = False
self.setDefaults()
self.errorLog = []
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'openlp_stop_wizard'), self.stop_import)
QtCore.SIGNAL(u'openlp_stop_wizard'), self.stopImport)
def set_defaults(self):
def setDefaults(self):
"""
Create defaults for properties - call this before each song
if importing many songs at once to ensure a clean beginning
"""
self.title = u''
self.song_number = u''
self.alternate_title = u''
self.songNumber = u''
self.alternateTitle = u''
self.copyright = u''
self.comments = u''
self.theme_name = u''
self.ccli_number = u''
self.themeName = u''
self.ccliNumber = u''
self.authors = []
self.topics = []
self.media_files = []
self.song_book_name = u''
self.song_book_pub = u''
self.verse_order_list_generated_useful = False
self.verse_order_list_generated = []
self.verse_order_list = []
self.mediaFiles = []
self.songBookName = u''
self.songBookPub = u''
self.verseOrderListGeneratedUseful = False
self.verseOrderListGenerated = []
self.verseOrderList = []
self.verses = []
self.verse_counts = {}
self.copyright_string = unicode(translate(
self.verseCounts = {}
self.copyrightString = unicode(translate(
'SongsPlugin.SongImport', 'copyright'))
def log_error(self, filepath, reason=SongStrings.SongIncomplete):
def logError(self, filepath, reason=SongStrings.SongIncomplete):
"""
This should be called, when a song could not be imported.
``filepath``
This should be the file path if ``self.import_source`` is a list
This should be the file path if ``self.importSource`` is a list
with different files. If it is not a list, but a single file (for
instance a database), then this should be the song's title.
@ -110,30 +113,30 @@ class SongImport(QtCore.QObject):
The reason, why the import failed. The string should be as
informative as possible.
"""
self.set_defaults()
if self.import_wizard is None:
self.setDefaults()
if self.importWizard is None:
return
if self.import_wizard.errorReportTextEdit.isHidden():
self.import_wizard.errorReportTextEdit.setText(
if self.importWizard.errorReportTextEdit.isHidden():
self.importWizard.errorReportTextEdit.setText(
translate('SongsPlugin.SongImport',
'The following songs could not be imported:'))
self.import_wizard.errorReportTextEdit.setVisible(True)
self.import_wizard.errorCopyToButton.setVisible(True)
self.import_wizard.errorSaveToButton.setVisible(True)
self.import_wizard.errorReportTextEdit.append(
self.importWizard.errorReportTextEdit.setVisible(True)
self.importWizard.errorCopyToButton.setVisible(True)
self.importWizard.errorSaveToButton.setVisible(True)
self.importWizard.errorReportTextEdit.append(
u'- %s (%s)' % (filepath, reason))
def stop_import(self):
def stopImport(self):
"""
Sets the flag for importers to stop their import
"""
log.debug(u'Stopping songs import')
self.stop_import_flag = True
self.stopImportFlag = True
def register(self, import_wizard):
self.import_wizard = import_wizard
self.importWizard = import_wizard
def tidy_text(self, text):
def tidyText(self, text):
"""
Get rid of some dodgy unicode and formatting characters we're not
interested in. Some can be converted to ascii.
@ -151,34 +154,34 @@ class SongImport(QtCore.QObject):
text = re.sub(r' ?(\n{5}|\f)+ ?', u'\f', text)
return text
def process_song_text(self, text):
def processSongText(self, text):
verse_texts = text.split(u'\n\n')
for verse_text in verse_texts:
if verse_text.strip() != u'':
self.process_verse_text(verse_text.strip())
self.processVerseText(verse_text.strip())
def process_verse_text(self, text):
def processVerseText(self, text):
lines = text.split(u'\n')
if text.lower().find(self.copyright_string) >= 0 \
if text.lower().find(self.copyrightString) >= 0 \
or text.find(unicode(SongStrings.CopyrightSymbol)) >= 0:
copyright_found = False
for line in lines:
if (copyright_found or
line.lower().find(self.copyright_string) >= 0 or
line.lower().find(self.copyrightString) >= 0 or
line.find(unicode(SongStrings.CopyrightSymbol)) >= 0):
copyright_found = True
self.add_copyright(line)
self.addCopyright(line)
else:
self.parse_author(line)
self.parseAuthor(line)
return
if len(lines) == 1:
self.parse_author(lines[0])
self.parseAuthor(lines[0])
return
if not self.title:
self.title = lines[0]
self.add_verse(text)
self.addVerse(text)
def add_copyright(self, copyright):
def addCopyright(self, copyright):
"""
Build the copyright field
"""
@ -188,7 +191,7 @@ class SongImport(QtCore.QObject):
self.copyright += ' '
self.copyright += copyright
def parse_author(self, text):
def parseAuthor(self, text):
"""
Add the author. OpenLP stores them individually so split by 'and', '&'
and comma. However need to check for 'Mr and Mrs Smith' and turn it to
@ -204,9 +207,9 @@ class SongImport(QtCore.QObject):
if author2.endswith(u'.'):
author2 = author2[:-1]
if author2:
self.add_author(author2)
self.addAuthor(author2)
def add_author(self, author):
def addAuthor(self, author):
"""
Add an author to the list
"""
@ -214,15 +217,15 @@ class SongImport(QtCore.QObject):
return
self.authors.append(author)
def add_media_file(self, filename):
def addMediaFile(self, filename, weight=0):
"""
Add a media file to the list
"""
if filename in self.media_files:
if filename in map(lambda x: x[0], self.mediaFiles):
return
self.media_files.append(filename)
self.mediaFiles.append((filename, weight))
def add_verse(self, verse_text, verse_def=u'v', lang=None):
def addVerse(self, verse_text, verse_def=u'v', lang=None):
"""
Add a verse. This is the whole verse, lines split by \\n. It will also
attempt to detect duplicates. In this case it will just add to the verse
@ -241,29 +244,29 @@ class SongImport(QtCore.QObject):
"""
for (old_verse_def, old_verse, old_lang) in self.verses:
if old_verse.strip() == verse_text.strip():
self.verse_order_list_generated.append(old_verse_def)
self.verse_order_list_generated_useful = True
self.verseOrderListGenerated.append(old_verse_def)
self.verseOrderListGeneratedUseful = True
return
if verse_def[0] in self.verse_counts:
self.verse_counts[verse_def[0]] += 1
if verse_def[0] in self.verseCounts:
self.verseCounts[verse_def[0]] += 1
else:
self.verse_counts[verse_def[0]] = 1
self.verseCounts[verse_def[0]] = 1
if len(verse_def) == 1:
verse_def += unicode(self.verse_counts[verse_def[0]])
elif int(verse_def[1:]) > self.verse_counts[verse_def[0]]:
self.verse_counts[verse_def[0]] = int(verse_def[1:])
verse_def += unicode(self.verseCounts[verse_def[0]])
elif int(verse_def[1:]) > self.verseCounts[verse_def[0]]:
self.verseCounts[verse_def[0]] = int(verse_def[1:])
self.verses.append([verse_def, verse_text.rstrip(), lang])
self.verse_order_list_generated.append(verse_def)
self.verseOrderListGenerated.append(verse_def)
def repeat_verse(self):
def repeatVerse(self):
"""
Repeat the previous verse in the verse order
"""
self.verse_order_list_generated.append(
self.verse_order_list_generated[-1])
self.verse_order_list_generated_useful = True
self.verseOrderListGenerated.append(
self.verseOrderListGenerated[-1])
self.verseOrderListGeneratedUseful = True
def check_complete(self):
def checkComplete(self):
"""
Check the mandatory fields are entered (i.e. title and a verse)
Author not checked here, if no author then "Author unknown" is
@ -278,21 +281,21 @@ class SongImport(QtCore.QObject):
"""
All fields have been set to this song. Write the song to disk.
"""
if not self.check_complete():
self.set_defaults()
if not self.checkComplete():
self.setDefaults()
return False
log.info(u'committing song %s to database', self.title)
song = Song()
song.title = self.title
if self.import_wizard is not None:
self.import_wizard.incrementProgressBar(
if self.importWizard is not None:
self.importWizard.incrementProgressBar(
WizardStrings.ImportingType % song.title)
song.alternate_title = self.alternate_title
song.alternate_title = self.alternateTitle
# Values will be set when cleaning the song.
song.search_title = u''
song.search_lyrics = u''
song.verse_order = u''
song.song_number = self.song_number
song.song_number = self.songNumber
verses_changed_to_other = {}
sxml = SongXML()
other_count = 1
@ -310,18 +313,18 @@ class SongImport(QtCore.QObject):
verse_def = new_verse_def
sxml.add_verse_to_lyrics(verse_tag, verse_def[1:], verse_text, lang)
song.lyrics = unicode(sxml.extract_xml(), u'utf-8')
if not len(self.verse_order_list) and \
self.verse_order_list_generated_useful:
self.verse_order_list = self.verse_order_list_generated
for i, current_verse_def in enumerate(self.verse_order_list):
if not len(self.verseOrderList) and \
self.verseOrderListGeneratedUseful:
self.verseOrderList = self.verseOrderListGenerated
for i, current_verse_def in enumerate(self.verseOrderList):
if verses_changed_to_other.has_key(current_verse_def):
self.verse_order_list[i] = \
self.verseOrderList[i] = \
verses_changed_to_other[current_verse_def]
song.verse_order = u' '.join(self.verse_order_list)
song.verse_order = u' '.join(self.verseOrderList)
song.copyright = self.copyright
song.comments = self.comments
song.theme_name = self.theme_name
song.ccli_number = self.ccli_number
song.theme_name = self.themeName
song.ccli_number = self.ccliNumber
for authortext in self.authors:
author = self.manager.get_object_filtered(Author,
Author.display_name == authortext)
@ -330,17 +333,12 @@ class SongImport(QtCore.QObject):
last_name=authortext.split(u' ')[-1],
first_name=u' '.join(authortext.split(u' ')[:-1]))
song.authors.append(author)
for filename in self.media_files:
media_file = self.manager.get_object_filtered(MediaFile,
MediaFile.file_name == filename)
if not media_file:
song.media_files.append(MediaFile.populate(file_name=filename))
if self.song_book_name:
if self.songBookName:
song_book = self.manager.get_object_filtered(Book,
Book.name == self.song_book_name)
Book.name == self.songBookName)
if song_book is None:
song_book = Book.populate(name=self.song_book_name,
publisher=self.song_book_pub)
song_book = Book.populate(name=self.songBookName,
publisher=self.songBookPub)
song.book = song_book
for topictext in self.topics:
if not topictext:
@ -350,38 +348,42 @@ class SongImport(QtCore.QObject):
if topic is None:
topic = Topic.populate(name=topictext)
song.topics.append(topic)
# We need to save the song now, before adding the media files, so that
# we know where to save the media files to.
clean_song(self.manager, song)
self.manager.save_object(song)
self.set_defaults()
# Now loop through the media files, copy them to the correct location,
# and save the song again.
for filename, weight in self.mediaFiles:
media_file = self.manager.get_object_filtered(MediaFile,
MediaFile.file_name == filename)
if not media_file:
if os.path.dirname(filename):
filename = self.copyMediaFile(song.id, filename)
song.media_files.append(
MediaFile.populate(file_name=filename, weight=weight)
)
self.manager.save_object(song)
self.setDefaults()
return True
def print_song(self):
def copyMediaFile(self, song_id, filename):
"""
For debugging
This method copies the media file to the correct location and returns
the new file location.
``filename``
The file to copy.
"""
print u'========================================' \
+ u'========================================'
print u'TITLE: ' + self.title
print u'ALT TITLE: ' + self.alternate_title
for (verse_def, verse_text, lang) in self.verses:
print u'VERSE ' + verse_def + u': ' + verse_text
print u'ORDER: ' + u' '.join(self.verse_order_list)
print u'GENERATED ORDER: ' + u' '.join(self.verse_order_list_generated)
for author in self.authors:
print u'AUTHOR: ' + author
if self.copyright:
print u'COPYRIGHT: ' + self.copyright
if self.song_book_name:
print u'BOOK: ' + self.song_book_name
if self.song_book_pub:
print u'BOOK PUBLISHER: ' + self.song_book_pub
if self.song_number:
print u'NUMBER: ' + self.song_number
for topictext in self.topics:
print u'TOPIC: ' + topictext
if self.comments:
print u'COMMENTS: ' + self.comments
if self.theme_name:
print u'THEME: ' + self.theme_name
if self.ccli_number:
print u'CCLI: ' + self.ccli_number
if not hasattr(self, u'save_path'):
self.save_path = os.path.join(
AppLocation.get_section_data_path(
self.importWizard.plugin.name),
'audio', str(song_id))
if not os.path.exists(self.save_path):
os.makedirs(self.save_path)
if not filename.startswith(self.save_path):
oldfile, filename = filename, os.path.join(self.save_path,
os.path.split(filename)[1])
shutil.copyfile(oldfile, filename)
return filename

View File

@ -95,120 +95,120 @@ class SongShowPlusImport(SongImport):
"""
SongImport.__init__(self, manager, **kwargs)
def do_import(self):
def doImport(self):
"""
Receive a single file or a list of files to import.
"""
if not isinstance(self.import_source, list):
if not isinstance(self.importSource, list):
return
self.import_wizard.progressBar.setMaximum(len(self.import_source))
for file in self.import_source:
if self.stop_import_flag:
self.importWizard.progressBar.setMaximum(len(self.importSource))
for file in self.importSource:
if self.stopImportFlag:
return
self.sspVerseOrderList = []
otherCount = 0
otherList = {}
other_count = 0
other_list = {}
file_name = os.path.split(file)[1]
self.import_wizard.incrementProgressBar(
self.importWizard.incrementProgressBar(
WizardStrings.ImportingType % file_name, 0)
songData = open(file, 'rb')
song_data = open(file, 'rb')
while True:
blockKey, = struct.unpack("I", songData.read(4))
block_key, = struct.unpack("I", song_data.read(4))
# The file ends with 4 NUL's
if blockKey == 0:
if block_key == 0:
break
nextBlockStarts, = struct.unpack("I", songData.read(4))
nextBlockStarts += songData.tell()
if blockKey in (VERSE, CHORUS, BRIDGE):
null, verseNo, = struct.unpack("BB", songData.read(2))
elif blockKey == CUSTOM_VERSE:
null, verseNameLength, = struct.unpack("BB",
songData.read(2))
verseName = songData.read(verseNameLength)
lengthDescriptorSize, = struct.unpack("B", songData.read(1))
log.debug(lengthDescriptorSize)
next_block_starts, = struct.unpack("I", song_data.read(4))
next_block_starts += song_data.tell()
if block_key in (VERSE, CHORUS, BRIDGE):
null, verse_no, = struct.unpack("BB", song_data.read(2))
elif block_key == CUSTOM_VERSE:
null, verse_name_length, = struct.unpack("BB",
song_data.read(2))
verse_name = song_data.read(verse_name_length)
length_descriptor_size, = struct.unpack("B", song_data.read(1))
log.debug(length_descriptor_size)
# Detect if/how long the length descriptor is
if lengthDescriptorSize == 12 or lengthDescriptorSize == 20:
lengthDescriptor, = struct.unpack("I", songData.read(4))
elif lengthDescriptorSize == 2:
lengthDescriptor = 1
elif lengthDescriptorSize == 9:
lengthDescriptor = 0
if length_descriptor_size == 12 or length_descriptor_size == 20:
length_descriptor, = struct.unpack("I", song_data.read(4))
elif length_descriptor_size == 2:
length_descriptor = 1
elif length_descriptor_size == 9:
length_descriptor = 0
else:
lengthDescriptor, = struct.unpack("B", songData.read(1))
log.debug(lengthDescriptorSize)
data = songData.read(lengthDescriptor)
if blockKey == TITLE:
length_descriptor, = struct.unpack("B", song_data.read(1))
log.debug(length_descriptor_size)
data = song_data.read(length_descriptor)
if block_key == TITLE:
self.title = unicode(data, u'cp1252')
elif blockKey == AUTHOR:
elif block_key == AUTHOR:
authors = data.split(" / ")
for author in authors:
if author.find(",") !=-1:
authorParts = author.split(", ")
author = authorParts[1] + " " + authorParts[0]
self.parse_author(unicode(author, u'cp1252'))
elif blockKey == COPYRIGHT:
self.add_copyright(unicode(data, u'cp1252'))
elif blockKey == CCLI_NO:
self.ccli_number = int(data)
elif blockKey == VERSE:
self.add_verse(unicode(data, u'cp1252'),
"%s%s" % (VerseType.Tags[VerseType.Verse], verseNo))
elif blockKey == CHORUS:
self.add_verse(unicode(data, u'cp1252'),
"%s%s" % (VerseType.Tags[VerseType.Chorus], verseNo))
elif blockKey == BRIDGE:
self.add_verse(unicode(data, u'cp1252'),
"%s%s" % (VerseType.Tags[VerseType.Bridge], verseNo))
elif blockKey == TOPIC:
self.parseAuthor(unicode(author, u'cp1252'))
elif block_key == COPYRIGHT:
self.addCopyright(unicode(data, u'cp1252'))
elif block_key == CCLI_NO:
self.ccliNumber = int(data)
elif block_key == VERSE:
self.addVerse(unicode(data, u'cp1252'),
"%s%s" % (VerseType.Tags[VerseType.Verse], verse_no))
elif block_key == CHORUS:
self.addVerse(unicode(data, u'cp1252'),
"%s%s" % (VerseType.Tags[VerseType.Chorus], verse_no))
elif block_key == BRIDGE:
self.addVerse(unicode(data, u'cp1252'),
"%s%s" % (VerseType.Tags[VerseType.Bridge], verse_no))
elif block_key == TOPIC:
self.topics.append(unicode(data, u'cp1252'))
elif blockKey == COMMENTS:
elif block_key == COMMENTS:
self.comments = unicode(data, u'cp1252')
elif blockKey == VERSE_ORDER:
verseTag = self.toOpenLPVerseTag(data, True)
if verseTag:
if not isinstance(verseTag, unicode):
verseTag = unicode(verseTag, u'cp1252')
self.sspVerseOrderList.append(verseTag)
elif blockKey == SONG_BOOK:
self.song_book_name = unicode(data, u'cp1252')
elif blockKey == SONG_NUMBER:
self.song_number = ord(data)
elif blockKey == CUSTOM_VERSE:
verseTag = self.toOpenLPVerseTag(verseName)
self.add_verse(unicode(data, u'cp1252'), verseTag)
elif block_key == VERSE_ORDER:
verse_tag = self.toOpenLPVerseTag(data, True)
if verse_tag:
if not isinstance(verse_tag, unicode):
verse_tag = unicode(verse_tag, u'cp1252')
self.sspVerseOrderList.append(verse_tag)
elif block_key == SONG_BOOK:
self.songBookName = unicode(data, u'cp1252')
elif block_key == SONG_NUMBER:
self.songNumber = ord(data)
elif block_key == CUSTOM_VERSE:
verse_tag = self.toOpenLPVerseTag(verse_name)
self.addVerse(unicode(data, u'cp1252'), verse_tag)
else:
log.debug("Unrecognised blockKey: %s, data: %s"
% (blockKey, data))
songData.seek(nextBlockStarts)
self.verse_order_list = self.sspVerseOrderList
songData.close()
% (block_key, data))
song_data.seek(next_block_starts)
self.verseOrderList = self.sspVerseOrderList
song_data.close()
if not self.finish():
self.log_error(file)
self.logError(file)
def toOpenLPVerseTag(self, verseName, ignoreUnique=False):
if verseName.find(" ") != -1:
verseParts = verseName.split(" ")
verseType = verseParts[0]
verseNumber = verseParts[1]
def toOpenLPVerseTag(self, verse_name, ignore_unique=False):
if verse_name.find(" ") != -1:
verse_parts = verse_name.split(" ")
verse_type = verse_parts[0]
verse_number = verse_parts[1]
else:
verseType = verseName
verseNumber = "1"
verseType = verseType.lower()
if verseType == "verse":
verseTag = VerseType.Tags[VerseType.Verse]
elif verseType == "chorus":
verseTag = VerseType.Tags[VerseType.Chorus]
elif verseType == "bridge":
verseTag = VerseType.Tags[VerseType.Bridge]
elif verseType == "pre-chorus":
verseTag = VerseType.Tags[VerseType.PreChorus]
verse_type = verse_name
verse_number = "1"
verse_type = verse_type.lower()
if verse_type == "verse":
verse_tag = VerseType.Tags[VerseType.Verse]
elif verse_type == "chorus":
verse_tag = VerseType.Tags[VerseType.Chorus]
elif verse_type == "bridge":
verse_tag = VerseType.Tags[VerseType.Bridge]
elif verse_type == "pre-chorus":
verse_tag = VerseType.Tags[VerseType.PreChorus]
else:
if not self.otherList.has_key(verseName):
if ignoreUnique:
if not self.otherList.has_key(verse_name):
if ignore_unique:
return None
self.otherCount = self.otherCount + 1
self.otherList[verseName] = str(self.otherCount)
verseTag = VerseType.Tags[VerseType.Other]
verseNumber = self.otherList[verseName]
return verseTag + verseNumber
self.otherList[verse_name] = str(self.otherCount)
verse_tag = VerseType.Tags[VerseType.Other]
verse_number = self.otherList[verse_name]
return verse_tag + verse_number

View File

@ -98,58 +98,58 @@ class WowImport(SongImport):
"""
SongImport.__init__(self, manager, **kwargs)
def do_import(self):
def doImport(self):
"""
Receive a single file or a list of files to import.
"""
if isinstance(self.import_source, list):
self.import_wizard.progressBar.setMaximum(len(self.import_source))
for file in self.import_source:
if self.stop_import_flag:
if isinstance(self.importSource, list):
self.importWizard.progressBar.setMaximum(len(self.importSource))
for file in self.importSource:
if self.stopImportFlag:
return
file_name = os.path.split(file)[1]
# Get the song title
self.title = file_name.rpartition(u'.')[0]
songData = open(file, 'rb')
if songData.read(19) != u'WoW File\nSong Words':
self.log_error(file)
song_data = open(file, 'rb')
if song_data.read(19) != u'WoW File\nSong Words':
self.logError(file)
continue
# Seek to byte which stores number of blocks in the song
songData.seek(56)
no_of_blocks = ord(songData.read(1))
song_data.seek(56)
no_of_blocks = ord(song_data.read(1))
# Seek to the beging of the first block
songData.seek(82)
song_data.seek(82)
for block in range(no_of_blocks):
self.lines_to_read = ord(songData.read(1))
self.linesToRead = ord(song_data.read(1))
# Skip 3 nulls to the beginnig of the 1st line
songData.seek(3, os.SEEK_CUR)
song_data.seek(3, os.SEEK_CUR)
block_text = u''
while self.lines_to_read:
self.line_text = unicode(
songData.read(ord(songData.read(1))), u'cp1252')
songData.seek(1, os.SEEK_CUR)
while self.linesToRead:
self.lineText = unicode(
song_data.read(ord(song_data.read(1))), u'cp1252')
song_data.seek(1, os.SEEK_CUR)
if block_text:
block_text += u'\n'
block_text += self.line_text
self.lines_to_read -= 1
block_type = BLOCK_TYPES[ord(songData.read(1))]
block_text += self.lineText
self.linesToRead -= 1
block_type = BLOCK_TYPES[ord(song_data.read(1))]
# Skip 3 nulls at the end of the block
songData.seek(3, os.SEEK_CUR)
song_data.seek(3, os.SEEK_CUR)
# Blocks are seperated by 2 bytes, skip them, but not if
# this is the last block!
if block + 1 < no_of_blocks:
songData.seek(2, os.SEEK_CUR)
self.add_verse(block_text, block_type)
song_data.seek(2, os.SEEK_CUR)
self.addVerse(block_text, block_type)
# Now to extract the author
author_length = ord(songData.read(1))
author_length = ord(song_data.read(1))
if author_length:
self.parse_author(
unicode(songData.read(author_length), u'cp1252'))
self.parseAuthor(
unicode(song_data.read(author_length), u'cp1252'))
# Finally the copyright
copyright_length = ord(songData.read(1))
copyright_length = ord(song_data.read(1))
if copyright_length:
self.add_copyright(unicode(
songData.read(copyright_length), u'cp1252'))
songData.close()
self.addCopyright(unicode(
song_data.read(copyright_length), u'cp1252'))
song_data.close()
if not self.finish():
self.log_error(file)
self.logError(file)

View File

@ -196,7 +196,7 @@ class SongsPlugin(Plugin):
def importSongs(self, format, **kwargs):
class_ = SongFormat.get_class(format)
importer = class_(self.manager, **kwargs)
importer.register(self.mediaItem.import_wizard)
importer.register(self.mediaItem.importWizard)
return importer
def setPluginTextStrings(self):
@ -252,7 +252,7 @@ class SongsPlugin(Plugin):
progress.setValue(idx)
Receiver.send_message(u'openlp_process_events')
importer = OpenLPSongImport(self.manager, filename=db)
importer.do_import()
importer.doImport()
progress.setValue(len(song_dbs))
self.mediaItem.onSearchTextButtonClick()