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