From 118f295204a1c8548c31919c0cce31610b382a4b Mon Sep 17 00:00:00 2001 From: M2j Date: Sun, 31 Mar 2013 12:31:54 +0200 Subject: [PATCH] Precompute the whole comparision key for song sorting. --- openlp/core/utils/__init__.py | 29 ++++++++------------ openlp/plugins/songs/forms/songexportform.py | 3 +- openlp/plugins/songs/lib/db.py | 28 +++---------------- openlp/plugins/songs/lib/mediaitem.py | 4 +-- 4 files changed, 18 insertions(+), 46 deletions(-) diff --git a/openlp/core/utils/__init__.py b/openlp/core/utils/__init__.py index 625bd25b5..ba7e4dd25 100644 --- a/openlp/core/utils/__init__.py +++ b/openlp/core/utils/__init__.py @@ -398,25 +398,18 @@ def get_local_key(string): def get_natural_key(string): """ - Generate a key for locale aware natural string sorting. Returns a list of strings and integers. - - ``string`` - A string, list or tuple which represents the item string. + Generate a key for locale aware natural string sorting. + Returns a list of string compare keys and integers. """ - if isinstance(string, basestring): - string = re.findall(r'(\d+|\D+)', string) - if len(string) == 1: - return list(get_local_key(string[0])) - elif isinstance(string, tuple): - string = list(string) - if isinstance(string, list): - for index, part in enumerate(string): - if isinstance(part, basestring): - if part.isdigit(): - string[index] = int(part) - else: - string[index] = get_local_key(part) - return string + key = re.findall(r'(\d+|\D+)', string) + if len(key) == 1: + return list(get_local_key(string)) + for index, part in enumerate(key): + if part.isdigit(): + key[index] = int(part) + else: + key[index] = get_local_key(part) + return key from applocation import AppLocation diff --git a/openlp/plugins/songs/forms/songexportform.py b/openlp/plugins/songs/forms/songexportform.py index 94748d3e4..f0554f588 100644 --- a/openlp/plugins/songs/forms/songexportform.py +++ b/openlp/plugins/songs/forms/songexportform.py @@ -37,7 +37,6 @@ from PyQt4 import QtCore, QtGui from openlp.core.lib import Registry, UiStrings, create_separated_list, build_icon, translate from openlp.core.lib.ui import critical_error_message_box from openlp.core.ui.wizard import OpenLPWizard, WizardStrings -from openlp.core.utils import get_natural_key from openlp.plugins.songs.lib.db import Song from openlp.plugins.songs.lib.openlyricsexport import OpenLyricsExport @@ -222,7 +221,7 @@ class SongExportForm(OpenLPWizard): # Load the list of songs. self.application.set_busy_cursor() songs = self.plugin.manager.get_all_objects(Song) - songs.sort(key=lambda song: get_natural_key(song.sort_key)) + songs.sort(key=lambda song: song.sort_key) 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 db5f59357..015caa87d 100644 --- a/openlp/plugins/songs/lib/db.py +++ b/openlp/plugins/songs/lib/db.py @@ -38,6 +38,7 @@ from sqlalchemy.orm import mapper, relation, reconstructor from sqlalchemy.sql.expression import func from openlp.core.lib.db import BaseModel, init_db +from openlp.core.utils import get_natural_key class Author(BaseModel): @@ -69,36 +70,15 @@ class Song(BaseModel): def __init__(self): self.sort_key = () - def _try_int(self, s): - """ - Convert to integer if possible. - """ - try: - return int(s) - except: - return s.lower() - - def _natsort_key(self, s): - """ - Used internally to get a tuple by which s is sorted. - """ - return map(self._try_int, re.findall(r'(\d+|\D+)', s)) - - # This decorator tells sqlalchemy to call this method everytime - # any data on this object is updated. - @reconstructor def init_on_load(self): """ - Precompute a tuple to be used for sorting. + Precompute a natural sorting, locale aware sorting key. Song sorting is performance sensitive operation. - To get maximum speed lets precompute the string - used for comparison. + To get maximum speed lets precompute the sorting key. """ - # Avoid the overhead of converting string to lowercase and to QString - # with every call to sort(). - self.sort_key = self._natsort_key(self.title) + self.sort_key = get_natural_key(self.title) class Topic(BaseModel): diff --git a/openlp/plugins/songs/lib/mediaitem.py b/openlp/plugins/songs/lib/mediaitem.py index 81aab4d0f..d75124d84 100644 --- a/openlp/plugins/songs/lib/mediaitem.py +++ b/openlp/plugins/songs/lib/mediaitem.py @@ -38,7 +38,7 @@ from sqlalchemy.sql import or_ from openlp.core.lib import Registry, MediaManagerItem, ItemCapabilities, PluginStatus, ServiceItemContext, Settings, \ UiStrings, translate, check_item_selected, create_separated_list, check_directory_exists from openlp.core.lib.ui import create_widget_action -from openlp.core.utils import AppLocation, get_natural_key +from openlp.core.utils import AppLocation from openlp.plugins.songs.forms.editsongform import EditSongForm from openlp.plugins.songs.forms.songmaintenanceform import SongMaintenanceForm from openlp.plugins.songs.forms.songimportform import SongImportForm @@ -225,7 +225,7 @@ class SongMediaItem(MediaManagerItem): log.debug(u'display results Song') self.save_auto_select_id() self.list_view.clear() - searchresults.sort(key=lambda song: get_natural_key(song.sort_key)) + searchresults.sort(key=lambda song: song.sort_key) for song in searchresults: # Do not display temporary songs if song.temporary: