forked from openlp/openlp
Fix song "10 bla" comes before "2 foo"
bzr-revno: 2113
This commit is contained in:
commit
12e7f7384d
@ -31,6 +31,8 @@ The :mod:`db` module provides the database and schema that is the backend for
|
|||||||
the Songs plugin
|
the Songs plugin
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import re
|
||||||
|
|
||||||
from sqlalchemy import Column, ForeignKey, Table, types
|
from sqlalchemy import Column, ForeignKey, Table, types
|
||||||
from sqlalchemy.orm import mapper, relation, reconstructor
|
from sqlalchemy.orm import mapper, relation, reconstructor
|
||||||
from sqlalchemy.sql.expression import func
|
from sqlalchemy.sql.expression import func
|
||||||
@ -38,6 +40,7 @@ from PyQt4 import QtCore
|
|||||||
|
|
||||||
from openlp.core.lib.db import BaseModel, init_db
|
from openlp.core.lib.db import BaseModel, init_db
|
||||||
|
|
||||||
|
|
||||||
class Author(BaseModel):
|
class Author(BaseModel):
|
||||||
"""
|
"""
|
||||||
Author model
|
Author model
|
||||||
@ -66,21 +69,33 @@ class Song(BaseModel):
|
|||||||
Song model
|
Song model
|
||||||
"""
|
"""
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.sort_string = ''
|
self.sort_key = ()
|
||||||
|
|
||||||
|
def _try_int(self, s):
|
||||||
|
"Convert to integer if possible."
|
||||||
|
try:
|
||||||
|
return int(s)
|
||||||
|
except:
|
||||||
|
return QtCore.QString(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
|
# This decorator tells sqlalchemy to call this method everytime
|
||||||
# any data on this object are updated.
|
# any data on this object is updated.
|
||||||
@reconstructor
|
@reconstructor
|
||||||
def init_on_load(self):
|
def init_on_load(self):
|
||||||
"""
|
"""
|
||||||
Precompute string to be used for sorting.
|
Precompute a tuple to be used for sorting.
|
||||||
|
|
||||||
Song sorting is performance sensitive operation.
|
Song sorting is performance sensitive operation.
|
||||||
To get maximum speed lets precompute the string
|
To get maximum speed lets precompute the string
|
||||||
used for comparison.
|
used for comparison.
|
||||||
"""
|
"""
|
||||||
# Avoid the overhead of converting string to lowercase and to QString
|
# Avoid the overhead of converting string to lowercase and to QString
|
||||||
self.sort_string = QtCore.QString(self.title.lower())
|
# with every call to sort().
|
||||||
|
self.sort_key = self._natsort_key(self.title)
|
||||||
|
|
||||||
|
|
||||||
class Topic(BaseModel):
|
class Topic(BaseModel):
|
||||||
|
@ -50,6 +50,44 @@ from openlp.plugins.songs.lib.ui import SongStrings
|
|||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
def natcmp(a, b):
|
||||||
|
"""
|
||||||
|
Natural string comparison which mimics the behaviour of Python's internal
|
||||||
|
cmp function.
|
||||||
|
"""
|
||||||
|
log.debug('a: %s; b: %s', a, b)
|
||||||
|
if len(a) <= len(b):
|
||||||
|
for i, key in enumerate(a):
|
||||||
|
if isinstance(key, int) and isinstance(b[i], int):
|
||||||
|
result = cmp(key, b[i])
|
||||||
|
elif isinstance(key, int) and not isinstance(b[i], int):
|
||||||
|
result = locale_direct_compare(QtCore.QString(str(key)), b[i])
|
||||||
|
elif not isinstance(key, int) and isinstance(b[i], int):
|
||||||
|
result = locale_direct_compare(key, QtCore.QString(str(b[i])))
|
||||||
|
else:
|
||||||
|
result = locale_direct_compare(key, b[i])
|
||||||
|
if result != 0:
|
||||||
|
return result
|
||||||
|
if len(a) == len(b):
|
||||||
|
return 0
|
||||||
|
else:
|
||||||
|
return -1
|
||||||
|
else:
|
||||||
|
for i, key in enumerate(b):
|
||||||
|
if isinstance(a[i], int) and isinstance(key, int):
|
||||||
|
result = cmp(a[i], key)
|
||||||
|
elif isinstance(a[i], int) and not isinstance(key, int):
|
||||||
|
result = locale_direct_compare(QtCore.QString(str(a[i])), key)
|
||||||
|
elif not isinstance(a[i], int) and isinstance(key, int):
|
||||||
|
result = locale_direct_compare(a[i], QtCore.QString(str(key)))
|
||||||
|
else:
|
||||||
|
result = locale_direct_compare(a[i], key)
|
||||||
|
if result != 0:
|
||||||
|
return result
|
||||||
|
return 1
|
||||||
|
|
||||||
|
|
||||||
class SongSearch(object):
|
class SongSearch(object):
|
||||||
"""
|
"""
|
||||||
An enumeration for song search methods.
|
An enumeration for song search methods.
|
||||||
@ -260,8 +298,7 @@ class SongMediaItem(MediaManagerItem):
|
|||||||
log.debug(u'display results Song')
|
log.debug(u'display results Song')
|
||||||
self.saveAutoSelectId()
|
self.saveAutoSelectId()
|
||||||
self.listView.clear()
|
self.listView.clear()
|
||||||
searchresults.sort(
|
searchresults.sort(cmp=natcmp, key=lambda song: song.sort_key)
|
||||||
cmp=locale_direct_compare, key=lambda song: song.sort_string)
|
|
||||||
for song in searchresults:
|
for song in searchresults:
|
||||||
# Do not display temporary songs
|
# Do not display temporary songs
|
||||||
if song.temporary:
|
if song.temporary:
|
||||||
|
Loading…
Reference in New Issue
Block a user