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
195 195
   *
196 196
   * \sa sort()
197 197
   */
198
  int sortColumn() const { return sortKeyColumn_; }
198
  int sortColumn() const { return sortKeyColumns_.empty() ? -1 : sortKeyColumns_.front(); }
199

  
200
  /*! \brief Returns the all sort columns.
201
   *
202
   * When sort() has not been called, the model is unsorted, and this method returns empty container.
203
   *
204
   * \sa sort()
205
   */
206
  std::vector<int> const &sortColumnsAll() const { return sortKeyColumns_; }
199 207

  
200 208
  /*! \brief Returns the current sort order.
201 209
   *
202 210
   * \sa sort()
203 211
   */
204
  SortOrder sortOrder() const { return sortOrder_; }
212
  SortOrder sortOrder() const { return sortOrders_.empty() ? SortOrder::AscendingOrder : sortOrders_.front(); }
213

  
214
  /*! \brief Returns the sort order for all sorted columns.
215
   *
216
   * \sa sort()
217
   */
218
  std::vector<SortOrder> const & sortOrdersAll() const { return sortOrders_; }
205 219

  
206 220
  /*! \brief Configure the proxy to dynamically track changes in the
207 221
   *         source model.
......
275 289

  
276 290
  virtual void sort(int column, SortOrder order = AscendingOrder);
277 291

  
292
  virtual void sort(std::vector<int> const &columns, std::vector<SortOrder> const &orders);
293

  
278 294
protected:
279 295
  /*! \brief Returns whether a source row is accepted by the filter.
280 296
   *
......
347 363
  WRegExp *regex_;
348 364

  
349 365
  int       filterKeyColumn_, filterRole_;
350
  int       sortKeyColumn_, sortRole_;
351
  SortOrder sortOrder_;
366
  int       sortRole_;
367
  std::vector<int> sortKeyColumns_;
368
  std::vector<SortOrder> sortOrders_;
352 369
  bool      dynamic_, inserting_;
353 370

  
354 371
  std::vector<Wt::Signals::connection> modelConnections_;
src/Wt/WSortFilterProxyModel.C
16 16
bool WSortFilterProxyModel::Compare::operator()(int sourceRow1,
17 17
						int sourceRow2) const
18 18
{
19
  if (model->sortOrder_ == AscendingOrder)
20
    return lessThan(sourceRow1, sourceRow2);
21
  else
22
    return lessThan(sourceRow2, sourceRow1);
19
  return lessThan(sourceRow1, sourceRow2);
23 20
}
24 21

  
25 22
bool WSortFilterProxyModel::Compare::lessThan(int sourceRow1, int sourceRow2)
26 23
  const
27 24
{
28
  if (model->sortKeyColumn_ == -1)
29
    return sourceRow1 < sourceRow2;
25
  bool result;
30 26

  
31
  WModelIndex lhs
32
    = model->sourceModel()->index(sourceRow1, model->sortKeyColumn_,
27
  if (model->sortKeyColumns_.empty())
28
	  result = sourceRow1 < sourceRow2;
29
  else
30
  {
31
	  // Process columns by one
32
	  for(auto i = 0U; i < model->sortKeyColumns_.size(); ++i)
33
	  {
34
		  auto const column = model->sortKeyColumns_[i];
35
		  auto const order = model->sortOrders_[i];
36

  
37
		  WModelIndex lhs
38
			  = model->sourceModel()->index(sourceRow1, column,
33 39
				  item->sourceIndex_);
34 40

  
35
  WModelIndex rhs
36
    = model->sourceModel()->index(sourceRow2, model->sortKeyColumn_,
41
		  WModelIndex rhs
42
			  = model->sourceModel()->index(sourceRow2, column,
37 43
				  item->sourceIndex_);
38 44

  
39
  return model->lessThan(lhs, rhs);
45

  
46
		  // Save result, if we're at the last column
47
		  result = (order == SortOrder::AscendingOrder ? model->lessThan(lhs, rhs) : model->lessThan(rhs, lhs));
48
		  // Are the same, go to the next column comparison
49
		  if(!result && !(order == SortOrder::AscendingOrder ? model->lessThan(rhs, lhs) : model->lessThan(lhs, rhs)))
50
			  continue;
51
		  // Otherwise, we can stop here
52
		  else
53
			  break;
54
	  }
55
  }
56
  
57
  return result;
40 58
}
41 59
#endif // WT_TARGET_JAVA
42 60

  
43 61
int WSortFilterProxyModel::Compare::compare(int sourceRow1, int sourceRow2)
44 62
  const
45 63
{
46
  int factor = (model->sortOrder_ == AscendingOrder) ? 1 : -1;
64
  int result;
47 65

  
48
  if (model->sortKeyColumn_ == -1)
49
    return factor * (sourceRow1 - sourceRow2);
66
  if(model->sortKeyColumns_.empty())
67
    result = (sourceRow1 - sourceRow2);
68
  else
69
  {
70
	  // Process columns by one
71
	  for(auto i = 0U; i < model->sortKeyColumns_.size(); ++i)
72
	  {
73
		  auto const column = model->sortKeyColumns_[i];
74
		  auto const order = model->sortOrders_[i];
75

  
76
		  int factor = (order == AscendingOrder) ? 1 : -1;
50 77

  
51
  WModelIndex lhs
52
    = model->sourceModel()->index(sourceRow1, model->sortKeyColumn_,
78
		  WModelIndex lhs
79
			  = model->sourceModel()->index(sourceRow1, column,
53 80
				  item->sourceIndex_);
54 81

  
55
  WModelIndex rhs
56
    = model->sourceModel()->index(sourceRow2, model->sortKeyColumn_,
82
		  WModelIndex rhs
83
			  = model->sourceModel()->index(sourceRow2, column,
57 84
				  item->sourceIndex_);
58 85

  
59
  return factor * model->compare(lhs, rhs);
86
		  result = factor * model->compare(lhs, rhs);
87
		  // Aren't same, we're done
88
		  if(result != 0)
89
			  break;
90
	  }
91
  }
92

  
93
  return result;
60 94
}
61 95

  
62 96
#endif // DOXYGEN_ONLY
......
69 103
    regex_(0),
70 104
    filterKeyColumn_(0),
71 105
    filterRole_(DisplayRole),
72
    sortKeyColumn_(-1),
73 106
    sortRole_(DisplayRole),
74
    sortOrder_(AscendingOrder),
75 107
    dynamic_(false),
76 108
    inserting_(false),
77 109
    mappedRootItem_(0)
......
179 211

  
180 212
void WSortFilterProxyModel::sort(int column, SortOrder order)
181 213
{
182
  sortKeyColumn_ = column;
183
  sortOrder_ = order;
214
  sortKeyColumns_.clear();
215
  sortOrders_.clear();
216

  
217
  sortKeyColumns_.push_back(column);
218
  sortOrders_.push_back(order);
184 219

  
185 220
  invalidate();
186 221
}
187 222

  
223
void WSortFilterProxyModel::sort(std::vector<int> const &columns, std::vector<SortOrder> const &orders)
224
{
225
	sortKeyColumns_ = columns;
226
	sortOrders_ = orders;
227
}
228

  
188 229
void WSortFilterProxyModel::invalidate()
189 230
{
190 231
  if (sourceModel()) {
......
322 363
  /*
323 364
   * Sort...
324 365
   */
