Sort templates in "Natural" order.

This commit is contained in:
Jim Evins
2013-11-06 01:46:00 -05:00
parent ba83204445
commit 773587b3e4
5 changed files with 147 additions and 0 deletions
+12
View File
@@ -24,12 +24,22 @@
#include <iostream> #include <iostream>
#include "Config.h" #include "Config.h"
#include "StrUtil.h"
#include "XmlPaperParser.h" #include "XmlPaperParser.h"
#include "XmlCategoryParser.h" #include "XmlCategoryParser.h"
#include "XmlVendorParser.h" #include "XmlVendorParser.h"
#include "XmlTemplateParser.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 namespace libglabels
{ {
@@ -573,6 +583,8 @@ namespace libglabels
readTemplatesFromDir( systemTemplatesDir() ); readTemplatesFromDir( systemTemplatesDir() );
// TODO: Read user directories // TODO: Read user directories
qStableSort( mTemplates.begin(), mTemplates.end(), partNameLessThan );
} }
+129
View File
@@ -33,6 +33,8 @@ namespace
"²⁰", "²¹", "²²", "²³", "²⁴", "²⁵", "²⁶", "²⁷", "²⁸", "²⁹", "²⁰", "²¹", "²²", "²³", "²⁴", "²⁵", "²⁶", "²⁷", "²⁸", "²⁹",
"³⁰", "³¹" }; "³⁰", "³¹" };
} }
namespace libglabels 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;
}
} }
} }
+2
View File
@@ -32,6 +32,8 @@ namespace libglabels
QString &formatFraction( double x ); QString &formatFraction( double x );
int comparePartNames( const QString &s1, const QString &s2 );
} }
} }
+3
View File
@@ -73,6 +73,9 @@ namespace libglabels
tmplate->mPart = part; tmplate->mPart = part;
tmplate->mEquivPart = equivPart; tmplate->mEquivPart = equivPart;
tmplate->mName = "";
tmplate->mName.append( brand ).append( " " ).append( part );
return tmplate; return tmplate;
} }
else else
+1
View File
@@ -106,6 +106,7 @@ namespace libglabels
bool hasCategory( const QString &categoryId ) const; bool hasCategory( const QString &categoryId ) const;
bool isSimilarTo( const Template &other ) const; bool isSimilarTo( const Template &other ) const;
private: private:
QString mBrand; QString mBrand;
QString mPart; QString mPart;