From 773587b3e42ef6e3ee4310e0f0473999439735fe Mon Sep 17 00:00:00 2001 From: Jim Evins Date: Wed, 6 Nov 2013 01:46:00 -0500 Subject: [PATCH] Sort templates in "Natural" order. --- libglabels/Db.cpp | 12 ++++ libglabels/StrUtil.cpp | 129 ++++++++++++++++++++++++++++++++++++++++ libglabels/StrUtil.h | 2 + libglabels/Template.cpp | 3 + libglabels/Template.h | 1 + 5 files changed, 147 insertions(+) diff --git a/libglabels/Db.cpp b/libglabels/Db.cpp index d15fd85..483d85e 100644 --- a/libglabels/Db.cpp +++ b/libglabels/Db.cpp @@ -24,12 +24,22 @@ #include #include "Config.h" +#include "StrUtil.h" #include "XmlPaperParser.h" #include "XmlCategoryParser.h" #include "XmlVendorParser.h" #include "XmlTemplateParser.h" +namespace +{ + bool partNameLessThan( const libglabels::Template *a, const libglabels::Template *b ) + { + return libglabels::StrUtil::comparePartNames( a->name(), b->name() ) < 0; + } +} + + namespace libglabels { @@ -573,6 +583,8 @@ namespace libglabels readTemplatesFromDir( systemTemplatesDir() ); // TODO: Read user directories + + qStableSort( mTemplates.begin(), mTemplates.end(), partNameLessThan ); } diff --git a/libglabels/StrUtil.cpp b/libglabels/StrUtil.cpp index 15d6671..7149c77 100644 --- a/libglabels/StrUtil.cpp +++ b/libglabels/StrUtil.cpp @@ -33,6 +33,8 @@ namespace "²⁰", "²¹", "²²", "²³", "²⁴", "²⁵", "²⁶", "²⁷", "²⁸", "²⁹", "³⁰", "³¹" }; } + + namespace libglabels { @@ -73,7 +75,134 @@ namespace libglabels } } + + QString spanDigits( const QString &s, int *i ) + { + QString chunk; + + for ( int j = *i; (j < s.size()) && s.at(j).isNumber(); j++ ) + { + chunk.append( s.at(j) ); + *i = j+1; /* only advance i, if character is used. */ + } + + return chunk; + } + + + QString spanNonDigits( const QString &s, int *i ) + { + QString chunk; + + for ( int j = *i; (j < s.size()) && !s.at(j).isNumber(); j++ ) + { + chunk.append( s.at(j) ); + *i = j+1; /* only advance i, if character is used. */ + } + + return chunk; + } + + + /** + * Compare part names + * @s1: string to compare with s2. + * @s2: string to compare with s1. + * + * Compare two strings representing part names or numbers. This function + * uses a natural sort order: + * + * - Ignores case. + * + * - Strings are divided into chunks (numeric and non-numeric) + * + * - Non-numeric chunks are compared character by character + * + * - Numerical chunks are compared numerically, so that "20" precedes "100". + * + * - Comparison of chunks is performed left to right until the first difference + * is encountered or all chunks evaluate as equal. + * + * Numeric chunks are converted to 64 bit unsigned integers for comparison, + * so the behaviour may be unpredictable for numeric chunks that exceed + * 18446744073709551615. + * + * Returns: 0 if the strings match, a negative value if s1 < s2, + * or a positive value if s1 > s2. + * + */ + int comparePartNames( const QString &s1, const QString &s2 ) + { + if ( s1 == s2 ) return 0; + if ( s1 == "" ) return -1; + if ( s2 == "" ) return 1; + + QString folded_s1 = s1.toUpper(); + QString folded_s2 = s2.toUpper(); + + int i1 = 0; + int i2 = 0; + int result = 0; + bool done = false; + + while ( (result == 0) && !done ) + { + QString chunk1, chunk2; + bool isnum1, isnum2; + + if ( folded_s1.at( i1 ).isNumber() ) + { + chunk1 = spanDigits( folded_s1, &i1 ); + isnum1 = true; + } + else + { + chunk1 = spanNonDigits( folded_s1, &i1 ); + isnum1 = false; + } + + if ( folded_s2.at( i2 ).isNumber() ) + { + chunk2 = spanDigits( folded_s2, &i2 ); + isnum2 = true; + } + else + { + chunk2 = spanNonDigits( folded_s2, &i2 ); + isnum2 = false; + } + + + if ( ( chunk1 == "" ) && ( chunk2 == "" ) ) + { + /* Case 1: Both are empty. */ + done = true; + } + else if ( isnum1 && isnum2 ) + { + /* Case 2: They both contain numbers */ + qlonglong n1 = chunk1.toLongLong(); + qlonglong n2 = chunk2.toLongLong(); + + if ( n1 < n2 ) result = -1; + else if ( n1 > n2 ) result = 1; + } + else + { + /* Case 3: One or both do not contain numbers */ + if ( chunk1 < chunk2 ) result = -1; + else if( chunk1 > chunk2 ) result = 1; + } + + } + + return result; + } + + + } + } diff --git a/libglabels/StrUtil.h b/libglabels/StrUtil.h index f9917c1..e81fdcb 100644 --- a/libglabels/StrUtil.h +++ b/libglabels/StrUtil.h @@ -32,6 +32,8 @@ namespace libglabels QString &formatFraction( double x ); + int comparePartNames( const QString &s1, const QString &s2 ); + } } diff --git a/libglabels/Template.cpp b/libglabels/Template.cpp index 3562efa..c2ed15f 100644 --- a/libglabels/Template.cpp +++ b/libglabels/Template.cpp @@ -73,6 +73,9 @@ namespace libglabels tmplate->mPart = part; tmplate->mEquivPart = equivPart; + tmplate->mName = ""; + tmplate->mName.append( brand ).append( " " ).append( part ); + return tmplate; } else diff --git a/libglabels/Template.h b/libglabels/Template.h index 910bd67..8d90cfa 100644 --- a/libglabels/Template.h +++ b/libglabels/Template.h @@ -106,6 +106,7 @@ namespace libglabels bool hasCategory( const QString &categoryId ) const; bool isSimilarTo( const Template &other ) const; + private: QString mBrand; QString mPart;