KDEUI
klinkitemselectionmodel.cpp
Go to the documentation of this file.
00001 /* 00002 Copyright (C) 2010 Klarälvdalens Datakonsult AB, 00003 a KDAB Group company, info@kdab.net, 00004 author Stephen Kelly <stephen@kdab.com> 00005 00006 This library is free software; you can redistribute it and/or modify it 00007 under the terms of the GNU Library General Public License as published by 00008 the Free Software Foundation; either version 2 of the License, or (at your 00009 option) any later version. 00010 00011 This library is distributed in the hope that it will be useful, but WITHOUT 00012 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 00013 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public 00014 License for more details. 00015 00016 You should have received a copy of the GNU Library General Public License 00017 along with this library; see the file COPYING.LIB. If not, write to the 00018 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 00019 02110-1301, USA. 00020 */ 00021 00022 00023 #include "klinkitemselectionmodel.h" 00024 00025 #include "kmodelindexproxymapper.h" 00026 00027 #include "kdebug.h" 00028 00029 #include <QItemSelection> 00030 00031 class KLinkItemSelectionModelPrivate 00032 { 00033 public: 00034 KLinkItemSelectionModelPrivate(KLinkItemSelectionModel *proxySelectionModel, QAbstractItemModel *model, 00035 QItemSelectionModel *linkedItemSelectionModel) 00036 : q_ptr(proxySelectionModel), 00037 m_model(model), 00038 m_linkedItemSelectionModel(linkedItemSelectionModel), 00039 m_ignoreCurrentChanged(false), 00040 m_indexMapper(new KModelIndexProxyMapper(model, linkedItemSelectionModel->model(), proxySelectionModel)) 00041 { 00042 } 00043 00044 Q_DECLARE_PUBLIC(KLinkItemSelectionModel) 00045 KLinkItemSelectionModel * const q_ptr; 00046 00047 00048 bool assertSelectionValid(const QItemSelection &selection) const { 00049 foreach(const QItemSelectionRange &range, selection) { 00050 if (!range.isValid()) { 00051 kDebug() << selection; 00052 } 00053 Q_ASSERT(range.isValid()); 00054 } 00055 return true; 00056 } 00057 00058 void sourceSelectionChanged(const QItemSelection& selected, const QItemSelection& deselected); 00059 00060 QAbstractItemModel * const m_model; 00061 QItemSelectionModel * const m_linkedItemSelectionModel; 00062 bool m_ignoreCurrentChanged; 00063 KModelIndexProxyMapper * const m_indexMapper; 00064 }; 00065 00066 KLinkItemSelectionModel::KLinkItemSelectionModel(QAbstractItemModel *model, QItemSelectionModel *proxySelector, QObject *parent) 00067 : QItemSelectionModel(model, parent), 00068 d_ptr(new KLinkItemSelectionModelPrivate(this, model, proxySelector)) 00069 { 00070 connect(proxySelector, SIGNAL(selectionChanged(QItemSelection, QItemSelection)), SLOT(sourceSelectionChanged(QItemSelection, QItemSelection))); 00071 } 00072 00073 KLinkItemSelectionModel::~KLinkItemSelectionModel() 00074 { 00075 delete d_ptr; 00076 } 00077 00078 void KLinkItemSelectionModel::select(const QModelIndex &index, QItemSelectionModel::SelectionFlags command) 00079 { 00080 Q_D(KLinkItemSelectionModel); 00081 // When an item is removed, the current index is set to the top index in the model. 00082 // That causes a selectionChanged signal with a selection which we do not want. 00083 if (d->m_ignoreCurrentChanged) { 00084 return; 00085 } 00086 QItemSelectionModel::select(index, command); 00087 if (index.isValid()) 00088 d->m_linkedItemSelectionModel->select(d->m_indexMapper->mapSelectionLeftToRight(QItemSelection(index, index)), command); 00089 else { 00090 d->m_linkedItemSelectionModel->clearSelection(); 00091 } 00092 } 00093 00094 // QAbstractProxyModel::mapSelectionFromSource creates invalid ranges to we filter 00095 // those out manually in a loop. Hopefully fixed in Qt 4.7.2, so we ifdef it out. 00096 // http://qt.gitorious.org/qt/qt/merge_requests/2474 00097 // http://qt.gitorious.org/qt/qt/merge_requests/831 00098 #if QT_VERSION < 0x040702 00099 #define RANGE_FIX_HACK 00100 #endif 00101 00102 #ifdef RANGE_FIX_HACK 00103 static QItemSelection klink_removeInvalidRanges(const QItemSelection &selection) 00104 { 00105 QItemSelection result; 00106 Q_FOREACH(const QItemSelectionRange &range, selection) 00107 { 00108 if (!range.isValid()) 00109 continue; 00110 result << range; 00111 } 00112 return result; 00113 } 00114 #endif 00115 00116 void KLinkItemSelectionModel::select(const QItemSelection &selection, QItemSelectionModel::SelectionFlags command) 00117 { 00118 Q_D(KLinkItemSelectionModel); 00119 d->m_ignoreCurrentChanged = true; 00120 #ifdef RANGE_FIX_HACK 00121 QItemSelection _selection = klink_removeInvalidRanges(selection); 00122 #else 00123 QItemSelection _selection = selection; 00124 #endif 00125 QItemSelectionModel::select(_selection, command); 00126 Q_ASSERT(d->assertSelectionValid(_selection)); 00127 QItemSelection mappedSelection = d->m_indexMapper->mapSelectionLeftToRight(_selection); 00128 Q_ASSERT(d->assertSelectionValid(mappedSelection)); 00129 d->m_linkedItemSelectionModel->select(mappedSelection, command); 00130 d->m_ignoreCurrentChanged = false; 00131 } 00132 00133 void KLinkItemSelectionModelPrivate::sourceSelectionChanged(const QItemSelection& selected, const QItemSelection& deselected) 00134 { 00135 Q_Q(KLinkItemSelectionModel); 00136 #ifdef RANGE_FIX_HACK 00137 QItemSelection _selected = klink_removeInvalidRanges(selected); 00138 QItemSelection _deselected = klink_removeInvalidRanges(deselected); 00139 #else 00140 QItemSelection _selected = selected; 00141 QItemSelection _deselected = deselected; 00142 #endif 00143 Q_ASSERT(assertSelectionValid(_selected)); 00144 Q_ASSERT(assertSelectionValid(_deselected)); 00145 const QItemSelection mappedDeselection = m_indexMapper->mapSelectionRightToLeft(_deselected); 00146 const QItemSelection mappedSelection = m_indexMapper->mapSelectionRightToLeft(_selected); 00147 00148 q->QItemSelectionModel::select(mappedDeselection, QItemSelectionModel::Deselect); 00149 q->QItemSelectionModel::select(mappedSelection, QItemSelectionModel::Select); 00150 } 00151 00152 #include "klinkitemselectionmodel.moc"
KDE 4.6 API Reference