File indexing completed on 2024-04-28 04:50:50
0001 /* 0002 * tablemodel.h 0003 * 0004 * Copyright (C) 2011 Christoph Pfister <christophpfister@gmail.com> 0005 * 0006 * This program is free software; you can redistribute it and/or modify 0007 * it under the terms of the GNU General Public License as published by 0008 * the Free Software Foundation; either version 2 of the License, or 0009 * (at your option) any later version. 0010 * 0011 * This program is distributed in the hope that it will be useful, 0012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0014 * GNU General Public License for more details. 0015 * 0016 * You should have received a copy of the GNU General Public License along 0017 * with this program; if not, write to the Free Software Foundation, Inc., 0018 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 0019 */ 0020 0021 #ifndef TABLEMODEL_H 0022 #define TABLEMODEL_H 0023 0024 #include <QAbstractTableModel> 0025 0026 template<class T> class TableModel : public QAbstractTableModel 0027 { 0028 typedef typename T::ItemType ItemType; 0029 typedef typename T::LessThanType LessThanType; 0030 typedef typename LessThanType::SortOrder SortOrder; 0031 public: 0032 explicit TableModel(QObject *parent) : QAbstractTableModel(parent), updatingRow(-1) { } 0033 ~TableModel() { } 0034 0035 QModelIndex find(const ItemType &item) const 0036 { 0037 if (item.isValid()) { 0038 int row = binaryFind(item); 0039 0040 if (row < items.size()) { 0041 return index(row, 0); 0042 } 0043 } 0044 0045 return QModelIndex(); 0046 } 0047 0048 const ItemType &value(int row) const 0049 { 0050 if ((row >= 0) && (row < items.size())) { 0051 return items.at(row); 0052 } 0053 0054 return sharedNull; 0055 } 0056 0057 const ItemType &value(const QModelIndex &index) const 0058 { 0059 if ((index.row() >= 0) && (index.row() < items.size())) { 0060 return items.at(index.row()); 0061 } 0062 0063 return sharedNull; 0064 } 0065 0066 int columnCount(const QModelIndex &parent) const override 0067 { 0068 if (!parent.isValid()) { 0069 return helper.columnCount(); 0070 } 0071 0072 return 0; 0073 } 0074 0075 int rowCount(const QModelIndex &parent) const override 0076 { 0077 if (!parent.isValid()) { 0078 return items.size(); 0079 } 0080 0081 return 0; 0082 } 0083 0084 protected: 0085 template<class U> void reset(const U &container) 0086 { 0087 beginLayoutChange(); 0088 items.clear(); 0089 0090 for (typename U::ConstIterator it = container.constBegin(); 0091 it != container.constEnd(); ++it) { 0092 const ItemType &item = *it; 0093 0094 if (helper.filterAcceptsItem(item)) { 0095 items.append(item); 0096 } 0097 } 0098 0099 std::sort(items.begin(), items.end(), lessThan); 0100 endLayoutChange(); 0101 } 0102 0103 template<class U> void resetFromKeys(const U &container) 0104 { 0105 beginLayoutChange(); 0106 items.clear(); 0107 0108 for (typename U::ConstIterator it = container.constBegin(); 0109 it != container.constEnd(); ++it) { 0110 const ItemType &item = it.key(); 0111 0112 if (helper.filterAcceptsItem(item)) { 0113 items.append(item); 0114 } 0115 } 0116 0117 std::sort(items.begin(), items.end(), lessThan); 0118 endLayoutChange(); 0119 } 0120 0121 void insert(const ItemType &item) 0122 { 0123 if (item.isValid() && helper.filterAcceptsItem(item)) { 0124 int row = upperBound(item); 0125 beginInsertRows(QModelIndex(), row, row); 0126 items.insert(row, item); 0127 endInsertRows(); 0128 } 0129 } 0130 0131 void aboutToUpdate(const ItemType &item) 0132 { 0133 updatingRow = -1; 0134 0135 if (item.isValid()) { 0136 updatingRow = binaryFind(item); 0137 } 0138 } 0139 0140 void update(const ItemType &item) 0141 { 0142 int row = updatingRow; 0143 updatingRow = -1; 0144 0145 if ((row >= 0) && (row < items.size())) { 0146 if (item.isValid() && helper.filterAcceptsItem(item)) { 0147 items.replace(row, item); 0148 int targetRow = row; 0149 0150 while (((targetRow - 1) >= 0) && 0151 lessThan(item, items.at(targetRow - 1))) { 0152 --targetRow; 0153 } 0154 0155 while (((targetRow + 1) < items.size()) && 0156 lessThan(items.at(targetRow + 1), item)) { 0157 ++targetRow; 0158 } 0159 0160 if (row == targetRow) { 0161 emit dataChanged(index(row, 0), 0162 index(row, helper.columnCount() - 1)); 0163 } else { 0164 beginLayoutChange(); 0165 items.move(row, targetRow); 0166 endLayoutChange(); 0167 } 0168 } else { 0169 beginRemoveRows(QModelIndex(), row, row); 0170 items.removeAt(row); 0171 endRemoveRows(); 0172 } 0173 } else { 0174 insert(item); 0175 } 0176 } 0177 0178 void remove(const ItemType &item) 0179 { 0180 if (item.isValid()) { 0181 int row = binaryFind(item); 0182 beginRemoveRows(QModelIndex(), row, row); 0183 items.removeAt(row); 0184 endRemoveRows(); 0185 } 0186 } 0187 0188 void internalSort(SortOrder sortOrder) 0189 { 0190 if (lessThan.getSortOrder() != sortOrder) { 0191 beginLayoutChange(); 0192 lessThan.setSortOrder(sortOrder); 0193 std::sort(items.begin(), items.end(), lessThan); 0194 endLayoutChange(); 0195 } 0196 } 0197 0198 private: 0199 int binaryFind(const ItemType &item) const 0200 { 0201 return (std::lower_bound(items.constBegin(), items.constEnd(), item, lessThan) - 0202 items.constBegin()); 0203 } 0204 0205 int upperBound(const ItemType &item) const 0206 { 0207 return (std::upper_bound(items.constBegin(), items.constEnd(), item, lessThan) - 0208 items.constBegin()); 0209 } 0210 0211 void beginLayoutChange() 0212 { 0213 emit layoutAboutToBeChanged(); 0214 oldPersistentIndexes = persistentIndexList(); 0215 persistentItems.clear(); 0216 0217 foreach (const QModelIndex &index, oldPersistentIndexes) { 0218 if ((index.row() >= 0) && (index.row() < items.size())) { 0219 persistentItems.append(items.at(index.row())); 0220 } else { 0221 persistentItems.append(ItemType()); 0222 } 0223 } 0224 } 0225 0226 void endLayoutChange() 0227 { 0228 QModelIndexList newPersistentIndexes; 0229 0230 for (int i = 0; i < oldPersistentIndexes.size(); ++i) { 0231 const QModelIndex &oldIndex = oldPersistentIndexes.at(i); 0232 const ItemType &item = persistentItems.at(i); 0233 0234 if (item.isValid()) { 0235 int row = binaryFind(item); 0236 newPersistentIndexes.append(index(row, oldIndex.column())); 0237 } else { 0238 newPersistentIndexes.append(QModelIndex()); 0239 } 0240 } 0241 0242 changePersistentIndexList(oldPersistentIndexes, newPersistentIndexes); 0243 oldPersistentIndexes.clear(); 0244 persistentItems.clear(); 0245 emit layoutChanged(); 0246 } 0247 0248 private: 0249 QList<ItemType> items; 0250 LessThanType lessThan; 0251 ItemType sharedNull; 0252 QModelIndexList oldPersistentIndexes; 0253 QList<ItemType> persistentItems; 0254 int updatingRow; 0255 0256 protected: 0257 T helper; 0258 }; 0259 0260 #endif /* TABLEMODEL_H */