From 0f18ec43a060b7f4f7bfe99ddee2bf5d2a4eb583 Mon Sep 17 00:00:00 2001 From: Martin Zibricky Date: Sun, 14 Oct 2012 13:11:48 +0200 Subject: [PATCH] Bug #687638: improved performance of local aware sorting. --- openlp/core/utils/__init__.py | 12 ++++++--- openlp/plugins/songs/forms/songexportform.py | 4 ++- openlp/plugins/songs/lib/db.py | 26 +++++++++++++------- openlp/plugins/songs/lib/mediaitem.py | 5 ++-- 4 files changed, 32 insertions(+), 15 deletions(-) diff --git a/openlp/core/utils/__init__.py b/openlp/core/utils/__init__.py index 764cab06a..742b1e4bc 100644 --- a/openlp/core/utils/__init__.py +++ b/openlp/core/utils/__init__.py @@ -498,8 +498,13 @@ def locale_compare(string1, string2): """ # Function locale.strcol() from standard Python library does not work # properly on Windows and probably somewhere else. - return int(QtCore.QString.localeAwareCompare( - QtCore.QString(string1).toLower(), QtCore.QString(string2).toLower())) + 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 @@ -508,4 +513,5 @@ 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'locale_compare'] + u'delete_file', u'clean_filename', u'format_time', u'locale_compare', + u'locale_direct_compare'] diff --git a/openlp/plugins/songs/forms/songexportform.py b/openlp/plugins/songs/forms/songexportform.py index 15239f9c2..1f2988568 100644 --- a/openlp/plugins/songs/forms/songexportform.py +++ b/openlp/plugins/songs/forms/songexportform.py @@ -37,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 @@ -251,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() + 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: diff --git a/openlp/plugins/songs/lib/db.py b/openlp/plugins/songs/lib/db.py index 36b6d53ad..122d29859 100644 --- a/openlp/plugins/songs/lib/db.py +++ b/openlp/plugins/songs/lib/db.py @@ -31,11 +31,11 @@ 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 -from openlp.core.utils import locale_compare class Author(BaseModel): """ @@ -64,14 +64,22 @@ class Song(BaseModel): """ Song model """ - # By default sort the songs 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 __init__(self): + self.sort_string = '' - def __eq__(self, other): - return 0 == locale_compare(self.title, other.title) + # 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): diff --git a/openlp/plugins/songs/lib/mediaitem.py b/openlp/plugins/songs/lib/mediaitem.py index 0808bcba0..05da69f61 100644 --- a/openlp/plugins/songs/lib/mediaitem.py +++ b/openlp/plugins/songs/lib/mediaitem.py @@ -39,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, \ @@ -259,7 +259,8 @@ class SongMediaItem(MediaManagerItem): log.debug(u'display results Song') self.saveAutoSelectId() self.listView.clear() - searchresults.sort() + searchresults.sort( + cmp=locale_direct_compare, key=lambda song: song.sort_string) for song in searchresults: # Do not display temporary songs if song.temporary: