This should fix the locale aware sorting of songs and other items. The implementation uses Qt function QString.localeAwareCompare() for that.

bzr-revno: 2086
Fixes: https://launchpad.net/bugs/687638
This commit is contained in:
Martin Zibricky 2012-10-13 19:08:33 +02:00 committed by Raoul Snyman
commit 5c8c5cafaa
12 changed files with 64 additions and 44 deletions

View File

@ -30,7 +30,6 @@ import os
import zipfile import zipfile
import shutil import shutil
import logging import logging
import locale
import re import re
from xml.etree.ElementTree import ElementTree, XML 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 create_widget_action
from openlp.core.theme import Theme from openlp.core.theme import Theme
from openlp.core.ui import FileRenameForm, ThemeForm 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__) log = logging.getLogger(__name__)
@ -457,9 +457,8 @@ class ThemeManager(QtGui.QWidget):
self.configUpdated() self.configUpdated()
files = SettingsManager.get_files(self.settingsSection, u'.png') files = SettingsManager.get_files(self.settingsSection, u'.png')
# Sort the themes by its name considering language specific characters. # Sort the themes by its name considering language specific characters.
# lower() is needed for windows! files.sort(key=lambda file_name: unicode(file_name),
files.sort(key=lambda file_name: unicode(file_name).lower(), cmp=locale_compare)
cmp=locale.strcoll)
# now process the file list of png files # now process the file list of png files
for name in files: for name in files:
# check to see file is in theme root directory # check to see file is in theme root directory

View File

@ -488,10 +488,24 @@ def format_time(text, local_time):
return re.sub('\%[a-zA-Z]', match_formatting, text) 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 int(QtCore.QString.localeAwareCompare(
QtCore.QString(string1).toLower(), QtCore.QString(string2).toLower()))
from languagemanager import LanguageManager from languagemanager import LanguageManager
from actions import ActionList from actions import ActionList
__all__ = [u'AppLocation', u'get_application_version', u'check_latest_version', __all__ = [u'AppLocation', u'get_application_version', u'check_latest_version',
u'add_actions', u'get_filesystem_encoding', u'LanguageManager', u'add_actions', u'get_filesystem_encoding', u'LanguageManager',
u'ActionList', u'get_web_page', u'get_uno_command', u'get_uno_instance', 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']

View File

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

View File

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

View File

@ -34,12 +34,21 @@ from sqlalchemy import Column, Table, types
from sqlalchemy.orm import mapper from sqlalchemy.orm import mapper
from openlp.core.lib.db import BaseModel, init_db from openlp.core.lib.db import BaseModel, init_db
from openlp.core.utils import locale_compare
class CustomSlide(BaseModel): class CustomSlide(BaseModel):
""" """
CustomSlide model 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): def init_schema(url):
""" """

View File

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

View File

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

View File

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

View File

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

View File

@ -29,7 +29,6 @@
The :mod:`songexportform` module provides the wizard for exporting songs to the The :mod:`songexportform` module provides the wizard for exporting songs to the
OpenLyrics format. OpenLyrics format.
""" """
import locale
import logging import logging
from PyQt4 import QtCore, QtGui from PyQt4 import QtCore, QtGui
@ -252,7 +251,7 @@ class SongExportForm(OpenLPWizard):
# Load the list of songs. # Load the list of songs.
Receiver.send_message(u'cursor_busy') Receiver.send_message(u'cursor_busy')
songs = self.plugin.manager.get_all_objects(Song) songs = self.plugin.manager.get_all_objects(Song)
songs.sort(cmp=locale.strcoll, key=lambda song: song.title.lower()) songs.sort()
for song in songs: for song in songs:
# No need to export temporary songs. # No need to export temporary songs.
if song.temporary: if song.temporary:

View File

@ -35,6 +35,7 @@ from sqlalchemy.orm import mapper, relation
from sqlalchemy.sql.expression import func from sqlalchemy.sql.expression import func
from openlp.core.lib.db import BaseModel, init_db from openlp.core.lib.db import BaseModel, init_db
from openlp.core.utils import locale_compare
class Author(BaseModel): class Author(BaseModel):
""" """
@ -63,7 +64,14 @@ class Song(BaseModel):
""" """
Song model Song model
""" """
pass # 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 __eq__(self, other):
return 0 == locale_compare(self.title, other.title)
class Topic(BaseModel): class Topic(BaseModel):

View File

@ -27,7 +27,6 @@
############################################################################### ###############################################################################
import logging import logging
import locale
import re import re
import os import os
import shutil import shutil
@ -260,10 +259,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()
# Sort the songs by its title considering language specific characters. searchresults.sort()
# lower() is needed for windows!
searchresults.sort(
cmp=locale.strcoll, key=lambda song: song.title.lower())
for song in searchresults: for song in searchresults:
# Do not display temporary songs # Do not display temporary songs
if song.temporary: if song.temporary: