← Back to team overview

openlp-core team mailing list archive

[Merge] lp:~mzibricky/openlp/bug-687638 into lp:openlp

 

matysek has proposed merging lp:~mzibricky/openlp/bug-687638 into lp:openlp.

Requested reviews:
  Raoul Snyman (raoul-snyman)
  Tim Bentley (trb143)

For more details, see:
https://code.launchpad.net/~mzibricky/openlp/bug-687638/+merge/129501

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

Some inspiration is based on branch ~m2j/openlp/bug-687638.

I tested it mostly on osx. I probably need to test it on windows with a build.
-- 
https://code.launchpad.net/~mzibricky/openlp/bug-687638/+merge/129501
Your team OpenLP Core is subscribed to branch lp:openlp.
=== modified file 'openlp/core/ui/thememanager.py'
--- openlp/core/ui/thememanager.py	2012-09-19 18:43:02 +0000
+++ openlp/core/ui/thememanager.py	2012-10-12 19:42:25 +0000
@@ -30,7 +30,6 @@
 import zipfile
 import shutil
 import logging
-import locale
 import re
 
 from xml.etree.ElementTree import ElementTree, XML
@@ -46,7 +45,8 @@
     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__)
 
@@ -457,9 +457,8 @@
                 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

=== modified file 'openlp/core/utils/__init__.py'
--- openlp/core/utils/__init__.py	2012-09-17 22:20:38 +0000
+++ openlp/core/utils/__init__.py	2012-10-12 19:42:25 +0000
@@ -488,10 +488,24 @@
     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 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']

=== modified file 'openlp/plugins/bibles/forms/bibleimportform.py'
--- openlp/plugins/bibles/forms/bibleimportform.py	2012-06-22 14:14:53 +0000
+++ openlp/plugins/bibles/forms/bibleimportform.py	2012-10-12 19:42:25 +0000
@@ -30,7 +30,6 @@
 """
 import logging
 import os
-import locale
 
 from PyQt4 import QtCore, QtGui
 
@@ -39,7 +38,7 @@
 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 @@
         """
         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):

=== modified file 'openlp/plugins/bibles/lib/mediaitem.py'
--- openlp/plugins/bibles/lib/mediaitem.py	2012-07-10 04:56:07 +0000
+++ openlp/plugins/bibles/lib/mediaitem.py	2012-10-12 19:42:25 +0000
@@ -27,7 +27,6 @@
 ###############################################################################
 
 import logging
-import locale
 
 from PyQt4 import QtCore, QtGui
 
@@ -38,6 +37,7 @@
 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 @@
         # 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 @@
                         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):

=== modified file 'openlp/plugins/custom/lib/db.py'
--- openlp/plugins/custom/lib/db.py	2012-06-22 14:14:53 +0000
+++ openlp/plugins/custom/lib/db.py	2012-10-12 19:42:25 +0000
@@ -34,12 +34,21 @@
 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):
     """

=== modified file 'openlp/plugins/custom/lib/mediaitem.py'
--- openlp/plugins/custom/lib/mediaitem.py	2012-06-22 14:14:53 +0000
+++ openlp/plugins/custom/lib/mediaitem.py	2012-10-12 19:42:25 +0000
@@ -27,7 +27,6 @@
 ###############################################################################
 
 import logging
-import locale
 
 from PyQt4 import QtCore, QtGui
 from sqlalchemy.sql import or_, func
@@ -109,10 +108,7 @@
         # 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(

=== modified file 'openlp/plugins/images/lib/mediaitem.py'
--- openlp/plugins/images/lib/mediaitem.py	2012-06-30 15:19:33 +0000
+++ openlp/plugins/images/lib/mediaitem.py	2012-10-12 19:42:25 +0000
@@ -28,7 +28,6 @@
 
 import logging
 import os
-import locale
 
 from PyQt4 import QtCore, QtGui
 
@@ -37,7 +36,8 @@
     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 @@
         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)

=== modified file 'openlp/plugins/media/lib/mediaitem.py'
--- openlp/plugins/media/lib/mediaitem.py	2012-10-09 18:00:33 +0000
+++ openlp/plugins/media/lib/mediaitem.py	2012-10-12 19:42:25 +0000
@@ -28,7 +28,6 @@
 
 import logging
 import os
-import locale
 
 from PyQt4 import QtCore, QtGui
 
@@ -39,6 +38,7 @@
     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 @@
                 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 @@
 
     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

=== modified file 'openlp/plugins/presentations/lib/mediaitem.py'
--- openlp/plugins/presentations/lib/mediaitem.py	2012-06-22 14:14:53 +0000
+++ openlp/plugins/presentations/lib/mediaitem.py	2012-10-12 19:42:25 +0000
@@ -28,7 +28,6 @@
 
 import logging
 import os
-import locale
 
 from PyQt4 import QtCore, QtGui
 
@@ -38,6 +37,7 @@
 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 @@
         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()

=== modified file 'openlp/plugins/songs/forms/songexportform.py'
--- openlp/plugins/songs/forms/songexportform.py	2012-06-22 14:14:53 +0000
+++ openlp/plugins/songs/forms/songexportform.py	2012-10-12 19:42:25 +0000
@@ -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
@@ -252,7 +251,7 @@
         # 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()
         for song in songs:
             # No need to export temporary songs.
             if song.temporary:

=== modified file 'openlp/plugins/songs/lib/db.py'
--- openlp/plugins/songs/lib/db.py	2012-06-22 14:14:53 +0000
+++ openlp/plugins/songs/lib/db.py	2012-10-12 19:42:25 +0000
@@ -35,6 +35,7 @@
 from sqlalchemy.sql.expression import func
 
 from openlp.core.lib.db import BaseModel, init_db
+from openlp.core.utils import locale_compare
 
 class Author(BaseModel):
     """
@@ -63,7 +64,14 @@
     """
     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):

=== modified file 'openlp/plugins/songs/lib/mediaitem.py'
--- openlp/plugins/songs/lib/mediaitem.py	2012-07-07 14:54:14 +0000
+++ openlp/plugins/songs/lib/mediaitem.py	2012-10-12 19:42:25 +0000
@@ -27,7 +27,6 @@
 ###############################################################################
 
 import logging
-import locale
 import re
 import os
 import shutil
@@ -260,10 +259,7 @@
         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())
+        searchresults.sort()
         for song in searchresults:
             # Do not display temporary songs
             if song.temporary:


Follow ups