#include <QAbstractItemModel>
#include "mappedselectionmodel.h"
+#include <QAbstractProxyModel>
#include <QDebug>
SelectionModelSynchronizer::SelectionModelSynchronizer(QAbstractItemModel *parent)
: QObject(parent),
- _model(parent)
+ _model(parent),
+ _selectionModel(parent)
{
+ 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 &)));
}
-SelectionModelSynchronizer::~SelectionModelSynchronizer() {
+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::addSelectionModel(MappedSelectionModel *selectionmodel) {
- if(selectionmodel->baseModel() != model()) {
- qWarning() << "cannot Syncronize SelectionModel" << selectionmodel << "which has a different baseModel()";
+void SelectionModelSynchronizer::addSelectionModel(QItemSelectionModel *selectionModel) {
+ if(!checkBaseModel(selectionModel)) {
+ qWarning() << "cannot Syncronize SelectionModel" << selectionModel << "which has a different baseModel()";
return;
}
- connect(selectionmodel, SIGNAL(mappedCurrentChanged(QModelIndex)),
- this, SLOT(_mappedCurrentChanged(QModelIndex)));
- connect(selectionmodel, SIGNAL(mappedSelectionChanged(QItemSelection)),
- this, SLOT(_mappedSelectionChanged(QItemSelection)));
-
- connect(this, SIGNAL(setCurrentIndex(QModelIndex, QItemSelectionModel::SelectionFlags)),
- selectionmodel, SLOT(mappedSetCurrentIndex(QModelIndex, QItemSelectionModel::SelectionFlags)));
- connect(this, SIGNAL(select(QItemSelection, QItemSelectionModel::SelectionFlags)),
- selectionmodel, SLOT(mappedSelect(QItemSelection, QItemSelectionModel::SelectionFlags)));
-
+ connect(selectionModel, SIGNAL(currentChanged(QModelIndex, QModelIndex)),
+ this, SLOT(mappedCurrentChanged(QModelIndex, QModelIndex)));
+ connect(selectionModel, SIGNAL(selectionChanged(QItemSelection, QItemSelection)),
+ this, SLOT(mappedSelectionChanged(QItemSelection, QItemSelection)));
+
+ if(qobject_cast<MappedSelectionModel *>(selectionModel)) {
+ connect(this, SIGNAL(setCurrentIndex(QModelIndex, QItemSelectionModel::SelectionFlags)),
+ selectionModel, SLOT(mappedSetCurrentIndex(QModelIndex, QItemSelectionModel::SelectionFlags)));
+ connect(this, SIGNAL(select(QItemSelection, QItemSelectionModel::SelectionFlags)),
+ selectionModel, SLOT(mappedSelect(QItemSelection, QItemSelectionModel::SelectionFlags)));
+ } else {
+ connect(this, SIGNAL(setCurrentIndex(QModelIndex, QItemSelectionModel::SelectionFlags)),
+ selectionModel, SLOT(setCurrentIndex(QModelIndex, QItemSelectionModel::SelectionFlags)));
+ connect(this, SIGNAL(select(QItemSelection, QItemSelectionModel::SelectionFlags)),
+ selectionModel, SLOT(select(QItemSelection, QItemSelectionModel::SelectionFlags)));
+ }
}
-void SelectionModelSynchronizer::removeSelectionModel(MappedSelectionModel *model) {
+void SelectionModelSynchronizer::removeSelectionModel(QItemSelectionModel *model) {
disconnect(model, 0, this, 0);
disconnect(this, 0, model, 0);
}
-void SelectionModelSynchronizer::_mappedCurrentChanged(const QModelIndex ¤t) {
- emit setCurrentIndex(current, QItemSelectionModel::ClearAndSelect);
+void SelectionModelSynchronizer::mappedCurrentChanged(const QModelIndex ¤t, const QModelIndex &previous) {
+ Q_UNUSED(previous);
+ QItemSelectionModel *selectionModel = qobject_cast<QItemSelectionModel *>(sender());
+ Q_ASSERT(selectionModel);
+ QModelIndex newSourceCurrent = mapToSource(current, selectionModel);
+ if(newSourceCurrent.isValid() && newSourceCurrent != currentIndex())
+ setCurrentIndex(newSourceCurrent);
+}
+
+void SelectionModelSynchronizer::mappedSelectionChanged(const QItemSelection &selected, const QItemSelection &deselected) {
+ Q_UNUSED(selected);
+ Q_UNUSED(deselected);
+ QItemSelectionModel *selectionModel = qobject_cast<QItemSelectionModel *>(sender());
+ Q_ASSERT(selectionModel);
+ QItemSelection newSourceSelection = mapSelectionToSource(selectionModel->selection(), selectionModel);
+ QItemSelection currentContainsSelection = newSourceSelection;
+ currentContainsSelection.merge(currentSelection(), QItemSelectionModel::Deselect);
+ if(!currentContainsSelection.isEmpty())
+ setCurrentSelection(newSourceSelection);
+}
+
+QModelIndex SelectionModelSynchronizer::mapToSource(const QModelIndex &index, QItemSelectionModel *selectionModel) {
+ Q_ASSERT(selectionModel);
+
+ QModelIndex sourceIndex = index;
+ const QAbstractItemModel *baseModel = selectionModel->model();
+ const QAbstractProxyModel *proxyModel = 0;
+ while((proxyModel = qobject_cast<const QAbstractProxyModel *>(baseModel)) != 0) {
+ sourceIndex = proxyModel->mapToSource(sourceIndex);
+ baseModel = proxyModel->sourceModel();
+ if(baseModel == model())
+ break;
+ }
+ return sourceIndex;
+}
+
+QItemSelection SelectionModelSynchronizer::mapSelectionToSource(const QItemSelection &selection, QItemSelectionModel *selectionModel) {
+ Q_ASSERT(selectionModel);
+
+ QItemSelection sourceSelection = selection;
+ const QAbstractItemModel *baseModel = selectionModel->model();
+ const QAbstractProxyModel *proxyModel = 0;
+ while((proxyModel = qobject_cast<const QAbstractProxyModel *>(baseModel)) != 0) {
+ sourceSelection = proxyModel->mapSelectionToSource(sourceSelection);
+ baseModel = proxyModel->sourceModel();
+ if(baseModel == model())
+ break;
+ }
+ return sourceSelection;
+}
+
+void SelectionModelSynchronizer::setCurrentIndex(const QModelIndex &index) {
+ _selectionModel.setCurrentIndex(index, QItemSelectionModel::Current);
+}
+void SelectionModelSynchronizer::setCurrentSelection(const QItemSelection &selection) {
+ _selectionModel.select(selection, QItemSelectionModel::Rows | QItemSelectionModel::ClearAndSelect);
+}
+
+void SelectionModelSynchronizer::currentChanged(const QModelIndex ¤t, const QModelIndex &previous) {
+ Q_UNUSED(previous);
+ emit setCurrentIndex(current, QItemSelectionModel::Current);
}
-void SelectionModelSynchronizer::_mappedSelectionChanged(const QItemSelection &selected) {
- emit select(selected, QItemSelectionModel::ClearAndSelect);
+void SelectionModelSynchronizer::selectionChanged(const QItemSelection &selected, const QItemSelection &deselected) {
+ Q_UNUSED(selected);
+ Q_UNUSED(deselected);
+ emit select(_selectionModel.selection(), QItemSelectionModel::ClearAndSelect);
}