325
  if (sortKeyColumn_ != -1) {
366
  if (!sortKeyColumns_.empty()) {
326 367
    Utils::stable_sort(item->proxyRowMap_, Compare(this, item));
327 368

  
328 369
    rebuildSourceRowMap(item);
......
565 606
    = dynamic_ && (filterKeyColumn_ >= topLeft.column() 
566 607
		   && filterKeyColumn_ <= bottomRight.column());
567 608

  
568
  bool resort
569
    = dynamic_ && (sortKeyColumn_ >= topLeft.column() 
570
		   && sortKeyColumn_ <= bottomRight.column());
609
  bool resort = dynamic_;
610
  if(dynamic_)
611
  {
612
	  for(auto const &column : sortKeyColumns_)
613
	  {
614
		  resort = (column >= topLeft.column()
615
			  && column <= bottomRight.column());
616
		  // At least 1 column in range, no need to continue
617
		  if(resort)
618
			  break;
619
	  }
620
  }
571 621

  
572 622
  WModelIndex parent = mapFromSource(topLeft.parent());
573 623
  // distinguish between invalid parent being root item or being filtered out
src/Wt/WStandardItem
651 651
   */
652 652
  virtual void sortChildren(int column, SortOrder order);
653 653

  
654
  /*! \brief Sorts the children according to a given column and sort order.
655
  */
656
  virtual void sortChildren(std::vector<int> const &columns, std::vector<SortOrder> const &orders);
657

  
654 658
protected:
655 659
  /*! \brief Set the model for this WStandardItem and its children.
656 660
   *
......
692 696
  void adoptChild(int row, int column, WStandardItem *item);
693 697
  void orphanChild(WStandardItem *item);
694 698
  void recursiveSortChildren(int column, SortOrder order);
699
  void recursiveSortChildren(std::vector<int> const &columns, std::vector<SortOrder> const &orders);
695 700
  void renumberColumns(int column);
696 701
  void renumberRows(int row);
697 702

  
src/Wt/WStandardItem.C
78 78
    SortOrder      order;
79 79
  };
80 80

  
81
  // Item comparer for multiple columns
82
  struct WStandardItemCompareMulti W_JAVA_COMPARATOR(int)
83
  {
84
	  WStandardItemCompareMulti(WStandardItem *anItem, std::vector<int> const &aColumns, std::vector<SortOrder> const &anOrders)
85
		  : item(anItem),
86
		  columns(aColumns),
87
		  orders(anOrders)
88
	  { }
89

  
90
#ifndef WT_TARGET_JAVA
91
	  bool operator()(int r1, int r2) const {
92
		  return compare(r1, r2);
93
	  }
94

  
95
	  bool compare(int r1, int r2) const {
96
		  // Always should have valid value at return
97
		  bool result;
98
		  // Process columns by one
99
		  for(auto i = 0U; i < columns.size(); ++i)
100
		  {
101
			  auto const column = columns[i];
102
			  auto const order = orders[i];
103

  
104
			  WStandardItem *item1 = item->child(r1, column);
105
			  WStandardItem *item2 = item->child(r2, column);
106

  
107
			  // First item valid
108
			  if(item1) {
109
				  // Second also valid
110
				  if(item2) {
111
					  // Save result, if we're at the last column
112
					  result = (order == SortOrder::AscendingOrder ? *item1 < *item2 : *item2 < *item1);
113
					  // Are the same, go to the next column comparison
114
					  if(!result && !(order == SortOrder::AscendingOrder ? *item2 < *item1 : *item1 < *item2))
115
						  continue;
116
					  // Otherwise, we can stop here
117
					  else
118
						break;
119
				  }
120
				  // Second not valid
121
				  else {
122
					  result = (order == SortOrder::AscendingOrder ? UNSPECIFIED_RESULT == -1 : UNSPECIFIED_RESULT != -1);
123
					  break;
124
				  }
125
			  }
126
			  // First not valid
127
			  else {
128
				  // Second valid
129
				  if(item2) {
130
					  result = (order == SortOrder::AscendingOrder ? UNSPECIFIED_RESULT != -1 : UNSPECIFIED_RESULT == -1);
131
					  break;
132
				  }
133
				  // Second also not valid, move to the next column
134
				  else {
135
					  result = (order == SortOrder::AscendingOrder ? false : true);
136
					  continue;
137
				  }
138
			  }
139
		  }
140

  
141
		  return result;
142
	  }
143
#else
144
	  int compare(int r1, int r2) const {
145
		  // Always should have valid value at return
146
		  int result;
147
		  // Process columns by one
148
		  for(auto i = 0U; i < columns.size(); ++i)
149
		  {
150
			  auto const column = columns[i];
151
			  auto const order = orders[i];
152

  
153
			  WStandardItem *item1 = item->child(r1, column);
154
			  WStandardItem *item2 = item->child(r2, column);
155

  
156
			  // First item valid
157
			  if(item1)
158
			  {
159
				  // Second also valid
160
				  if(item2)
161
				  {
162
					  // Save result, if we're at the last column
163
					  result = (order == SortOrder::AscendingOrder ? item1->compare(*item2) : item2->compare(*item1));
164
					  // Are the same, go to the next column comparison
165
					  if(result == 0)
166
						  continue;
167
					  // Otherwise, we can stop here
168
					  else
169
						  break;
170
  }
171
				  // Second not valid
172
				  else
173
				  {
174
					  result = (order == SortOrder::AscendingOrder ? -UNSPECIFIED_RESULT : UNSPECIFIED_RESULT);
175
					  break;
176
				  }
177
			  }
178
			  // First not valid
179
			  else
180
			  {
181
				  // Second valid
182
				  if(item2)
183
				  {
184
					  result = (order == SortOrder::AscendingOrder ? UNSPECIFIED_RESULT : -UNSPECIFIED_RESULT);
185
					  break;
186
				  }
187
				  // Second also not valid, move to the next column
188
				  else
189
				  {
190
					  result = 0;
191
					  continue;
192
				  }
193
			  }
194
		  }
195

  
196
		  return result;
197
	  }
198
#endif // WT_TARGET_JAVA
199

  
200
	  WStandardItem *item;
201
	  std::vector<int> const &columns;
202
	  std::vector<SortOrder> const &orders;
203
  };
204

  
81 205
}
82 206

  
83 207
namespace Wt {
......
820 944
    model_->layoutChanged().emit();
821 945
}
822 946

  
947
void WStandardItem::sortChildren(std::vector<int> const &columns, std::vector<SortOrder> const &orders)
948
{
949
	if(model_)
950
		model_->layoutAboutToBeChanged().emit();
951

  
952
	recursiveSortChildren(columns, orders);
953

  
954
	if(model_)
955
		model_->layoutChanged().emit();
956
}
957

  
823 958
bool WStandardItem::operator< (const WStandardItem& other) const
824 959
{
825 960
  return compare(other) < 0;
......
881 1016
    }
882 1017
}
883 1018

  
1019
void WStandardItem::recursiveSortChildren(std::vector<int> const &columns, std::vector<SortOrder> const &orders)
1020
{
1021
	bool all_columns_valid = true;
1022
	for(auto const col : columns)
1023
	{
1024
		if((all_columns_valid = (col < columnCount())) == false)
1025
			break;		
1026
	}
1027

  
1028
	if (all_columns_valid) {
1029
#ifndef WT_TARGET_JAVA
1030
		std::vector<int> permutation(rowCount());
1031

  
1032
		for (unsigned i = 0; i < permutation.size(); ++i)
1033
			permutation[i] = i;
1034
#else
1035
		std::vector<int> permutation;
1036
		for (unsigned i = 0; i < rowCount(); ++i)
1037
			permutation.push_back(i);
1038
#endif // WT_TARGET_JAVA
1039

  
1040
		Utils::stable_sort(permutation, WStandardItemCompareMulti(this, columns, orders));
1041

  
1042
#ifndef WT_TARGET_JAVA
1043
		Column temp(rowCount());
1044
#endif
1045

  
1046
		for (int c = 0; c < columnCount(); ++c) {
1047
#ifdef WT_TARGET_JAVA
1048
			Column temp;
1049
#endif // WT_TARGET_JAVA
1050
			Column& cc = (*columns_)[c];
1051
			for (int r = 0; r < rowCount(); ++r) {
1052
#ifndef WT_TARGET_JAVA
1053
				temp[r] = cc[permutation[r]];
1054
#else
1055
				temp.push_back(cc[permutation[r]]);
1056
#endif // WT_TARGET_JAVA
1057
				if (temp[r])
1058
					temp[r]->row_ = r;
1059
			}
1060
			(*columns_)[c] = temp;
1061
		}
1062
	}
1063

  
1064
	for (int c = 0; c < columnCount(); ++c)
1065
		for (int r = 0; r < rowCount(); ++r) {
1066
			WStandardItem *ch = child(r, c);
1067
			if (ch)
1068
				ch->recursiveSortChildren(columns, orders);
1069
		}
1070
}
1071

  
884 1072
void WStandardItem::signalModelDataChange()
885 1073
{
886 1074
  if (model_) {
src/Wt/WStandardItemModel
386 386

  
387 387
  virtual void sort(int column, SortOrder order = AscendingOrder);
388 388

  
389
  virtual void sort(std::vector<int> const &columns, std::vector<SortOrder> const &orders);
390

  
389 391
  /*! \brief %Signal emitted when an item is changed.
390 392
   *
391 393
   * This signal is emitted whenever data for an item has changed. The
src/Wt/WStandardItemModel.C
415 415
  invisibleRootItem_->sortChildren(column, order);
416 416
}
417 417

  
418
void WStandardItemModel::sort(std::vector<int> const &columns, std::vector<SortOrder> const &orders)
419
{
420
	invisibleRootItem_->sortChildren(columns, orders);
421
}
422

  
418 423
}
419 424

  
420 425
#endif // DOXYGEN_ONLY
421
- 
(2-2/2)