File indexing completed on 2025-02-02 14:20:13
0001 /* 0002 SPDX-FileCopyrightText: 2010 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.net> 0003 SPDX-FileContributor: Stephen Kelly <stephen@kdab.com> 0004 0005 SPDX-License-Identifier: LGPL-2.0-or-later 0006 */ 0007 0008 #ifndef KVIEWSTATESERIALIZER_H 0009 #define KVIEWSTATESERIALIZER_H 0010 0011 #include <QObject> 0012 #include <QPair> 0013 #include <QStringList> 0014 #include <memory> 0015 0016 #include "kwidgetsaddons_export.h" 0017 0018 class QAbstractItemView; 0019 class QItemSelectionModel; 0020 class QAbstractItemModel; 0021 class QAbstractScrollArea; 0022 class QModelIndex; 0023 0024 class KViewStateSerializerPrivate; 0025 0026 /** 0027 @class KViewStateSerializer kviewstateserializer.h KViewStateSerializer 0028 0029 @brief Object for saving and restoring state in QTreeViews and QItemSelectionModels 0030 0031 Implement the indexFromConfigString and indexToConfigString methods to handle 0032 the model in the view whose state is being saved. These implementations can be 0033 quite trivial: 0034 0035 @code 0036 QModelIndex DynamicTreeStateSaver::indexFromConfigString(const QAbstractItemModel* model, 0037 const QString& key) const 0038 { 0039 QModelIndexList list = model->match(model->index(0, 0), 0040 DynamicTreeModel::DynamicTreeModelId, 0041 key.toInt(), 1, Qt::MatchRecursive); 0042 if (list.isEmpty()) { 0043 return QModelIndex(); 0044 } 0045 return list.first(); 0046 } 0047 0048 QString DynamicTreeStateSaver::indexToConfigString(const QModelIndex& index) const 0049 { 0050 return index.data(DynamicTreeModel::DynamicTreeModelId).toString(); 0051 } 0052 @endcode 0053 0054 It is possible to restore the state of a QTreeView (that is, the expanded state and 0055 selected state of all indexes as well as the horizontal and vertical scroll state) by 0056 using setTreeView. 0057 0058 If there is no tree view state to restore (for example if using QML), the selection 0059 state of a QItemSelectionModel can be saved or restored instead. 0060 0061 The state of any QAbstractScrollArea can also be saved and restored. 0062 0063 A KViewStateSerializer should be created on the stack when saving and on the heap 0064 when restoring. The model may be populated dynamically between several event loops, 0065 so it may not be immediate for the indexes that should be selected to be in the model. 0066 The saver should *not* be persisted as a member. The saver will destroy itself when it 0067 has completed the restoration specified in the config group, or a small amount of time 0068 has elapsed. 0069 0070 @code 0071 MyWidget::MyWidget(Qobject *parent) 0072 : QWidget(parent) 0073 { 0074 ... 0075 0076 m_view = new QTreeView(splitter); 0077 m_view->setModel(model); 0078 0079 connect(model, &QAbstractItemModel::modelAboutToBeReset, this, [this]() { saveState(); }); 0080 connect(model, &QAbstractItemModel::modelReset, [this]() { restoreState(); }); 0081 connect(qApp, &QApplication::aboutToQuit, this, [this]() { saveState(); }); 0082 0083 restoreState(); 0084 } 0085 0086 void StateSaverWidget::saveState() 0087 { 0088 ConcreteStateSaver saver; 0089 saver.setTreeView(m_view); 0090 0091 KConfigGroup cfg(KSharedConfig::openConfig(), "ExampleViewState"); 0092 saver.saveState(cfg); 0093 cfg.sync(); 0094 } 0095 0096 void StateSaverWidget::restoreState() 0097 { 0098 // Will delete itself. 0099 ConcreteTreeStateSaver *saver = new ConcreteStateSaver(); 0100 saver->setTreeView(m_view); 0101 KConfigGroup cfg(KSharedConfig::openConfig(), "ExampleViewState"); 0102 saver->restoreState(cfg); 0103 } 0104 @endcode 0105 0106 After creating a saver, the state can be saved using a KConfigGroup. 0107 0108 It is also possible to save and restore state directly by using the restoreSelection, 0109 restoreExpanded etc methods. Note that the implementation of these methods should return 0110 strings that the indexFromConfigString implementation can handle. 0111 0112 @code 0113 class DynamicTreeStateSaver : public KViewStateSerializer 0114 { 0115 Q_OBJECT 0116 public: 0117 // ... 0118 0119 void selectItems(const QList<qint64> &items) 0120 { 0121 QStringList itemStrings; 0122 for (qint64 item : items) { 0123 itemStrings << QString::number(item); 0124 } 0125 restoreSelection(itemStrings); 0126 } 0127 0128 void expandItems(const QList<qint64> &items) 0129 { 0130 QStringList itemStrings; 0131 for (qint64 item : items) { 0132 itemStrings << QString::number(item); 0133 } 0134 restoreSelection(itemStrings); 0135 } 0136 }; 0137 @endcode 0138 0139 Note that a single instance of this class should be used with only one widget. 0140 That is don't do this: 0141 0142 @code 0143 saver->setTreeView(treeView1); 0144 saver->setSelectionModel(treeView2->selectionModel()); 0145 saver->setScrollArea(treeView3); 0146 @endcode 0147 0148 To save the state of 3 different widgets, use three savers, even if they operate 0149 on the same root model. 0150 0151 @code 0152 saver1->setTreeView(treeView1); 0153 saver2->setSelectionModel(treeView2->selectionModel()); 0154 saver3->setScrollArea(treeView3); 0155 @endcode 0156 0157 @note The KViewStateSerializer does not take ownership of any widgets set on it. 0158 0159 It is recommended to restore the state on application startup and after the 0160 model has been reset, and to save the state on application close and before 0161 the model has been reset. 0162 0163 @see QAbstractItemModel::modelAboutToBeReset QAbstractItemModel::modelReset 0164 0165 @author Stephen Kelly <stephen@kdab.com> 0166 @since 4.5 0167 */ 0168 class KWIDGETSADDONS_EXPORT KViewStateSerializer : public QObject 0169 { 0170 Q_OBJECT 0171 public: 0172 /** 0173 * Constructor 0174 */ 0175 explicit KViewStateSerializer(QObject *parent = nullptr); 0176 0177 /** 0178 * Destructor 0179 */ 0180 ~KViewStateSerializer() override; 0181 0182 /** 0183 * The view whose state is persisted. 0184 */ 0185 QAbstractItemView *view() const; 0186 0187 /** 0188 * Sets the view whose state is persisted. 0189 */ 0190 void setView(QAbstractItemView *view); 0191 0192 /** 0193 * The QItemSelectionModel whose state is persisted. 0194 */ 0195 QItemSelectionModel *selectionModel() const; 0196 0197 /** 0198 * Sets the QItemSelectionModel whose state is persisted. 0199 */ 0200 void setSelectionModel(QItemSelectionModel *selectionModel); 0201 0202 /** 0203 * Returns a QStringList describing the selection in the selectionModel. 0204 */ 0205 QStringList selectionKeys() const; 0206 0207 /** 0208 * Returns a QStringList representing the expanded indexes in the QTreeView. 0209 */ 0210 QStringList expansionKeys() const; 0211 0212 /** 0213 * Returns a QString describing the current index in the selection model. 0214 */ 0215 QString currentIndexKey() const; 0216 0217 /** 0218 * Returns the vertical and horizontal scroll of the QAbstractScrollArea. 0219 */ 0220 QPair<int, int> scrollState() const; 0221 0222 /** 0223 * Select the indexes described by @p indexStrings 0224 */ 0225 void restoreSelection(const QStringList &indexStrings); 0226 0227 /** 0228 * Make the index described by @p indexString the currentIndex in the selectionModel. 0229 */ 0230 void restoreCurrentItem(const QString &indexString); 0231 0232 /** 0233 * Expand the indexes described by @p indexStrings in the QTreeView. 0234 */ 0235 void restoreExpanded(const QStringList &indexStrings); 0236 0237 /** 0238 * Restores the scroll state of the QAbstractScrollArea to the @p verticalScoll 0239 * and @p horizontalScroll 0240 */ 0241 void restoreScrollState(int verticalScoll, int horizontalScroll); 0242 0243 protected: 0244 /** 0245 * Reimplement to return an index in the @p model described by the unique key @p key 0246 */ 0247 virtual QModelIndex indexFromConfigString(const QAbstractItemModel *model, const QString &key) const = 0; 0248 0249 /** 0250 * Reimplement to return a unique string for the @p index. 0251 */ 0252 virtual QString indexToConfigString(const QModelIndex &index) const = 0; 0253 0254 void restoreState(); 0255 0256 private: 0257 //@cond PRIVATE 0258 Q_DECLARE_PRIVATE(KViewStateSerializer) 0259 std::unique_ptr<KViewStateSerializerPrivate> const d_ptr; 0260 //@endcond 0261 }; 0262 0263 #endif