This commit is contained in:
Tim Bentley 2012-10-16 18:48:13 +01:00
commit 0f0cf5987c
21 changed files with 260 additions and 104 deletions

View File

@ -85,6 +85,14 @@ class PluginManager(object):
log.debug(u'finding plugins in %s at depth %d',
unicode(plugin_dir), startdepth)
for root, dirs, files in os.walk(plugin_dir):
# TODO Presentation plugin is not yet working on Mac OS X.
# For now just ignore it. The following code will hide it
# in settings dialog.
if sys.platform == 'darwin':
present_plugin_dir = os.path.join(plugin_dir, 'presentations')
# Ignore files from the presentation plugin directory.
if root.startswith(present_plugin_dir):
continue
for name in files:
if name.endswith(u'.py') and not name.startswith(u'__'):
path = os.path.abspath(os.path.join(root, name))

View File

@ -177,8 +177,10 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
return FirstTimePage.Progress
elif self.currentId() == FirstTimePage.Themes:
Receiver.send_message(u'cursor_busy')
Receiver.send_message(u'openlp_process_events')
while not self.themeScreenshotThread.isFinished():
time.sleep(0.1)
Receiver.send_message(u'openlp_process_events')
# Build the screenshot icons, as this can not be done in the thread.
self._buildThemeScreenshots()
Receiver.send_message(u'cursor_normal')
@ -188,10 +190,11 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
def onCurrentIdChanged(self, pageId):
"""
Detects Page changes and updates as approprate.
Detects Page changes and updates as appropriate.
"""
# Keep track of the page we are at. Triggering "Cancel" causes pageId
# to be a -1.
Receiver.send_message(u'openlp_process_events')
if pageId != -1:
self.lastId = pageId
if pageId == FirstTimePage.Plugins:
@ -227,10 +230,12 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
self.cancelButton.setVisible(False)
elif pageId == FirstTimePage.Progress:
Receiver.send_message(u'cursor_busy')
self.repaint()
Receiver.send_message(u'openlp_process_events')
# Try to give the wizard a chance to redraw itself
time.sleep(0.2)
self._preWizard()
Receiver.send_message(u'openlp_process_events')
self._performWizard()
Receiver.send_message(u'openlp_process_events')
self._postWizard()
Receiver.send_message(u'cursor_normal')
Receiver.send_message(u'openlp_process_events')
@ -263,8 +268,8 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
"""
Receiver.send_message(u'cursor_busy')
self._performWizard()
Receiver.send_message(u'openlp_process_events')
Receiver.send_message(u'cursor_normal')
Receiver.send_message(u'openlp_process_events')
Settings().setValue(u'general/has run wizard',
QtCore.QVariant(True))
self.close()
@ -344,6 +349,7 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
Receiver.send_message(u'openlp_process_events')
# Loop through the songs list and increase for each selected item
for i in xrange(self.songsListWidget.count()):
Receiver.send_message(u'openlp_process_events')
item = self.songsListWidget.item(i)
if item.checkState() == QtCore.Qt.Checked:
filename = item.data(QtCore.Qt.UserRole).toString()
@ -352,6 +358,7 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
# Loop through the Bibles list and increase for each selected item
iterator = QtGui.QTreeWidgetItemIterator(self.biblesTreeWidget)
while iterator.value():
Receiver.send_message(u'openlp_process_events')
item = iterator.value()
if item.parent() and item.checkState(0) == QtCore.Qt.Checked:
filename = item.data(0, QtCore.Qt.UserRole).toString()
@ -360,6 +367,7 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
iterator += 1
# Loop through the themes list and increase for each selected item
for i in xrange(self.themesListWidget.count()):
Receiver.send_message(u'openlp_process_events')
item = self.themesListWidget.item(i)
if item.checkState() == QtCore.Qt.Checked:
filename = item.data(QtCore.Qt.UserRole).toString()
@ -381,6 +389,10 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard):
self.progressPage.setTitle(translate('OpenLP.FirstTimeWizard',
'Setting Up'))
self.progressPage.setSubTitle(u'Setup complete.')
self.repaint()
Receiver.send_message(u'openlp_process_events')
# Try to give the wizard a chance to repaint itself
time.sleep(0.1)
def _postWizard(self):
"""

View File

