From dc3c71ac579a1a89b2d6cce0f478d859eda78392 Mon Sep 17 00:00:00 2001 From: Yevgen Muntyan <17531749+muntyan@users.noreply.github.com> Date: Mon, 5 May 2008 10:22:38 -0500 Subject: [PATCH] Fixed sorting order on mac --- moo/moofileview/moofile-private.h | 11 +- moo/moofileview/moofile.c | 167 ++++++++++++++++++++++- moo/moofileview/moofolder.c | 2 +- moo/moofileview/moofoldermodel-private.h | 48 ++++++- 4 files changed, 216 insertions(+), 12 deletions(-) diff --git a/moo/moofileview/moofile-private.h b/moo/moofileview/moofile-private.h index 3ecd3293..ac85fc64 100644 --- a/moo/moofileview/moofile-private.h +++ b/moo/moofileview/moofile-private.h @@ -38,6 +38,7 @@ typedef GTime MooFileTime; #endif typedef gint64 MooFileSize; +typedef struct MooCollationKey MooCollationKey; struct _MooFile { @@ -45,7 +46,7 @@ struct _MooFile char *link_target; char *display_name; /* normalized */ char *case_display_name; - char *collation_key; + MooCollationKey *collation_key; MooFileInfo info; MooFileFlags flags; guint8 icon; @@ -74,8 +75,12 @@ GdkPixbuf *_moo_file_get_icon (const MooFile *file, GtkWidget *widget, GtkIconSize size); -const char *_moo_file_collation_key (const MooFile *file); -const char *_moo_file_case_display_name(const MooFile *file); +gsize _moo_collation_key_size (MooCollationKey *key); +int _moo_collation_key_cmp (const MooCollationKey *key1, + const MooCollationKey *key2); +const MooCollationKey *_moo_file_collation_key (const MooFile *file); + +const char *_moo_file_case_display_name(const MooFile *file); #ifndef __WIN32__ const char *_moo_file_link_get_target (const MooFile *file); diff --git a/moo/moofileview/moofile.c b/moo/moofileview/moofile.c index 50a6e656..932cf0cb 100644 --- a/moo/moofileview/moofile.c +++ b/moo/moofileview/moofile.c @@ -37,6 +37,9 @@ #endif #include #include +#if defined(HAVE_CARBON) +#include +#endif #include #include #include @@ -91,6 +94,166 @@ _moo_file_find_mime_type (MooFile *file, } +#if defined(HAVE_CARBON) + +struct MooCollationKey { + guint len; + UCCollationValue buf[1]; +}; + +static MooCollationKey * +create_collation_key (CollatorRef collator, + const gchar *str, + gssize len) +{ + MooCollationKey *key = NULL; + UniChar *str_utf16 = NULL; + ItemCount actual_len; + ItemCount try_len; + glong len_utf16; + OSStatus ret; + UCCollationValue buf[512]; + + if (!collator) + goto error; + + str_utf16 = g_utf8_to_utf16 (str, len, NULL, &len_utf16, NULL); + try_len = len_utf16 * 5 + 2; + + if (try_len <= sizeof buf) + { + ret = UCGetCollationKey (collator, str_utf16, len_utf16, + sizeof buf, &actual_len, buf); + + if (ret == 0) + { + key = g_malloc (sizeof (MooCollationKey) + (actual_len - 1) * sizeof (UCCollationValue)); + memcpy (key->buf, buf, actual_len * sizeof (UCCollationValue)); + } + else if (ret == kCollateBufferTooSmall) + try_len *= 2; + else + goto error; + } + + if (!key) + { + key = g_malloc (sizeof (MooCollationKey) + (try_len - 1) * sizeof (UCCollationValue)); + ret = UCGetCollationKey (collator, str_utf16, len_utf16, + try_len, &actual_len, key->buf); + + if (ret == kCollateBufferTooSmall) + { + try_len *= 2; + key = g_realloc (key, sizeof (MooCollationKey) + (actual_len - 1) * sizeof (UCCollationValue)); + ret = UCGetCollationKey (collator, str_utf16, len_utf16, + try_len, &actual_len, key->buf); + } + + if (ret != 0) + goto error; + } + + key->len = actual_len; + + g_free (str_utf16); + return key; + +error: + g_free (str_utf16); + g_free (key); + key = g_new (MooCollationKey, 1); + key->len = 0; + return key; +} + +G_GNUC_UNUSED static MooCollationKey * +moo_get_collation_key (const char *str, + gssize len) +{ + static CollatorRef collator; + + if (G_UNLIKELY (!collator)) + { + UCCreateCollator (NULL, 0, kUCCollateStandardOptions, &collator); + + if (!collator) + g_warning ("%s: UCCreateCollator failed", G_STRLOC); + } + + return create_collation_key (collator, str, len); +} + +static MooCollationKey * +moo_get_collation_key_for_filename (const char *str, + gssize len) +{ + static CollatorRef collator; + + if (G_UNLIKELY (!collator)) + { + /* http://developer.apple.com/qa/qa2004/qa1159.html */ + UCCreateCollator (NULL, 0, + kUCCollateComposeInsensitiveMask + | kUCCollateWidthInsensitiveMask + | kUCCollateCaseInsensitiveMask + | kUCCollateDigitsOverrideMask + | kUCCollateDigitsAsNumberMask + | kUCCollatePunctuationSignificantMask, + &collator); + + if (!collator) + g_warning ("%s: UCCreateCollator failed", G_STRLOC); + } + + return create_collation_key (collator, str, len); +} + +int +_moo_collation_key_cmp (const MooCollationKey *key1, + const MooCollationKey *key2) +{ + SInt32 order = 0; + + g_return_val_if_fail (key1 != NULL, 0); + g_return_val_if_fail (key2 != NULL, 0); + + UCCompareCollationKeys (key1->buf, key1->len, + key2->buf, key2->len, + NULL, &order); + return order; +} + +gsize +_moo_collation_key_size (MooCollationKey *key) +{ + return key ? + sizeof (MooCollationKey) + + key->len * sizeof (UCCollationValue) - + sizeof (UCCollationValue) : + 0; +} + +#else + +#define moo_get_collation_key_for_filename(fn,len) ((MooCollationKey*)g_utf8_collate_key_for_filename(fn,len)) + +int +_moo_collation_key_cmp (const MooCollationKey *key1, + const MooCollationKey *key2) +{ + return strcmp ((const char*) key1, (const char*) key2); +} + +gsize +_moo_collation_key_size (MooCollationKey *key) +{ + return key ? strlen ((char*) key) + 1 : 0; +} + +#endif + + /********************************************************************/ /* MooFile */ @@ -125,7 +288,7 @@ _moo_file_new (const char *dirname, file->display_name = g_utf8_normalize (display_name, -1, G_NORMALIZE_ALL); file->case_display_name = g_utf8_casefold (file->display_name, -1); - file->collation_key = g_utf8_collate_key_for_filename (file->display_name, -1); + file->collation_key = moo_get_collation_key_for_filename (file->display_name, -1); g_free (path); g_free (display_name); @@ -333,7 +496,7 @@ _moo_file_display_name (const MooFile *file) return file->display_name; } -const char * +const MooCollationKey * _moo_file_collation_key (const MooFile *file) { g_return_val_if_fail (file != NULL, NULL); diff --git a/moo/moofileview/moofolder.c b/moo/moofileview/moofolder.c index ba9d2d69..ac9993a3 100644 --- a/moo/moofileview/moofolder.c +++ b/moo/moofileview/moofolder.c @@ -240,7 +240,7 @@ add_file_size (G_GNUC_UNUSED const char *filename, *mem += STRING_SIZE (file->link_target); *mem += STRING_SIZE (file->display_name); *mem += STRING_SIZE (file->case_display_name); - *mem += STRING_SIZE (file->collation_key); + *mem += _moo_collation_key_size (file->collation_key); #undef STRING_SIZE } diff --git a/moo/moofileview/moofoldermodel-private.h b/moo/moofileview/moofoldermodel-private.h index cf7edaf5..284ec4de 100644 --- a/moo/moofileview/moofoldermodel-private.h +++ b/moo/moofileview/moofoldermodel-private.h @@ -336,20 +336,56 @@ static GList *_list_find (FileList *flist, } -static int moo_file_case_cmp (MooFile *f1, - MooFile *f2) +static int +moo_file_case_cmp (MooFile *f1, + MooFile *f2) +{ + if (!strcmp (_moo_file_name (f1), "..")) + return strcmp (_moo_file_name (f2), "..") ? -1 : 0; + else if (!strcmp (_moo_file_name (f2), "..")) + return 1; + else if (MOO_FILE_IS_DIR (f1) && !MOO_FILE_IS_DIR (f2)) + return -1; + else if (!MOO_FILE_IS_DIR (f1) && MOO_FILE_IS_DIR (f2)) + return 1; + else + return _moo_collation_key_cmp (_moo_file_collation_key (f1), + _moo_file_collation_key (f2)); +} + +static int +moo_file_cmp (MooFile *f1, + MooFile *f2) +{ + if (!strcmp (_moo_file_name (f1), "..")) + return strcmp (_moo_file_name (f2), "..") ? -1 : 0; + else if (!strcmp (_moo_file_name (f2), "..")) + return 1; + else if (MOO_FILE_IS_DIR (f1) && !MOO_FILE_IS_DIR (f2)) + return -1; + else if (!MOO_FILE_IS_DIR (f1) && MOO_FILE_IS_DIR (f2)) + return 1; + else + return strcmp (_moo_file_display_name (f1), + _moo_file_display_name (f2)); +} + +static int +moo_file_case_cmp_fi (MooFile *f1, + MooFile *f2) { if (!strcmp (_moo_file_name (f1), "..")) return strcmp (_moo_file_name (f2), "..") ? -1 : 0; else if (!strcmp (_moo_file_name (f2), "..")) return 1; else - return strcmp (_moo_file_collation_key (f1), - _moo_file_collation_key (f2)); + return _moo_collation_key_cmp (_moo_file_collation_key (f1), + _moo_file_collation_key (f2)); } -static int moo_file_cmp (MooFile *f1, - MooFile *f2) +static int +moo_file_cmp_fi (MooFile *f1, + MooFile *f2) { if (!strcmp (_moo_file_name (f1), "..")) return strcmp (_moo_file_name (f2), "..") ? -1 : 0;