+ : QObject(parent),
+ _model(parent),
+ _selectionModel(parent),
+ _changeCurrentEnabled(true),
+ _changeSelectionEnabled(true)
+{
+ connect(&_selectionModel, SIGNAL(currentChanged(const QModelIndex &, const QModelIndex &)),
+ this, SLOT(currentChanged(const QModelIndex &, const QModelIndex &)));
+ connect(&_selectionModel, SIGNAL(selectionChanged(const QItemSelection &, const QItemSelection &)),
+ this, SLOT(selectionChanged(const QItemSelection &, const QItemSelection &)));
+}
+
+
+bool SelectionModelSynchronizer::checkBaseModel(QItemSelectionModel *selectionModel)
+{
+ if (!selectionModel)
+ return false;
+
+ const QAbstractItemModel *baseModel = selectionModel->model();
+ const QAbstractProxyModel *proxyModel = 0;
+ while ((proxyModel = qobject_cast<const QAbstractProxyModel *>(baseModel)) != 0) {
+ baseModel = proxyModel->sourceModel();
+ if (baseModel == model())
+ break;
+ }
+ return baseModel == model();
+}
+
+
+void SelectionModelSynchronizer::synchronizeSelectionModel(QItemSelectionModel *selectionModel)
+{
+ if (!checkBaseModel(selectionModel)) {
+ qWarning() << "cannot Synchronize SelectionModel" << selectionModel << "which has a different baseModel()";
+ return;
+ }
+
+ if (_selectionModels.contains(selectionModel)) {
+ selectionModel->setCurrentIndex(mapFromSource(currentIndex(), selectionModel), QItemSelectionModel::Current);
+ selectionModel->select(mapSelectionFromSource(currentSelection(), selectionModel), QItemSelectionModel::ClearAndSelect);
+ return;
+ }
+
+ connect(selectionModel, SIGNAL(currentChanged(QModelIndex, QModelIndex)),
+ this, SLOT(syncedCurrentChanged(QModelIndex, QModelIndex)));
+ connect(selectionModel, SIGNAL(selectionChanged(QItemSelection, QItemSelection)),
+ this, SLOT(syncedSelectionChanged(QItemSelection, QItemSelection)));
+
+ connect(selectionModel, SIGNAL(destroyed(QObject *)), this, SLOT(selectionModelDestroyed(QObject *)));
+
+ _selectionModels << selectionModel;
+}
+
+
+void SelectionModelSynchronizer::removeSelectionModel(QItemSelectionModel *model)
+{
+ disconnect(model, 0, this, 0);
+ disconnect(this, 0, model, 0);
+ selectionModelDestroyed(model);
+}
+
+
+void SelectionModelSynchronizer::selectionModelDestroyed(QObject *object)
+{
+ QItemSelectionModel *model = static_cast<QItemSelectionModel *>(object);
+ QSet<QItemSelectionModel *>::iterator iter = _selectionModels.begin();
+ while (iter != _selectionModels.end()) {
+ if (*iter == model) {
+ iter = _selectionModels.erase(iter);
+ }
+ else {
+ ++iter;
+ }
+ }
+}
+
+
+void SelectionModelSynchronizer::syncedCurrentChanged(const QModelIndex ¤t, const QModelIndex &previous)
+{
+ Q_UNUSED(previous);
+
+ if (!_changeCurrentEnabled)
+ return;
+
+ QItemSelectionModel *selectionModel = qobject_cast<QItemSelectionModel *>(sender());
+ Q_ASSERT(selectionModel);
+ QModelIndex newSourceCurrent = mapToSource(current, selectionModel);
+ if (newSourceCurrent.isValid() && newSourceCurrent != currentIndex())
+ setCurrentIndex(newSourceCurrent);
+}
+
+
+void SelectionModelSynchronizer::syncedSelectionChanged(const QItemSelection &selected, const QItemSelection &deselected)
+{
+ Q_UNUSED(selected);
+ Q_UNUSED(deselected);
+
+ if (!_changeSelectionEnabled)
+ return;
+
+ QItemSelectionModel *selectionModel = qobject_cast<QItemSelectionModel *>(sender());
+ Q_ASSERT(selectionModel);
+
+ QItemSelection mappedSelection = selectionModel->selection();
+ QItemSelection currentSelectionMapped = mapSelectionFromSource(currentSelection(), selectionModel);
+
+ QItemSelection checkSelection = currentSelectionMapped;
+ checkSelection.merge(mappedSelection, QItemSelectionModel::Deselect);
+ if (checkSelection.isEmpty()) {
+ // that means the new selection contains the current selection (currentSel - newSel = {})
+ checkSelection = mappedSelection;
+ checkSelection.merge(currentSelectionMapped, QItemSelectionModel::Deselect);
+ if (checkSelection.isEmpty()) {
+ // that means the current selection contains the new selection (newSel - currentSel = {})
+ // -> currentSel == newSel
+ return;
+ }
+ }
+ setCurrentSelection(mapSelectionToSource(mappedSelection, selectionModel));
+}
+
+
+QModelIndex SelectionModelSynchronizer::mapFromSource(const QModelIndex &sourceIndex, const QItemSelectionModel *selectionModel)