Project

General

Profile

Feature #4380 » 0001-Add-support-for-multiple-column-sort-for-WStandardIt.patch

Trigve Siver, 11/10/2016 12:01 AM

View differences:

src/Wt/WSortFilterProxyModel
*
* \sa sort()
*/
int sortColumn() const { return sortKeyColumn_; }
int sortColumn() const { return sortKeyColumns_.empty() ? -1 : sortKeyColumns_.front(); }
/*! \brief Returns the all sort columns.
*
* When sort() has not been called, the model is unsorted, and this method returns empty container.
*
* \sa sort()
*/
std::vector<int> const &sortColumnsAll() const { return sortKeyColumns_; }
/*! \brief Returns the current sort order.
*
* \sa sort()
*/
SortOrder sortOrder() const { return sortOrder_; }
SortOrder sortOrder() const { return sortOrders_.empty() ? SortOrder::AscendingOrder : sortOrders_.front(); }
/*! \brief Returns the sort order for all sorted columns.
*
* \sa sort()
*/
std::vector<SortOrder> const & sortOrdersAll() const { return sortOrders_; }
/*! \brief Configure the proxy to dynamically track changes in the
* source model.
......
virtual void sort(int column, SortOrder order = AscendingOrder);
virtual void sort(std::vector<int> const &columns, std::vector<SortOrder> const &orders);
protected:
/*! \brief Returns whether a source row is accepted by the filter.
*
......
WRegExp *regex_;
int filterKeyColumn_, filterRole_;
int sortKeyColumn_, sortRole_;
SortOrder sortOrder_;
int sortRole_;
std::vector<int> sortKeyColumns_;
std::vector<SortOrder> sortOrders_;
bool dynamic_, inserting_;
std::vector<Wt::Signals::connection> modelConnections_;
src/Wt/WSortFilterProxyModel.C
bool WSortFilterProxyModel::Compare::operator()(int sourceRow1,
int sourceRow2) const
{
if (model->sortOrder_ == AscendingOrder)
return lessThan(sourceRow1, sourceRow2);
else
return lessThan(sourceRow2, sourceRow1);
return lessThan(sourceRow1, sourceRow2);
}
bool WSortFilterProxyModel::Compare::lessThan(int sourceRow1, int sourceRow2)
const
{
if (model->sortKeyColumn_ == -1)
return sourceRow1 < sourceRow2;
bool result;
WModelIndex lhs
= model->sourceModel()->index(sourceRow1, model->sortKeyColumn_,
if (model->sortKeyColumns_.empty())
result = sourceRow1 < sourceRow2;
else
{
// Process columns by one
for(auto i = 0U; i < model->sortKeyColumns_.size(); ++i)
{
auto const column = model->sortKeyColumns_[i];
auto const order = model->sortOrders_[i];
WModelIndex lhs
= model->sourceModel()->index(sourceRow1, column,
item->sourceIndex_);
WModelIndex rhs
= model->sourceModel()->index(sourceRow2, model->sortKeyColumn_,
WModelIndex rhs
= model->sourceModel()->index(sourceRow2, column,
item->sourceIndex_);
return model->lessThan(lhs, rhs);
// Save result, if we're at the last column
result = (order == SortOrder::AscendingOrder ? model->lessThan(lhs, rhs) : model->lessThan(rhs, lhs));
// Are the same, go to the next column comparison
if(!result && !(order == SortOrder::AscendingOrder ? model->lessThan(rhs, lhs) : model->lessThan(lhs, rhs)))
continue;
// Otherwise, we can stop here
else
break;
}
}
return result;
}
#endif // WT_TARGET_JAVA
int WSortFilterProxyModel::Compare::compare(int sourceRow1, int sourceRow2)
const
{
int factor = (model->sortOrder_ == AscendingOrder) ? 1 : -1;
int result;
if (model->sortKeyColumn_ == -1)
return factor * (sourceRow1 - sourceRow2);
if(model->sortKeyColumns_.empty())
result = (sourceRow1 - sourceRow2);
else
{
// Process columns by one
for(auto i = 0U; i < model->sortKeyColumns_.size(); ++i)
{
auto const column = model->sortKeyColumns_[i];
auto const order = model->sortOrders_[i];
int factor = (order == AscendingOrder) ? 1 : -1;
WModelIndex lhs
= model->sourceModel()->index(sourceRow1, model->sortKeyColumn_,
WModelIndex lhs
= model->sourceModel()->index(sourceRow1, column,
item->sourceIndex_);
WModelIndex rhs
= model->sourceModel()->index(sourceRow2, model->sortKeyColumn_,
WModelIndex rhs
= model->sourceModel()->index(sourceRow2, column,
item->sourceIndex_);
return factor * model->compare(lhs, rhs);
result = factor * model->compare(lhs, rhs);
// Aren't same, we're done
if(result != 0)
break;
}
}
return result;
}
#endif // DOXYGEN_ONLY
......
regex_(0),
filterKeyColumn_(0),
filterRole_(DisplayRole),
sortKeyColumn_(-1),
sortRole_(DisplayRole),
sortOrder_(AscendingOrder),
dynamic_(false),
inserting_(false),
mappedRootItem_(0)
......
void WSortFilterProxyModel::sort(int column, SortOrder order)
{
sortKeyColumn_ = column;
sortOrder_ = order;
sortKeyColumns_.clear();
sortOrders_.clear();
sortKeyColumns_.push_back(column);
sortOrders_.push_back(order);
invalidate();
}
void WSortFilterProxyModel::sort(std::vector<int> const &columns, std::vector<SortOrder> const &orders)
{
sortKeyColumns_ = columns;
sortOrders_ = orders;
}
void WSortFilterProxyModel::invalidate()
{
if (sourceModel()) {
......
/*
* Sort...
*/
if (sortKeyColumn_ != -1) {
if (!sortKeyColumns_.empty()) {
Utils::stable_sort(item->proxyRowMap_, Compare(this, item));
rebuildSourceRowMap(item);
......
= dynamic_ && (filterKeyColumn_ >= topLeft.column()
&& filterKeyColumn_ <= bottomRight.column());
bool resort
= dynamic_ && (sortKeyColumn_ >= topLeft.column()
&& sortKeyColumn_ <= bottomRight.column());
bool resort = dynamic_;
if(dynamic_)
{
for(auto const &column : sortKeyColumns_)
{
resort = (column >= topLeft.column()
&& column <= bottomRight.column());
// At least 1 column in range, no need to continue
if(resort)
break;
}
}
WModelIndex parent = mapFromSource(topLeft.parent());
// distinguish between invalid parent being root item or being filtered out
src/Wt/WStandardItem
*/
virtual void sortChildren(int column, SortOrder order);
/*! \brief Sorts the children according to a given column and sort order.
*/
virtual void sortChildren(std::vector<int> const &columns, std::vector<SortOrder> const &orders);
protected:
/*! \brief Set the model for this WStandardItem and its children.
*
......
void adoptChild(int row, int column, WStandardItem *item);
void orphanChild(WStandardItem *item);
void recursiveSortChildren(int column, SortOrder order);
void recursiveSortChildren(std::vector<int> const &columns, std::vector<SortOrder> const &orders);
void renumberColumns(int column);
void renumberRows(int row);
src/Wt/WStandardItem.C
SortOrder order;
};
// Item comparer for multiple columns
struct WStandardItemCompareMulti W_JAVA_COMPARATOR(int)
{
WStandardItemCompareMulti(WStandardItem *anItem, std::vector<int> const &aColumns, std::vector<SortOrder> const &anOrders)
: item(anItem),
columns(aColumns),
orders(anOrders)
{ }
#ifndef WT_TARGET_JAVA
bool operator()(int r1, int r2) const {
return compare(r1, r2);
}
bool compare(int r1, int r2) const {
// Always should have valid value at return
bool result;
// Process columns by one
for(auto i = 0U; i < columns.size(); ++i)
{
auto const column = columns[i];
auto const order = orders[i];
WStandardItem *item1 = item->child(r1, column);
WStandardItem *item2 = item->child(r2, column);
// First item valid
if(item1) {
// Second also valid
if(item2) {
// Save result, if we're at the last column
result = (order == SortOrder::AscendingOrder ? *item1 < *item2 : *item2 < *item1);
// Are the same, go to the next column comparison
if(!result && !(order == SortOrder::AscendingOrder ? *item2 < *item1 : *item1 < *item2))
continue;
// Otherwise, we can stop here
else
break;
}
// Second not valid
else {
result = (order == SortOrder::AscendingOrder ? UNSPECIFIED_RESULT == -1 : UNSPECIFIED_RESULT != -1);
break;
}
}
// First not valid
else {
// Second valid
if(item2) {
result = (order == SortOrder::AscendingOrder ? UNSPECIFIED_RESULT != -1 : UNSPECIFIED_RESULT == -1);
break;
}
// Second also not valid, move to the next column
else {
result = (order == SortOrder::AscendingOrder ? false : true);
continue;
}
}
}
return result;
}
#else
int compare(int r1, int r2) const {
// Always should have valid value at return
int result;
// Process columns by one
for(auto i = 0U; i < columns.size(); ++i)
{
auto const column = columns[i];
auto const order = orders[i];
WStandardItem *item1 = item->child(r1, column);
WStandardItem *item2 = item->child(r2, column);
// First item valid
if(item1)
{
// Second also valid
if(item2)
{
// Save result, if we're at the last column
result = (order == SortOrder::AscendingOrder ? item1->compare(*item2) : item2->compare(*item1));
// Are the same, go to the next column comparison
if(result == 0)
continue;
// Otherwise, we can stop here
else
break;
}
// Second not valid
else
{
result = (order == SortOrder::AscendingOrder ? -UNSPECIFIED_RESULT : UNSPECIFIED_RESULT);
break;
}
}
// First not valid
else
{
// Second valid
if(item2)
{
result = (order == SortOrder::AscendingOrder ? UNSPECIFIED_RESULT : -UNSPECIFIED_RESULT);
break;
}
// Second also not valid, move to the next column
else
{
result = 0;
continue;
}
}
}
return result;
}
#endif // WT_TARGET_JAVA
WStandardItem *item;
std::vector<int> const &columns;
std::vector<SortOrder> const &orders;
};
}
namespace Wt {
......
model_->layoutChanged().emit();
}
void WStandardItem::sortChildren(std::vector<int> const &columns, std::vector<SortOrder> const &orders)
{
if(model_)
model_->layoutAboutToBeChanged().emit();
recursiveSortChildren(columns, orders);
if(model_)
model_->layoutChanged().emit();
}
bool WStandardItem::operator< (const WStandardItem& other) const
{
return compare(other) < 0;
......
}
}
void WStandardItem::recursiveSortChildren(std::vector<int> const &columns, std::vector<SortOrder> const &orders)
{
bool all_columns_valid = true;
for(auto const col : columns)
{
if((all_columns_valid = (col < columnCount())) == false)
break;
}
if (all_columns_valid) {
#ifndef WT_TARGET_JAVA
std::vector<int> permutation(rowCount());
for (unsigned i = 0; i < permutation.size(); ++i)
permutation[i] = i;
#else
std::vector<int> permutation;
for (unsigned i = 0; i < rowCount(); ++i)
permutation.push_back(i);
#endif // WT_TARGET_JAVA
Utils::stable_sort(permutation, WStandardItemCompareMulti(this, columns, orders));
#ifndef WT_TARGET_JAVA
Column temp(rowCount());
#endif
for (int c = 0; c < columnCount(); ++c) {
#ifdef WT_TARGET_JAVA
Column temp;
#endif // WT_TARGET_JAVA
Column& cc = (*columns_)[c];
for (int r = 0; r < rowCount(); ++r) {
#ifndef WT_TARGET_JAVA
temp[r] = cc[permutation[r]];
#else
temp.push_back(cc[permutation[r]]);
#endif // WT_TARGET_JAVA
if (temp[r])
temp[r]->row_ = r;
}
(*columns_)[c] = temp;
}
}
for (int c = 0; c < columnCount(); ++c)
for (int r = 0; r < rowCount(); ++r) {
WStandardItem *ch = child(r, c);
if (ch)
ch->recursiveSortChildren(columns, orders);
}
}
void WStandardItem::signalModelDataChange()
{
if (model_) {
src/Wt/WStandardItemModel
virtual void sort(int column, SortOrder order = AscendingOrder);
virtual void sort(std::vector<int> const &columns, std::vector<SortOrder> const &orders);
/*! \brief %Signal emitted when an item is changed.
*
* This signal is emitted whenever data for an item has changed. The
src/Wt/WStandardItemModel.C
invisibleRootItem_->sortChildren(column, order);
}
void WStandardItemModel::sort(std::vector<int> const &columns, std::vector<SortOrder> const &orders)
{
invisibleRootItem_->sortChildren(columns, orders);
}
}
#endif // DOXYGEN_ONLY
(2-2/2)