File indexing completed on 2024-05-05 05:35:33
0001 #ifndef ListModel_h 0002 #define ListModel_h 0003 ////////////////////////////////////////////////////////////////////////////// 0004 // listmodel.h 0005 // ------------------- 0006 // 0007 // SPDX-FileCopyrightText: 2009 Hugo Pereira Da Costa <hugo.pereira@free.fr> 0008 // 0009 // SPDX-License-Identifier: MIT 0010 ////////////////////////////////////////////////////////////////////////////// 0011 0012 #include "oxygenitemmodel.h" 0013 0014 #include <QList> 0015 #include <QSet> 0016 0017 #include <algorithm> 0018 0019 namespace Oxygen 0020 { 0021 //* Job model. Stores job information for display in lists 0022 template<class T> 0023 class ListModel : public ItemModel 0024 { 0025 public: 0026 //* value type 0027 using ValueType = T; 0028 0029 //* reference 0030 using Reference = T &; 0031 0032 //* pointer 0033 using Pointer = T *; 0034 0035 //* value list and iterators 0036 using List = QList<ValueType>; 0037 using ListIterator = QListIterator<ValueType>; 0038 using MutableListIterator = QMutableListIterator<ValueType>; 0039 0040 //* constructor 0041 ListModel(QObject *parent = nullptr) 0042 : ItemModel(parent) 0043 { 0044 } 0045 0046 //*@name methods reimplemented from base class 0047 //@{ 0048 0049 //* flags 0050 Qt::ItemFlags flags(const QModelIndex &index) const override 0051 { 0052 if (!index.isValid()) 0053 return Qt::NoItemFlags; 0054 return Qt::ItemIsEnabled | Qt::ItemIsSelectable; 0055 } 0056 0057 //* unique index for given row, column and parent index 0058 QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override 0059 { 0060 // check if index is valid 0061 if (!hasIndex(row, column, parent)) 0062 return QModelIndex(); 0063 0064 // return invalid index if parent is valid 0065 if (parent.isValid()) 0066 return QModelIndex(); 0067 0068 // check against _values 0069 return (row < (int)_values.size()) ? createIndex(row, column) : QModelIndex(); 0070 } 0071 0072 //* index of parent 0073 QModelIndex parent(const QModelIndex &) const override 0074 { 0075 return QModelIndex(); 0076 } 0077 0078 //* number of rows below given index 0079 int rowCount(const QModelIndex &parent = QModelIndex()) const override 0080 { 0081 return parent.isValid() ? 0 : _values.size(); 0082 } 0083 0084 //@} 0085 0086 //*@name selection 0087 //@{ 0088 0089 //* clear internal list selected items 0090 void clearSelectedIndexes(void) 0091 { 0092 _selection.clear(); 0093 } 0094 0095 //* store index internal selection state 0096 void setIndexSelected(const QModelIndex &index, bool value) 0097 { 0098 if (value) 0099 _selection.push_back(get(index)); 0100 else 0101 _selection.erase(std::remove(_selection.begin(), _selection.end(), get(index)), _selection.end()); 0102 } 0103 0104 //* get list of internal selected items 0105 QModelIndexList selectedIndexes(void) const 0106 { 0107 QModelIndexList out; 0108 for (typename List::const_iterator iter = _selection.begin(); iter != _selection.end(); iter++) { 0109 QModelIndex index(ListModel::index(*iter)); 0110 if (index.isValid()) 0111 out.push_back(index); 0112 } 0113 return out; 0114 } 0115 0116 //@} 0117 0118 //*@name interface 0119 //@{ 0120 0121 //* add value 0122 void add(const ValueType &value) 0123 { 0124 emit layoutAboutToBeChanged(); 0125 _add(value); 0126 privateSort(); 0127 emit layoutChanged(); 0128 } 0129 0130 //* add values 0131 void add(const List &values) 0132 { 0133 // check if not empty 0134 // this avoids sending useless signals 0135 if (values.empty()) 0136 return; 0137 0138 emit layoutAboutToBeChanged(); 0139 0140 for (typename List::const_iterator iter = values.begin(); iter != values.end(); iter++) { 0141 _add(*iter); 0142 } 0143 0144 privateSort(); 0145 emit layoutChanged(); 0146 } 0147 0148 //* insert values 0149 void insert(const QModelIndex &index, const ValueType &value) 0150 { 0151 emit layoutAboutToBeChanged(); 0152 _insert(index, value); 0153 emit layoutChanged(); 0154 } 0155 0156 //* insert values 0157 void insert(const QModelIndex &index, const List &values) 0158 { 0159 emit layoutAboutToBeChanged(); 0160 0161 // need to loop in reverse order so that the "values" ordering is preserved 0162 ListIterator iter(values); 0163 iter.toBack(); 0164 while (iter.hasPrevious()) { 0165 _insert(index, iter.previous()); 0166 } 0167 0168 emit layoutChanged(); 0169 } 0170 0171 //* insert values 0172 void replace(const QModelIndex &index, const ValueType &value) 0173 { 0174 if (!index.isValid()) 0175 add(value); 0176 else { 0177 emit layoutAboutToBeChanged(); 0178 setIndexSelected(index, false); 0179 _values[index.row()] = value; 0180 setIndexSelected(index, true); 0181 emit layoutChanged(); 0182 } 0183 } 0184 0185 //* remove 0186 void remove(const ValueType &value) 0187 { 0188 emit layoutAboutToBeChanged(); 0189 _remove(value); 0190 emit layoutChanged(); 0191 return; 0192 } 0193 0194 //* remove 0195 void remove(const List &values) 0196 { 0197 // check if not empty 0198 // this avoids sending useless signals 0199 if (values.empty()) 0200 return; 0201 0202 emit layoutAboutToBeChanged(); 0203 for (typename List::const_iterator iter = values.begin(); iter != values.end(); iter++) { 0204 _remove(*iter); 0205 } 0206 emit layoutChanged(); 0207 return; 0208 } 0209 0210 //* clear 0211 void clear(void) 0212 { 0213 set(List()); 0214 } 0215 0216 //* update values from list 0217 /** 0218 values that are not found in current are removed 0219 new values are set to the end. 0220 This is slower than the "set" method, but the selection is not cleared in the process 0221 */ 0222 void update(List values) 0223 { 0224 emit layoutAboutToBeChanged(); 0225 0226 // store values to be removed 0227 List removed_values; 0228 0229 // update values that are common to both lists 0230 for (typename List::iterator iter = _values.begin(); iter != _values.end(); iter++) { 0231 // see if iterator is in list 0232 typename List::iterator found_iter(std::find(values.begin(), values.end(), *iter)); 0233 if (found_iter == values.end()) 0234 removed_values.push_back(*iter); 0235 else { 0236 *iter = *found_iter; 0237 values.erase(found_iter); 0238 } 0239 } 0240 0241 // remove values that have not been found in new list 0242 for (typename List::const_iterator iter = removed_values.constBegin(); iter != removed_values.constEnd(); iter++) { 0243 _remove(*iter); 0244 } 0245 0246 // add remaining values 0247 for (typename List::const_iterator iter = values.constBegin(); iter != values.constEnd(); iter++) { 0248 _add(*iter); 0249 } 0250 0251 privateSort(); 0252 emit layoutChanged(); 0253 } 0254 0255 //* set all values 0256 void set(const List &values) 0257 { 0258 emit layoutAboutToBeChanged(); 0259 _values = values; 0260 _selection.clear(); 0261 privateSort(); 0262 emit layoutChanged(); 0263 0264 return; 0265 } 0266 0267 //* return all values 0268 const List &get(void) const 0269 { 0270 return _values; 0271 } 0272 0273 //* return value for given index 0274 ValueType get(const QModelIndex &index) const 0275 { 0276 return (index.isValid() && index.row() < int(_values.size())) ? _values[index.row()] : ValueType(); 0277 } 0278 0279 //* return value for given index 0280 ValueType &get(const QModelIndex &index) 0281 { 0282 Q_ASSERT(index.isValid() && index.row() < int(_values.size())); 0283 return _values[index.row()]; 0284 } 0285 0286 //* return all values 0287 List get(const QModelIndexList &indexes) const 0288 { 0289 List out; 0290 for (QModelIndexList::const_iterator iter = indexes.begin(); iter != indexes.end(); iter++) { 0291 if (iter->isValid() && iter->row() < int(_values.size())) 0292 out.push_back(get(*iter)); 0293 } 0294 return out; 0295 } 0296 0297 //* return index associated to a given value 0298 QModelIndex index(const ValueType &value, int column = 0) const 0299 { 0300 for (int row = 0; row < _values.size(); ++row) { 0301 if (value == _values[row]) 0302 return index(row, column); 0303 } 0304 return QModelIndex(); 0305 } 0306 0307 //@} 0308 0309 //* return true if model contains given index 0310 bool contains(const QModelIndex &index) const 0311 { 0312 return index.isValid() && index.row() < _values.size(); 0313 } 0314 0315 private: 0316 //* return all values 0317 List &_get(void) 0318 { 0319 return _values; 0320 } 0321 0322 //* add, without update 0323 void _add(const ValueType &value) 0324 { 0325 typename List::iterator iter = std::find(_values.begin(), _values.end(), value); 0326 if (iter == _values.end()) 0327 _values.push_back(value); 0328 else 0329 *iter = value; 0330 } 0331 0332 //* add, without update 0333 void _insert(const QModelIndex &index, const ValueType &value) 0334 { 0335 if (!index.isValid()) 0336 add(value); 0337 int row = 0; 0338 typename List::iterator iter(_values.begin()); 0339 for (; iter != _values.end() && row != index.row(); iter++, row++) { } 0340 0341 _values.insert(iter, value); 0342 } 0343 0344 //* remove, without update 0345 void _remove(const ValueType &value) 0346 { 0347 _values.erase(std::remove(_values.begin(), _values.end(), value), _values.end()); 0348 _selection.erase(std::remove(_selection.begin(), _selection.end(), value), _selection.end()); 0349 } 0350 0351 //* values 0352 List _values; 0353 0354 //* selection 0355 List _selection; 0356 }; 0357 } 0358 #endif