gui: clickable tree, better sorting

This commit is contained in:
Sergiusz Bazanski 2018-08-01 01:27:20 +01:00
parent c8cf0bbc05
commit e9e7004bf9

View File

@ -119,6 +119,21 @@ class StaticTreeItem : public LazyTreeItem
}
};
class IdStringItem : public StaticTreeItem
{
private:
IdString id_;
public:
IdStringItem(Context *ctx, IdString str, LazyTreeItem *parent, ElementType type) :
StaticTreeItem(QString(str.c_str(ctx)), parent, type), id_(str) {}
virtual IdString id() const override
{
return id_;
}
};
template <typename ElementT>
class ElementList : public LazyTreeItem
{
@ -156,14 +171,15 @@ class ElementList : public LazyTreeItem
int start = children_.size();
size_t end = std::min(start + count, (int)elements()->size());
for (int i = start; i < end; i++) {
QString name(getter_(ctx_, elements()->at(i)).c_str(ctx_));
auto idstring = getter_(ctx_, elements()->at(i));
QString name(idstring.c_str(ctx_));
// Remove X.../Y.../ prefix
QString prefix = QString("X%1/Y%2/").arg(x_).arg(y_);
if (name.startsWith(prefix))
name.remove(0, prefix.size());
auto item = new StaticTreeItem(name, this, child_type_);
auto item = new IdStringItem(ctx_, idstring, this, child_type_);
managed_.push_back(std::move(std::unique_ptr<StaticTreeItem>(item)));
}
}
@ -182,13 +198,40 @@ class ElementList : public LazyTreeItem
class IdStringList : public StaticTreeItem
{
private:
std::unordered_map<IdString, std::unique_ptr<StaticTreeItem>> managed_;
std::unordered_map<IdString, std::unique_ptr<IdStringItem>> managed_;
ElementType child_type_;
public:
IdStringList(QString name, LazyTreeItem *parent, ElementType type) :
StaticTreeItem(name, parent, ElementType::NONE), child_type_(type) {}
using StaticTreeItem::StaticTreeItem;
static std::vector<QString> alphaNumSplit(const QString &str)
{
std::vector<QString> res;
QString current_part;
bool number = true;
for (const auto c : str) {
if (current_part.size() == 0 && res.size() == 0) {
current_part.push_back(c);
number = c.isNumber();
continue;
}
if (number != c.isNumber()) {
number = c.isNumber();
res.push_back(current_part);
current_part.clear();
}
current_part.push_back(c);
}
res.push_back(current_part);
return res;
}
void updateElements(Context *ctx, std::vector<IdString> elements)
{
// for any elements that are not yet in managed_, created them.
@ -197,8 +240,8 @@ class IdStringList : public StaticTreeItem
element_set.insert(elem);
auto existing = managed_.find(elem);
if (existing == managed_.end()) {
auto item = new StaticTreeItem(elem.c_str(ctx), this, child_type_);
managed_.emplace(elem, std::unique_ptr<StaticTreeItem>(item));
auto item = new IdStringItem(ctx, elem, this, child_type_);
managed_.emplace(elem, std::unique_ptr<IdStringItem>(item));
}
}
@ -214,38 +257,45 @@ class IdStringList : public StaticTreeItem
// sort new children
qSort(children_.begin(), children_.end(), [&](const LazyTreeItem *a, const LazyTreeItem *b){
QString name_a = a->name();
QString name_b = b->name();
// Try to extract a common prefix from both strings.
QString common;
for (int i = 0; i < std::min(name_a.size(), name_b.size()); i++) {
const QChar c_a = name_a[i];
const QChar c_b = name_b[i];
if (c_a == c_b) {
common.push_back(c_a);
} else {
break;
}
}
// No common part? lexical sort.
if (common.size() == 0) {
return a->name() < b->name();
auto parts_a = alphaNumSplit(a->name());
auto parts_b = alphaNumSplit(b->name());
if (parts_a.size() != parts_b.size()) {
return parts_a.size() < parts_b.size();
}
// Get the non-common parts.
name_a.remove(0, common.size());
name_b.remove(0, common.size());
// And see if they're strings.
bool ok = true;
int num_a = name_a.toInt(&ok);
if (!ok) {
return a->name() < b->name();
for (int i = 0; i < parts_a.size(); i++) {
auto &part_a = parts_a.at(i);
auto &part_b = parts_b.at(i);
bool a_is_number, b_is_number;
int a_number = part_a.toInt(&a_is_number);
int b_number = part_b.toInt(&b_is_number);
if (a_is_number && b_is_number) {
if (a_number != b_number) {
return a_number < b_number;
} else {
continue;
}
}
if (a_is_number != b_is_number) {
return a_is_number;
}
// both strings
if (part_a == part_b) {
continue;
}
return part_a < part_b;
}
int num_b = name_b.toInt(&ok);
if (!ok) {
return a->name() < b->name();
}
return num_a < num_b;
// both equal
return true;
});
}
};