diff --git a/fbreader/app/src/main/java/org/fbreader/util/NaturalOrderComparator.java b/fbreader/app/src/main/java/org/fbreader/util/NaturalOrderComparator.java new file mode 100644 index 000000000..904829209 --- /dev/null +++ b/fbreader/app/src/main/java/org/fbreader/util/NaturalOrderComparator.java @@ -0,0 +1,134 @@ +package org.fbreader.util; + +/* + NaturalOrderComparator.java -- Perform 'natural order' comparisons of strings in Java. + Copyright (C) 2003 by Pierre-Luc Paour + + Based on the C version by Martin Pool, of which this is more or less a straight conversion. + Copyright (C) 2000 by Martin Pool + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + */ + +import java.util.Comparator; + +public class NaturalOrderComparator implements Comparator { + int compareRight(String a, String b) { + int bias = 0; + int ia = 0; + int ib = 0; + + // The longest run of digits wins. That aside, the greatest + // value wins, but we can't know that it will until we've scanned + // both numbers to know that they have the same magnitude, so we + // remember it in BIAS. + for (;; ia++, ib++) { + char ca = charAt(a, ia); + char cb = charAt(b, ib); + + if (!Character.isDigit(ca) && !Character.isDigit(cb)) { + return bias; + } else if (!Character.isDigit(ca)) { + return -1; + } else if (!Character.isDigit(cb)) { + return +1; + } else if (ca < cb) { + if (bias == 0) { + bias = -1; + } + } else if (ca > cb) { + if (bias == 0) + bias = +1; + } else if (ca == 0 && cb == 0) { + return bias; + } + } + } + + public int compare(String a, String b) { + if ((!a.toLowerCase().equals(a) || !b.toLowerCase().equals(b)) && !a.equalsIgnoreCase(b)) { + return compare(a.toLowerCase(), b.toLowerCase()); + } + + int ia = 0, ib = 0; + int nza = 0, nzb = 0; + char ca, cb; + int result; + + while (true) { + // only count the number of zeroes leading the last number compared + nza = nzb = 0; + + ca = charAt(a, ia); + cb = charAt(b, ib); + + // skip over leading spaces or zeros + while (Character.isSpaceChar(ca) || ca == '0') { + if (ca == '0') { + nza++; + } else { + // only count consecutive zeroes + nza = 0; + } + + ca = charAt(a, ++ia); + } + + while (Character.isSpaceChar(cb) || cb == '0') { + if (cb == '0') { + nzb++; + } else { + // only count consecutive zeroes + nzb = 0; + } + + cb = charAt(b, ++ib); + } + + // process run of digits + if (Character.isDigit(ca) && Character.isDigit(cb)) { + if ((result = compareRight(a.substring(ia), b.substring(ib))) != 0) { + return result; + } + } + + if (ca == 0 && cb == 0) { + // The strings compare the same. Perhaps the caller + // will want to call strcmp to break the tie. + return nza - nzb; + } + + if (ca < cb) { + return -1; + } else if (ca > cb) { + return +1; + } + + ++ia; + ++ib; + } + } + + static char charAt(String s, int i) { + if (i >= s.length()) { + return 0; + } else { + return s.charAt(i); + } + } + +} diff --git a/fbreader/app/src/main/java/org/geometerplus/fbreader/library/FileTree.java b/fbreader/app/src/main/java/org/geometerplus/fbreader/library/FileTree.java index 58dd21147..11d56b1be 100644 --- a/fbreader/app/src/main/java/org/geometerplus/fbreader/library/FileTree.java +++ b/fbreader/app/src/main/java/org/geometerplus/fbreader/library/FileTree.java @@ -21,6 +21,7 @@ package org.geometerplus.fbreader.library; import java.util.*; +import org.fbreader.util.NaturalOrderComparator; import org.fbreader.util.Pair; import org.geometerplus.zlibrary.core.filesystem.ZLFile; @@ -30,6 +31,19 @@ import org.geometerplus.fbreader.book.*; import org.geometerplus.fbreader.tree.FBTree; public class FileTree extends LibraryTree { + private static final NaturalOrderComparator ourNaturalOrderComparator = + new NaturalOrderComparator(); + + private static final Comparator ourFileComparator = new Comparator() { + public int compare(ZLFile file0, ZLFile file1) { + final boolean isDir = file0.isDirectory(); + if (isDir != file1.isDirectory()) { + return isDir ? -1 : 1; + } + return ourNaturalOrderComparator.compare(file0.getShortName(), file1.getShortName()); + } + }; + private final ZLFile myFile; private final String myName; private final String mySummary; @@ -168,16 +182,6 @@ public class FileTree extends LibraryTree { return myFile.equals(((FileTree)o).myFile); } - private static final Comparator ourFileComparator = new Comparator() { - public int compare(ZLFile file0, ZLFile file1) { - final boolean isDir = file0.isDirectory(); - if (isDir != file1.isDirectory()) { - return isDir ? -1 : 1; - } - return file0.getShortName().compareToIgnoreCase(file1.getShortName()); - } - }; - @Override public int compareTo(FBTree tree) { return ourFileComparator.compare(myFile, ((FileTree)tree).myFile); diff --git a/fbreader/app/src/main/java/org/geometerplus/fbreader/sort/TitledEntity.java b/fbreader/app/src/main/java/org/geometerplus/fbreader/sort/TitledEntity.java index b6d476e0b..2818531dd 100644 --- a/fbreader/app/src/main/java/org/geometerplus/fbreader/sort/TitledEntity.java +++ b/fbreader/app/src/main/java/org/geometerplus/fbreader/sort/TitledEntity.java @@ -26,7 +26,11 @@ import java.util.Map; import android.annotation.TargetApi; import android.os.Build; +import org.fbreader.util.NaturalOrderComparator; + public abstract class TitledEntity> implements Comparable { + private static final NaturalOrderComparator ourComparator = new NaturalOrderComparator(); + private String myTitle; private String mySortKey; @@ -66,7 +70,7 @@ public abstract class TitledEntity> implements Compara @Override public int compareTo(T other) { - return getSortKey().compareTo(other.getSortKey()); + return ourComparator.compare(getSortKey(), other.getSortKey()); } private final static Map ARTICLES = new HashMap(); diff --git a/third-party/android-filechooser/code/src/group/pals/android/lib/ui/filechooser/utils/FileComparator.java b/third-party/android-filechooser/code/src/group/pals/android/lib/ui/filechooser/utils/FileComparator.java index bfc38a307..31990d27a 100755 --- a/third-party/android-filechooser/code/src/group/pals/android/lib/ui/filechooser/utils/FileComparator.java +++ b/third-party/android-filechooser/code/src/group/pals/android/lib/ui/filechooser/utils/FileComparator.java @@ -13,6 +13,8 @@ import group.pals.android.lib.ui.filechooser.services.IFileProvider; import java.util.Comparator; +import org.fbreader.util.NaturalOrderComparator; + /** * {@link IFile} comparator.
* Rules:
@@ -24,6 +26,8 @@ import java.util.Comparator; * @since v1.91 */ public class FileComparator implements Comparator { + private static final NaturalOrderComparator ourNaturalOrderComparator = + new NaturalOrderComparator(); private final IFileProvider.SortType mSortType; private final IFileProvider.SortOrder mSortOrder; @@ -45,7 +49,7 @@ public class FileComparator implements Comparator { public int compare(IFile lhs, IFile rhs) { if ((lhs.isDirectory() && rhs.isDirectory()) || (lhs.isFile() && rhs.isFile())) { // default is to compare by name (case insensitive) - int res = lhs.getSecondName().compareToIgnoreCase(rhs.getSecondName()); + int res = ourNaturalOrderComparator.compare(lhs.getSecondName(), rhs.getSecondName()); switch (mSortType) { case SortByName: