1 /*
2  * Copyright (C) 2008 Emweb bv, Herent, Belgium.
3  *
4  * See the LICENSE file for terms of use.
5  */
6 
7 #include "Wt/WAbstractProxyModel.h"
8 
9 namespace Wt {
10 
11 #ifndef DOXYGEN_ONLY
12 
~BaseItem()13 WAbstractProxyModel::BaseItem::~BaseItem()
14 { }
15 
WAbstractProxyModel()16 WAbstractProxyModel::WAbstractProxyModel()
17   : sourceModel_(nullptr)
18 { }
19 
20 void WAbstractProxyModel
setSourceModel(const std::shared_ptr<WAbstractItemModel> & sourceModel)21 ::setSourceModel(const std::shared_ptr<WAbstractItemModel>& sourceModel)
22 {
23   sourceModel_ = sourceModel;
24 }
25 
data(const WModelIndex & index,ItemDataRole role)26 cpp17::any WAbstractProxyModel::data(const WModelIndex& index, ItemDataRole role) const
27 {
28   return sourceModel_->data(mapToSource(index), role);
29 }
30 
setData(const WModelIndex & index,const cpp17::any & value,ItemDataRole role)31 bool WAbstractProxyModel::setData(const WModelIndex& index,
32                                   const cpp17::any& value, ItemDataRole role)
33 {
34   return sourceModel_->setData(mapToSource(index), value, role);
35 }
36 
setItemData(const WModelIndex & index,const DataMap & values)37 bool WAbstractProxyModel::setItemData(const WModelIndex& index,
38 				      const DataMap& values)
39 {
40   return sourceModel_->setItemData(mapToSource(index), values);
41 }
42 
flags(const WModelIndex & index)43 WFlags<ItemFlag> WAbstractProxyModel::flags(const WModelIndex& index) const
44 {
45   return sourceModel_->flags(mapToSource(index));
46 }
47 
insertColumns(int column,int count,const WModelIndex & parent)48 bool WAbstractProxyModel::insertColumns(int column, int count,
49 					const WModelIndex& parent)
50 {
51   return sourceModel_->insertColumns(column, count, parent);
52 }
53 
removeColumns(int column,int count,const WModelIndex & parent)54 bool WAbstractProxyModel::removeColumns(int column, int count,
55 					const WModelIndex& parent)
56 {
57   return sourceModel_->removeColumns(column, count, parent);
58 }
59 
mimeType()60 std::string WAbstractProxyModel::mimeType() const
61 {
62   return sourceModel_->mimeType();
63 }
64 
acceptDropMimeTypes()65 std::vector<std::string> WAbstractProxyModel::acceptDropMimeTypes() const
66 {
67   return sourceModel_->acceptDropMimeTypes();
68 }
69 
dropEvent(const WDropEvent & e,DropAction action,int row,int column,const WModelIndex & parent)70 void WAbstractProxyModel::dropEvent(const WDropEvent& e, DropAction action,
71 				    int row, int column,
72 				    const WModelIndex& parent)
73 {
74   WModelIndex sourceParent = mapToSource(parent);
75 
76   int sourceRow = row;
77   int sourceColumn = column;
78 
79   if (sourceRow != -1)
80     sourceRow = mapToSource(index(row, 0, parent)).row();
81 
82   sourceModel_->dropEvent(e, action, sourceRow, sourceColumn, sourceParent);
83 }
84 
toRawIndex(const WModelIndex & index)85 void *WAbstractProxyModel::toRawIndex(const WModelIndex& index) const
86 {
87   return sourceModel_->toRawIndex(mapToSource(index));
88 }
89 
fromRawIndex(void * rawIndex)90 WModelIndex WAbstractProxyModel::fromRawIndex(void *rawIndex) const
91 {
92   return mapFromSource(sourceModel_->fromRawIndex(rawIndex));
93 }
94 
headerFlags(int section,Orientation orientation)95 WFlags<HeaderFlag> WAbstractProxyModel::headerFlags(int section,
96 						    Orientation orientation) const
97 {
98   if (orientation == Wt::Orientation::Horizontal) {
99     section = mapToSource(index(0, section, Wt::WModelIndex())).column();
100   } else {
101     section = mapToSource(index(section, 0, Wt::WModelIndex())).row();
102   }
103   return sourceModel_->headerFlags(section, orientation);
104 }
105 
headerData(int section,Orientation orientation,ItemDataRole role)106 cpp17::any WAbstractProxyModel::headerData(int section, Orientation orientation,
107                                         ItemDataRole role) const
108 {
109   if (orientation == Wt::Orientation::Horizontal) {
110     section = mapToSource(index(0, section, Wt::WModelIndex())).column();
111   } else {
112     section = mapToSource(index(section, 0, Wt::WModelIndex())).row();
113   }
114   return sourceModel_->headerData(section, orientation, role);
115 }
116 
createSourceIndex(int row,int column,void * ptr)117 WModelIndex WAbstractProxyModel::createSourceIndex(int row, int column,
118 						   void *ptr) const
119 {
120   return sourceModel_->createIndex(row, column, ptr);
121 }
122 
startShiftModelIndexes(const WModelIndex & sourceParent,int start,int count,ItemMap & items)123 void WAbstractProxyModel::startShiftModelIndexes(const WModelIndex& sourceParent,
124 						 int start, int count,
125 						 ItemMap& items)
126 {
127   /*
128    * We must shift all indexes within sourceParent >= start with count
129    * and delete items when count < 0.
130    */
131   std::vector<BaseItem *> erased;
132 
133   WModelIndex startIndex;
134   if (sourceModel()->rowCount(sourceParent) == 0)
135     startIndex = sourceParent;
136   else if (start >= sourceModel()->rowCount(sourceParent))
137     return;
138   else
139     startIndex = sourceModel()->index(start, 0, sourceParent);
140 
141 #ifdef WT_TARGET_JAVA
142   if (!startIndex.isValid())
143     return;
144 #endif
145 
146   for (ItemMap::iterator it = items.lower_bound(startIndex);
147        it != items.end();) {
148 #ifndef WT_TARGET_JAVA
149     ItemMap::iterator n = it;
150     ++n;
151 #endif
152     WModelIndex i = it->first;
153     if (i == sourceParent) {
154 #ifndef WT_TARGET_JAVA
155       it = n;
156 #endif
157       continue;
158     }
159 
160     if (i.isValid()) {
161       WModelIndex p = i.parent();
162       if (p != sourceParent && !WModelIndex::isAncestor(p, sourceParent))
163 	break;
164 
165       if (p == sourceParent) { /* Child of source parent: shift or remove */
166 	if (count < 0 &&
167 	    i.row() >= start &&
168 	    i.row() < start + (-count))
169 	  erased.push_back(it->second);
170 	else {
171 	  itemsToShift_.push_back(it->second);
172 	}
173       } else if (count < 0) { /* Other descendent: remove if necessary */
174 	// delete indexes that are about to be deleted, if they are within
175 	// the range of deleted indexes
176 	do {
177 	  if (p.parent() == sourceParent
178 	      && p.row() >= start
179 	      && p.row() < start + (-count)) {
180 	    erased.push_back(it->second);
181 	    break;
182 	  } else
183 	    p = p.parent();
184 	} while (p != sourceParent);
185       }
186     }
187 
188 #ifndef WT_TARGET_JAVA
189     it = n;
190 #endif
191   }
192 
193   for (unsigned i = 0; i < itemsToShift_.size(); ++i) {
194     BaseItem *item = itemsToShift_[i];
195     items.erase(item->sourceIndex_);
196     item->sourceIndex_ = sourceModel()->index
197       (item->sourceIndex_.row() + count,
198        item->sourceIndex_.column(),
199        sourceParent);
200   }
201 
202   for (unsigned i = 0; i < erased.size(); ++i) {
203     items.erase(erased[i]->sourceIndex_);
204     delete erased[i];
205   }
206 
207   if (count > 0)
208     endShiftModelIndexes(sourceParent, start, count, items);
209 }
210 
endShiftModelIndexes(const WModelIndex & sourceParent,int start,int count,ItemMap & items)211 void WAbstractProxyModel::endShiftModelIndexes(const WModelIndex& sourceParent,
212 					       int start, int count,
213 					       ItemMap& items)
214 {
215   for (unsigned i = 0; i < itemsToShift_.size(); ++i)
216     items[itemsToShift_[i]->sourceIndex_] = itemsToShift_[i];
217 
218   itemsToShift_.clear();
219 }
220 
221 
222 #endif // DOXYGEN_ONLY
223 
224 }
225