Browse Source

Fix natural sorting order in EditorFileDialog, FileDialog and EditorFileSystemDirectory

Make EditorFileDialog, FileDialog and EditorFileSystemDirectory alphanumerical sorting more natural

Added a new method 'naturalnocasecmp_to' and comparator 'NaturalNoCaseComparator' to String.

Fixes #8712.
Damian Day 8 years ago
parent
commit
f2564ca97f
5 changed files with 67 additions and 9 deletions
  1. 52 3
      core/ustring.cpp
  2. 9 0
      core/ustring.h
  3. 2 2
      editor/editor_file_dialog.cpp
  4. 2 2
      editor/editor_file_system.cpp
  5. 2 2
      scene/gui/file_dialog.cpp

+ 52 - 3
core/ustring.cpp

@@ -53,6 +53,8 @@
 #define MAX_DIGITS 6
 #define UPPERCASE(m_c) (((m_c) >= 'a' && (m_c) <= 'z') ? ((m_c) - ('a' - 'A')) : (m_c))
 #define LOWERCASE(m_c) (((m_c) >= 'A' && (m_c) <= 'Z') ? ((m_c) + ('a' - 'A')) : (m_c))
+#define IS_DIGIT(m_d) ((m_d) >= '0' && (m_d) <= '9')
+#define IS_HEX_DIGIT(m_d) (((m_d) >= '0' && (m_d) <= '9') || ((m_d) >= 'a' && (m_d) <= 'f') || ((m_d) >= 'A' && (m_d) <= 'F'))
 
 /** STRING **/
 
@@ -481,6 +483,56 @@ signed char String::casecmp_to(const String &p_str) const {
 	return 0; //should never reach anyway
 }
 
+signed char String::naturalnocasecmp_to(const String &p_str) const {
+
+	const CharType *this_str = c_str();
+	const CharType *that_str = p_str.c_str();
+
+	if (this_str && that_str) {
+		while (*this_str) {
+
+			if (!*that_str)
+				return 1;
+			else if (IS_DIGIT(*this_str)) {
+
+				int64_t this_int, that_int;
+
+				if (!IS_DIGIT(*that_str))
+					return -1;
+
+				/* Compare the numbers */
+				this_int = to_int(this_str);
+				that_int = to_int(that_str);
+
+				if (this_int < that_int)
+					return -1;
+				else if (this_int > that_int)
+					return 1;
+
+				/* Skip */
+				while (IS_DIGIT(*this_str))
+					this_str++;
+				while (IS_DIGIT(*that_str))
+					that_str++;
+			} else if (IS_DIGIT(*that_str))
+				return 1;
+			else {
+				if (_find_upper(*this_str) < _find_upper(*that_str)) //more than
+					return -1;
+				else if (_find_upper(*this_str) > _find_upper(*that_str)) //less than
+					return 1;
+
+				this_str++;
+				that_str++;
+			}
+		}
+		if (*that_str)
+			return -1;
+	}
+
+	return 0;
+}
+
 void String::erase(int p_pos, int p_chars) {
 
 	*this = left(p_pos) + substr(p_pos + p_chars, length() - ((p_pos + p_chars)));
@@ -1698,9 +1750,6 @@ bool String::is_numeric() const {
 	return true; // TODO: Use the parser below for this instead
 };
 
-#define IS_DIGIT(m_d) ((m_d) >= '0' && (m_d) <= '9')
-#define IS_HEX_DIGIT(m_d) (((m_d) >= '0' && (m_d) <= '9') || ((m_d) >= 'a' && (m_d) <= 'f') || ((m_d) >= 'A' && (m_d) <= 'F'))
-
 template <class C>
 static double built_in_strtod(const C *string, /* A decimal ASCII floating-point number,
 				 * optionally preceded by white space. Must

+ 9 - 0
core/ustring.h

@@ -98,6 +98,7 @@ public:
 
 	signed char casecmp_to(const String &p_str) const;
 	signed char nocasecmp_to(const String &p_str) const;
+	signed char naturalnocasecmp_to(const String &p_str) const;
 
 	const CharType *c_str() const;
 	/* standard size stuff */
@@ -256,6 +257,14 @@ struct NoCaseComparator {
 	}
 };
 
+struct NaturalNoCaseComparator {
+
+	bool operator()(const String &p_a, const String &p_b) const {
+
+		return p_a.naturalnocasecmp_to(p_b) < 0;
+	}
+};
+
 /* end of namespace */
 
 //tool translate

+ 2 - 2
editor/editor_file_dialog.cpp

@@ -552,8 +552,8 @@ void EditorFileDialog::update_file_list() {
 		dirs.push_back("..");
 	}
 
-	dirs.sort_custom<NoCaseComparator>();
-	files.sort_custom<NoCaseComparator>();
+	dirs.sort_custom<NaturalNoCaseComparator>();
+	files.sort_custom<NaturalNoCaseComparator>();
 
 	while (!dirs.empty()) {
 		const String &dir_name = dirs.front()->get();

+ 2 - 2
editor/editor_file_system.cpp

@@ -522,8 +522,8 @@ void EditorFileSystem::_scan_new_dir(EditorFileSystemDirectory *p_dir, DirAccess
 
 	da->list_dir_end();
 
-	dirs.sort();
-	files.sort();
+	dirs.sort_custom<NaturalNoCaseComparator>();
+	files.sort_custom<NaturalNoCaseComparator>();
 
 	int total = dirs.size() + files.size();
 	int idx = 0;

+ 2 - 2
scene/gui/file_dialog.cpp

@@ -336,8 +336,8 @@ void FileDialog::update_file_list() {
 		dirs.push_back("..");
 	}
 
-	dirs.sort_custom<NoCaseComparator>();
-	files.sort_custom<NoCaseComparator>();
+	dirs.sort_custom<NaturalNoCaseComparator>();
+	files.sort_custom<NaturalNoCaseComparator>();
 
 	while (!dirs.empty()) {
 		String &dir_name = dirs.front()->get();