@ -82,13 +82,13 @@ class Ui_FirstTimeWizard(object):
self.imageCheckBox.setChecked(True)
self.imageCheckBox.setObjectName(u'imageCheckBox')
self.pluginLayout.addWidget(self.imageCheckBox)
self.presentationCheckBox = QtGui.QCheckBox(self.pluginPage)
if sys.platform == "darwin":
self.presentationCheckBox.setChecked(False)
else:
# TODO Presentation plugin is not yet working on Mac OS X.
# For now just ignore it.
if sys.platform != 'darwin':
self.presentationCheckBox = QtGui.QCheckBox(self.pluginPage)
self.presentationCheckBox.setChecked(True)
self.presentationCheckBox.setObjectName(u'presentationCheckBox')
self.pluginLayout.addWidget(self.presentationCheckBox)
self.presentationCheckBox.setObjectName(u'presentationCheckBox')
self.pluginLayout.addWidget(self.presentationCheckBox)
self.mediaCheckBox = QtGui.QCheckBox(self.pluginPage)
self.mediaCheckBox.setChecked(True)
self.mediaCheckBox.setObjectName(u'mediaCheckBox')
@ -214,10 +214,11 @@ class Ui_FirstTimeWizard(object):
self.bibleCheckBox.setText(translate('OpenLP.FirstTimeWizard', 'Bible'))
self.imageCheckBox.setText(translate('OpenLP.FirstTimeWizard',
'Images'))
self.presentationCheckBox.setText(translate('OpenLP.FirstTimeWizard',
'Presentations'))
if sys.platform == "darwin":
self.presentationCheckBox.setEnabled(False)
# TODO Presentation plugin is not yet working on Mac OS X.
# For now just ignore it.
if sys.platform != 'darwin':
self.presentationCheckBox.setText(translate('OpenLP.FirstTimeWizard',
'Presentations'))
self.mediaCheckBox.setText(translate('OpenLP.FirstTimeWizard',
'Media (Audio and Video)'))
self.remoteCheckBox.setText(translate('OpenLP.FirstTimeWizard',

View File

@ -30,7 +30,6 @@ import os
import zipfile
import shutil
import logging
import locale
import re
from xml.etree.ElementTree import ElementTree, XML
@ -46,7 +45,8 @@ from openlp.core.lib.ui import UiStrings, critical_error_message_box, \
create_widget_action
from openlp.core.theme import Theme
from openlp.core.ui import FileRenameForm, ThemeForm
from openlp.core.utils import AppLocation, delete_file, get_filesystem_encoding
from openlp.core.utils import AppLocation, delete_file, locale_compare, \
get_filesystem_encoding
log = logging.getLogger(__name__)
@ -284,6 +284,7 @@ class ThemeManager(QtGui.QWidget):
plugin.renameTheme(old_theme_name, new_theme_name)
self.mainwindow.renderer.update_theme(
new_theme_name, old_theme_name)
self.loadThemes()
def onCopyTheme(self):
"""
@ -457,9 +458,8 @@ class ThemeManager(QtGui.QWidget):
self.configUpdated()
files = SettingsManager.get_files(self.settingsSection, u'.png')
# Sort the themes by its name considering language specific characters.
# lower() is needed for windows!
files.sort(key=lambda file_name: unicode(file_name).lower(),
cmp=locale.strcoll)
files.sort(key=lambda file_name: unicode(file_name),
cmp=locale_compare)
# now process the file list of png files
for name in files:
# check to see file is in theme root directory

View File

@ -488,10 +488,30 @@ def format_time(text, local_time):
return re.sub('\%[a-zA-Z]', match_formatting, text)
def locale_compare(string1, string2):
"""
Compares two strings according to the current locale settings.
As any other compare function, returns a negative, or a positive value,
or 0, depending on whether string1 collates before or after string2 or
is equal to it. Comparison is case insensitive.
"""
# Function locale.strcol() from standard Python library does not work
# properly on Windows and probably somewhere else.
return QtCore.QString.localeAwareCompare(string1.lower(), string2.lower())
# For performance reasons provide direct reference to compare function
# without wrapping it in another function making te string lowercase.
# This is needed for sorting songs.
locale_direct_compare = QtCore.QString.localeAwareCompare
from languagemanager import LanguageManager
from actions import ActionList
__all__ = [u'AppLocation', u'get_application_version', u'check_latest_version',
u'add_actions', u'get_filesystem_encoding', u'LanguageManager',
u'ActionList', u'get_web_page', u'get_uno_command', u'get_uno_instance',
u'delete_file', u'clean_filename', u'format_time']
u'delete_file', u'clean_filename', u'format_time', u'locale_compare',
u'locale_direct_compare']

View File

@ -30,7 +30,6 @@ The bible import functions for OpenLP
"""
import logging
import os
import locale
from PyQt4 import QtCore, QtGui
@ -39,7 +38,7 @@ from openlp.core.lib.db import delete_database
from openlp.core.lib.ui import UiStrings, critical_error_message_box
from openlp.core.lib.settings import Settings
from openlp.core.ui.wizard import OpenLPWizard, WizardStrings
from openlp.core.utils import AppLocation
from openlp.core.utils import AppLocation, locale_compare
from openlp.plugins.bibles.lib.manager import BibleFormat
from openlp.plugins.bibles.lib.db import BiblesResourcesDB, clean_filename
@ -523,7 +522,7 @@ class BibleImportForm(OpenLPWizard):
"""
self.webTranslationComboBox.clear()
bibles = self.web_bible_list[index].keys()
bibles.sort(cmp=locale.strcoll)
bibles.sort(cmp=locale_compare)
self.webTranslationComboBox.addItems(bibles)
def onOsisBrowseButtonClicked(self):

View File

@ -27,7 +27,6 @@
###############################################################################
import logging
import locale
from PyQt4 import QtCore, QtGui
@ -38,6 +37,7 @@ from openlp.core.lib.settings import Settings
from openlp.core.lib.ui import UiStrings, set_case_insensitive_completer, \
create_horizontal_adjusting_combo_box, critical_error_message_box, \
find_and_set_in_combo_box, build_icon
from openlp.core.utils import locale_compare
from openlp.plugins.bibles.forms import BibleImportForm, EditBibleForm
from openlp.plugins.bibles.lib import LayoutStyle, DisplayStyle, \
VerseReferenceList, get_reference_separator, LanguageSelection, \
@ -381,7 +381,7 @@ class BibleMediaItem(MediaManagerItem):
# Get all bibles and sort the list.
bibles = self.plugin.manager.get_bibles().keys()
bibles = filter(None, bibles)
bibles.sort(cmp=locale.strcoll)
bibles.sort(cmp=locale_compare)
# Load the bibles into the combo boxes.
self.quickVersionComboBox.addItems(bibles)
self.quickSecondComboBox.addItems(bibles)
@ -538,7 +538,7 @@ class BibleMediaItem(MediaManagerItem):
data = BiblesResourcesDB.get_book_by_id(
book.book_reference_id)
books.append(data[u'name'] + u' ')
books.sort(cmp=locale.strcoll)
books.sort(cmp=locale_compare)
set_case_insensitive_completer(books, self.quickSearchEdit)
def onImportClick(self):

View File

@ -34,12 +34,21 @@ from sqlalchemy import Column, Table, types
from sqlalchemy.orm import mapper
from openlp.core.lib.db import BaseModel, init_db
from openlp.core.utils import locale_compare
class CustomSlide(BaseModel):
"""
CustomSlide model
"""
pass
# By default sort the customs by its title considering language specific
# characters.
def __lt__(self, other):
r = locale_compare(self.title, other.title)
return True if r < 0 else False
def __eq__(self, other):
return 0 == locale_compare(self.title, other.title)
def init_schema(url):
"""

View File

@ -27,7 +27,6 @@
###############################################################################
import logging
import locale
from PyQt4 import QtCore, QtGui
from sqlalchemy.sql import or_, func
@ -109,10 +108,7 @@ class CustomMediaItem(MediaManagerItem):
# Sort out what custom we want to select after loading the list.
self.saveAutoSelectId()
self.listView.clear()
# Sort the customs by its title considering language specific
# characters. lower() is needed for windows!
custom_slides.sort(
cmp=locale.strcoll, key=lambda custom: custom.title.lower())
custom_slides.sort()
for custom_slide in custom_slides:
custom_name = QtGui.QListWidgetItem(custom_slide.title)
custom_name.setData(

View File

@ -28,7 +28,6 @@
import logging
import os
import locale
from PyQt4 import QtCore, QtGui
@ -37,7 +36,8 @@ from openlp.core.lib import MediaManagerItem, build_icon, ItemCapabilities, \
Receiver, create_thumb, validate_thumb
from openlp.core.lib.ui import UiStrings, critical_error_message_box
from openlp.core.lib.settings import Settings
from openlp.core.utils import AppLocation, delete_file, get_images_filter
from openlp.core.utils import AppLocation, delete_file, locale_compare, \
get_images_filter
log = logging.getLogger(__name__)
@ -126,10 +126,10 @@ class ImageMediaItem(MediaManagerItem):
if not initialLoad:
Receiver.send_message(u'cursor_busy')
self.plugin.formParent.displayProgressBar(len(images))
# Sort the themes by its filename considering language specific
# characters. lower() is needed for windows!
images.sort(cmp=locale.strcoll,
key=lambda filename: os.path.split(unicode(filename))[1].lower())
# Sort the images by its filename considering language specific
# characters.
images.sort(cmp=locale_compare,
key=lambda filename: os.path.split(unicode(filename))[1])
for imageFile in images:
filename = os.path.split(unicode(imageFile))[1]
thumb = os.path.join(self.servicePath, filename)

View File

@ -28,7 +28,6 @@
import logging
import os
import locale
from PyQt4 import QtCore, QtGui
@ -39,6 +38,7 @@ from openlp.core.lib.ui import UiStrings, critical_error_message_box, \
create_horizontal_adjusting_combo_box
from openlp.core.ui import Controller, Display
from openlp.core.ui.media import get_media_players, set_media_players
from openlp.core.utils import locale_compare
log = logging.getLogger(__name__)
@ -285,10 +285,10 @@ class MediaMediaItem(MediaManagerItem):
u'media', self.getFileList())
def loadList(self, media):
# Sort the themes by its filename considering language specific
# characters. lower() is needed for windows!
media.sort(cmp=locale.strcoll,
key=lambda filename: os.path.split(unicode(filename))[1].lower())
# Sort the media by its filename considering language specific
# characters.
media.sort(cmp=locale_compare,
key=lambda filename: os.path.split(unicode(filename))[1])
for track in media:
track_info = QtCore.QFileInfo(track)
if track_info.isFile():
@ -307,8 +307,8 @@ class MediaMediaItem(MediaManagerItem):
def getList(self, type=MediaType.Audio):
media = SettingsManager.load_list(self.settingsSection, u'media')
media.sort(cmp=locale.strcoll,
key=lambda filename: os.path.split(unicode(filename))[1].lower())
media.sort(cmp=locale_compare,
key=lambda filename: os.path.split(unicode(filename))[1])
ext = []
if type == MediaType.Audio:
ext = self.plugin.audio_extensions_list

View File

@ -153,7 +153,7 @@ class ImpressController(PresentationController):
desktop = None
try:
desktop = self.manager.createInstance(u'com.sun.star.frame.Desktop')
except AttributeError:
except (AttributeError, pywintypes.com_error):
log.warn(u'Failure to find desktop - Impress may have closed')
return desktop if desktop else None
@ -284,6 +284,8 @@ class ImpressDocument(PresentationDocument):
props = tuple(props)
doc = self.document
pages = doc.getDrawPages()
if not pages:
return
if not os.path.isdir(self.get_temp_folder()):
os.makedirs(self.get_temp_folder())
for idx in range(pages.getCount()):
@ -359,7 +361,7 @@ class ImpressDocument(PresentationDocument):
log.debug(u'is active OpenOffice')
if not self.is_loaded():
return False
return self.control is not None
return self.control.isRunning() if self.control else False
def unblank_screen(self):
"""
@ -380,7 +382,7 @@ class ImpressDocument(PresentationDocument):
Returns true if screen is blank
"""
log.debug(u'is blank OpenOffice')
if self.control:
if self.control and self.control.isRunning():
return self.control.isPaused()
else:
return False
@ -436,7 +438,11 @@ class ImpressDocument(PresentationDocument):
"""
Triggers the next effect of slide on the running presentation
"""
is_paused = self.control.isPaused()
self.control.gotoNextEffect()
time.sleep(0.1)
if not is_paused and self.control.isPaused():
self.control.gotoPreviousEffect()
def previous_step(self):
"""

View File

@ -28,7 +28,6 @@
import logging
import os
import locale
from PyQt4 import QtCore, QtGui
@ -38,6 +37,7 @@ from openlp.core.lib import MediaManagerItem, build_icon, SettingsManager, \
from openlp.core.lib.ui import UiStrings, critical_error_message_box, \
create_horizontal_adjusting_combo_box
from openlp.core.lib.settings import Settings
from openlp.core.utils import locale_compare
from openlp.plugins.presentations.lib import MessageListener
log = logging.getLogger(__name__)
@ -169,10 +169,10 @@ class PresentationMediaItem(MediaManagerItem):
if not initialLoad:
Receiver.send_message(u'cursor_busy')
self.plugin.formParent.displayProgressBar(len(files))
# Sort the themes by its filename considering language specific
# characters. lower() is needed for windows!
files.sort(cmp=locale.strcoll,
key=lambda filename: os.path.split(unicode(filename))[1].lower())
# Sort the presentations by its filename considering language specific
# characters.
files.sort(cmp=locale_compare,
key=lambda filename: os.path.split(unicode(filename))[1])
for file in files:
if not initialLoad:
self.plugin.formParent.incrementProgressBar()

View File

@ -49,6 +49,7 @@ class Controller(object):
"""
self.is_live = live
self.doc = None
self.hide_mode = None
log.info(u'%s controller loaded' % live)
def add_handler(self, controller, file, hide_mode, slide_no):
@ -67,6 +68,7 @@ class Controller(object):
# Inform slidecontroller that the action failed?
return
self.doc.slidenumber = slide_no
self.hide_mode = hide_mode
if self.is_live:
if hide_mode == HideMode.Screen:
Receiver.send_message(u'live_display_hide', HideMode.Screen)
@ -78,7 +80,7 @@ class Controller(object):
else:
self.doc.start_presentation()
Receiver.send_message(u'live_display_hide', HideMode.Screen)
self.doc.slidenumber = 0
self.doc.slidenumber = 1
if slide_no > 1:
self.slide(slide_no)
@ -88,100 +90,134 @@ class Controller(object):
Use the last slide number.
"""
log.debug(u'Live = %s, activate' % self.is_live)
if not self.doc:
return False
if self.doc.is_active():
return
return True
if not self.doc.is_loaded():
if not self.doc.load_presentation():
return
log.warn(u'Failed to activate %s' % self.doc.filepath)
return False
if self.is_live:
self.doc.start_presentation()
if self.doc.slidenumber > 1:
if self.doc.slidenumber > self.doc.get_slide_count():
self.doc.slidenumber = self.doc.get_slide_count()
self.doc.goto_slide(self.doc.slidenumber)
if self.doc.is_active():
return True
else:
log.warn(u'Failed to activate %s' % self.doc.filepath)
return False
def slide(self, slide):
"""
Go to a specific slide
"""
log.debug(u'Live = %s, slide' % self.is_live)
if not self.doc:
return
if not self.is_live:
return
if self.doc.is_blank():
if self.hide_mode:
self.doc.slidenumber = int(slide) + 1
self.poll()
return
if not self.activate():
return
self.activate()
self.doc.goto_slide(int(slide) + 1)
self.doc.poll_slidenumber(self.is_live)
self.poll()
def first(self):
"""
Based on the handler passed at startup triggers the first slide
"""
log.debug(u'Live = %s, first' % self.is_live)
if not self.doc:
return
if not self.is_live:
return
if self.doc.is_blank():
if self.hide_mode:
self.doc.slidenumber = 1
self.poll()
return
if not self.activate():
return
self.activate()
self.doc.start_presentation()
self.doc.poll_slidenumber(self.is_live)
self.poll()
def last(self):
"""
Based on the handler passed at startup triggers the last slide
"""
log.debug(u'Live = %s, last' % self.is_live)
if not self.doc:
return
if not self.is_live:
return
if self.doc.is_blank():
if self.hide_mode:
self.doc.slidenumber = self.doc.get_slide_count()
self.poll()
return
if not self.activate():
return
self.activate()
self.doc.goto_slide(self.doc.get_slide_count())
self.doc.poll_slidenumber(self.is_live)
self.poll()
def next(self):
"""
Based on the handler passed at startup triggers the next slide event
"""
log.debug(u'Live = %s, next' % self.is_live)
if not self.doc:
return
if not self.is_live:
return
if self.doc.is_blank():
if self.hide_mode:
if not self.doc.is_active():
return
if self.doc.slidenumber < self.doc.get_slide_count():
self.doc.slidenumber = self.doc.slidenumber + 1
self.poll()
return
if not self.activate():
return
# The "End of slideshow" screen is after the last slide
# Note, we can't just stop on the last slide, since it may
# contain animations that need to be stepped through.
if self.doc.slidenumber > self.doc.get_slide_count():
return
self.activate()
self.doc.next_step()
self.doc.poll_slidenumber(self.is_live)
self.poll()
def previous(self):
"""
Based on the handler passed at startup triggers the previous slide event
"""
log.debug(u'Live = %s, previous' % self.is_live)
if not self.doc:
return
if not self.is_live:
return
if self.doc.is_blank():
if self.hide_mode:
if not self.doc.is_active():
return
if self.doc.slidenumber > 1:
self.doc.slidenumber = self.doc.slidenumber - 1
self.poll()
return
if not self.activate():
return
self.activate()
self.doc.previous_step()
self.doc.poll_slidenumber(self.is_live)
self.poll()
def shutdown(self):
"""
Based on the handler passed at startup triggers slide show to shut down
"""
log.debug(u'Live = %s, shutdown' % self.is_live)
if not self.doc:
return
self.doc.close_presentation()
self.doc = None
@ -190,21 +226,30 @@ class Controller(object):
Instruct the controller to blank the presentation
"""
log.debug(u'Live = %s, blank' % self.is_live)
self.hide_mode = hide_mode
if not self.doc:
return
if not self.is_live:
return
if not self.doc.is_loaded():
return
if not self.doc.is_active():
return
if hide_mode == HideMode.Theme:
if not self.doc.is_loaded():
return
if not self.doc.is_active():
return
Receiver.send_message(u'live_display_hide', HideMode.Theme)
self.doc.blank_screen()
elif hide_mode == HideMode.Blank:
if not self.activate():
return
self.doc.blank_screen()
def stop(self):
"""
Instruct the controller to stop and hide the presentation
"""
log.debug(u'Live = %s, stop' % self.is_live)
self.hide_mode = HideMode.Screen
if not self.doc:
return
if not self.is_live:
return
if not self.doc.is_loaded():
@ -218,9 +263,13 @@ class Controller(object):
Instruct the controller to unblank the presentation
"""
log.debug(u'Live = %s, unblank' % self.is_live)
self.hide_mode = None
if not self.doc:
return
if not self.is_live:
return
self.activate()
if not self.activate():
return
if self.doc.slidenumber and \
self.doc.slidenumber != self.doc.get_slide_number():
self.doc.goto_slide(self.doc.slidenumber)
@ -228,7 +277,9 @@ class Controller(object):
Receiver.send_message(u'live_display_hide', HideMode.Screen)
def poll(self):
self.doc.poll_slidenumber(self.is_live)
if not self.doc:
return
self.doc.poll_slidenumber(self.is_live, self.hide_mode)
class MessageListener(object):

View File

@ -94,9 +94,9 @@ class PowerpointController(PresentationController):
self.docs[0].close_presentation()
if self.process is None:
return
if self.process.Presentations.Count > 0:
return
try:
if self.process.Presentations.Count > 0:
return
self.process.Quit()
except pywintypes.com_error:
pass
@ -210,6 +210,13 @@ class PowerpointDocument(PresentationDocument):
self.presentation.SlideShowSettings.Run()
self.presentation.SlideShowWindow.View.State = 1
self.presentation.SlideShowWindow.Activate()
if self.presentation.Application.Version == u'14.0':
# Unblanking is broken in PowerPoint 2010, need to redisplay
slide = self.presentation.SlideShowWindow.View.CurrentShowPosition
click = self.presentation.SlideShowWindow.View.GetClickIndex()
self.presentation.SlideShowWindow.View.GotoSlide(slide)
if click:
self.presentation.SlideShowWindow.View.GotoClick(click)
def blank_screen(self):
"""
@ -253,6 +260,8 @@ class PowerpointDocument(PresentationDocument):
renderer = self.controller.plugin.renderer
rect = renderer.screens.current[u'size']
ppt_window = self.presentation.SlideShowSettings.Run()
if not ppt_window:
return
ppt_window.Top = rect.y() * 72 / dpi
ppt_window.Height = rect.height() * 72 / dpi
ppt_window.Left = rect.x() * 72 / dpi
@ -286,6 +295,8 @@ class PowerpointDocument(PresentationDocument):
"""
log.debug(u'next_step')
self.presentation.SlideShowWindow.View.Next()
if self.get_slide_number() > self.get_slide_count():
self.previous_step()
def previous_step(self):
"""

View File

@ -260,16 +260,17 @@ class PresentationDocument(object):
else:
return None
def poll_slidenumber(self, is_live):
def poll_slidenumber(self, is_live, hide_mode):
"""
Check the current slide number
"""
if not self.is_active():
return
current = self.get_slide_number()
if current == self.slidenumber:
return
self.slidenumber = current
if not hide_mode:
current = self.get_slide_number()
if current == self.slidenumber:
return
self.slidenumber = current
if is_live:
prefix = u'live'
else:

View File

@ -29,7 +29,6 @@
The :mod:`songexportform` module provides the wizard for exporting songs to the
OpenLyrics format.
"""
import locale
import logging
from PyQt4 import QtCore, QtGui
@ -38,6 +37,7 @@ from openlp.core.lib import build_icon, Receiver, SettingsManager, translate, \
create_separated_list
from openlp.core.lib.ui import UiStrings, critical_error_message_box
from openlp.core.ui.wizard import OpenLPWizard, WizardStrings
from openlp.core.utils import locale_direct_compare
from openlp.plugins.songs.lib.db import Song
from openlp.plugins.songs.lib.openlyricsexport import OpenLyricsExport
@ -252,7 +252,8 @@ class SongExportForm(OpenLPWizard):
# Load the list of songs.
Receiver.send_message(u'cursor_busy')
songs = self.plugin.manager.get_all_objects(Song)
songs.sort(cmp=locale.strcoll, key=lambda song: song.title.lower())
songs.sort(
cmp=locale_direct_compare, key=lambda song: song.sort_string)
for song in songs:
# No need to export temporary songs.
if song.temporary:

View File

@ -31,8 +31,9 @@ the Songs plugin
"""
from sqlalchemy import Column, ForeignKey, Table, types
from sqlalchemy.orm import mapper, relation
from sqlalchemy.orm import mapper, relation, reconstructor
from sqlalchemy.sql.expression import func
from PyQt4 import QtCore
from openlp.core.lib.db import BaseModel, init_db
@ -63,7 +64,22 @@ class Song(BaseModel):
"""
Song model
"""
pass
def __init__(self):
self.sort_string = ''
# This decorator tells sqlalchemy to call this method everytime
# any data on this object are updated.
@reconstructor
def init_on_load(self):
"""
Precompute string to be used for sorting.
Song sorting is performance sensitive operation.
To get maximum speed lets precompute the string
used for comparison.
"""
# Avoid the overhead of converting string to lowercase and to QString
self.sort_string = QtCore.QString(self.title.lower())
class Topic(BaseModel):

View File

@ -27,7 +27,6 @@
###############################################################################
import logging
import locale
import re
import os
import shutil
@ -40,7 +39,7 @@ from openlp.core.lib import MediaManagerItem, Receiver, ItemCapabilities, \
check_directory_exists
from openlp.core.lib.ui import UiStrings, create_widget_action
from openlp.core.lib.settings import Settings
from openlp.core.utils import AppLocation
from openlp.core.utils import AppLocation, locale_direct_compare
from openlp.plugins.songs.forms import EditSongForm, SongMaintenanceForm, \
SongImportForm, SongExportForm
from openlp.plugins.songs.lib import OpenLyrics, SongXML, VerseType, \
@ -260,10 +259,8 @@ class SongMediaItem(MediaManagerItem):
log.debug(u'display results Song')
self.saveAutoSelectId()
self.listView.clear()
# Sort the songs by its title considering language specific characters.
# lower() is needed for windows!
searchresults.sort(
cmp=locale.strcoll, key=lambda song: song.title.lower())
cmp=locale_direct_compare, key=lambda song: song.sort_string)
for song in searchresults:
# Do not display temporary songs
if song.temporary:

View File

@ -63,10 +63,14 @@ class OpenLPSongImport(SongImport):
SongImport.__init__(self, manager, **kwargs)
self.sourceSession = None
def doImport(self):
def doImport(self, progressDialog=None):
"""
Run the import for an OpenLP version 2 song database.
``progressDialog``
The QProgressDialog used when importing songs from the FRW.
"""
class OldAuthor(BaseModel):
"""
Author model
@ -101,13 +105,14 @@ class OpenLPSongImport(SongImport):
"""
pass
# Check the file type
if not self.importSource.endswith(u'.sqlite'):
self.logError(self.importSource,
translate('SongsPlugin.OpenLPSongImport',
'Not a valid OpenLP 2.0 song database.'))
return
self.importSource = u'sqlite:///%s' % self.importSource
# Load the db file
engine = create_engine(self.importSource)
source_meta = MetaData()
source_meta.reflect(engine)
@ -224,7 +229,11 @@ class OpenLPSongImport(SongImport):
file_name=media_file.file_name))
clean_song(self.manager, new_song)
self.manager.save_object(new_song)
if self.importWizard:
if progressDialog:
progressDialog.setValue(progressDialog.value() + 1)
progressDialog.setLabelText(
WizardStrings.ImportingType % new_song.title)
else:
self.importWizard.incrementProgressBar(
WizardStrings.ImportingType % new_song.title)
if self.stopImportFlag:

View File

@ -29,6 +29,7 @@
import logging
import os
from tempfile import gettempdir
import sqlite3
from PyQt4 import QtCore, QtGui
@ -82,7 +83,7 @@ class SongsPlugin(Plugin):
unicode(UiStrings().Tools))
QtCore.QObject.connect(Receiver.get_receiver(),
QtCore.SIGNAL(u'servicemanager_new_service'),
self.clearTemporarySongs)
self.clearTemporarySongs)
def addImportMenuItem(self, import_menu):
@ -235,31 +236,37 @@ class SongsPlugin(Plugin):
If the first time wizard has run, this function is run to import all the
new songs into the database.
"""
Receiver.send_message(u'openlp_process_events')
self.onToolsReindexItemTriggered()
Receiver.send_message(u'openlp_process_events')
db_dir = unicode(os.path.join(
unicode(gettempdir(), get_filesystem_encoding()), u'openlp'))
if not os.path.exists(db_dir):
return
song_dbs = []
song_count = 0
for sfile in os.listdir(db_dir):
if sfile.startswith(u'songs_') and sfile.endswith(u'.sqlite'):
Receiver.send_message(u'openlp_process_events')
song_dbs.append(os.path.join(db_dir, sfile))
song_count += self._countSongs(os.path.join(db_dir, sfile))
if not song_dbs:
return
Receiver.send_message(u'openlp_process_events')
progress = QtGui.QProgressDialog(self.formParent)
progress.setWindowModality(QtCore.Qt.WindowModal)
progress.setWindowTitle(translate('OpenLP.Ui', 'Importing Songs'))
progress.setLabelText(translate('OpenLP.Ui', 'Starting import...'))
progress.setCancelButton(None)
progress.setRange(0, len(song_dbs))
progress.setRange(0, song_count)
progress.setMinimumDuration(0)
progress.forceShow()
for idx, db in enumerate(song_dbs):
progress.setValue(idx)
Receiver.send_message(u'openlp_process_events')
Receiver.send_message(u'openlp_process_events')
for db in song_dbs:
importer = OpenLPSongImport(self.manager, filename=db)
importer.doImport()
progress.setValue(len(song_dbs))
importer.doImport(progress)
Receiver.send_message(u'openlp_process_events')
progress.setValue(song_count)
self.mediaItem.onSearchTextButtonClicked()
def finalise(self):
@ -287,3 +294,15 @@ class SongsPlugin(Plugin):
songs = self.manager.get_all_objects(Song, Song.temporary == True)
for song in songs:
self.manager.delete_object(Song, song.id)
def _countSongs(self, db_file):
connection = sqlite3.connect(db_file)
cursor = connection.cursor()
cursor.execute(u'SELECT COUNT(id) AS song_count FROM songs')
song_count = cursor.fetchone()[0]
connection.close()
try:
song_count = int(song_count)
except (TypeError, ValueError):
song_count = 0
return song_count