File indexing completed on 2023-09-24 04:09:49
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 #include "breadcrumbnavigationwidget.h" 0009 0010 #include "dynamictreemodel.h" 0011 #include "dynamictreewidget.h" 0012 0013 #include <QHBoxLayout> 0014 #include <QListView> 0015 #include <QSplitter> 0016 #include <QTreeView> 0017 0018 #include "kbreadcrumbselectionmodel.h" 0019 #include "kselectionproxymodel.h" 0020 0021 #define SON(object) object->setObjectName(QStringLiteral(#object)) 0022 0023 CurrentItemLabel::CurrentItemLabel(QAbstractItemModel *model, QWidget *parent, Qt::WindowFlags f) 0024 : QLabel(parent, f) 0025 , m_model(model) 0026 { 0027 connect(model, SIGNAL(dataChanged(QModelIndex, QModelIndex)), SLOT(dataChanged(QModelIndex, QModelIndex))); 0028 connect(model, SIGNAL(rowsInserted(QModelIndex, int, int)), SLOT(rowsInserted(QModelIndex, int, int))); 0029 connect(model, SIGNAL(rowsRemoved(QModelIndex, int, int)), SLOT(rowsRemoved(QModelIndex, int, int))); 0030 connect(model, SIGNAL(modelReset()), SLOT(modelReset())); 0031 0032 if (!m_model->hasChildren()) { 0033 setText(QStringLiteral("No selection")); 0034 } 0035 } 0036 0037 void CurrentItemLabel::dataChanged(const QModelIndex &, const QModelIndex &) 0038 { 0039 setText(m_model->index(0, 0).data().toString()); 0040 } 0041 0042 void CurrentItemLabel::rowsInserted(const QModelIndex &, int, int) 0043 { 0044 setText(m_model->index(0, 0).data().toString()); 0045 } 0046 0047 void CurrentItemLabel::rowsRemoved(const QModelIndex &, int, int) 0048 { 0049 if (!m_model->hasChildren()) { 0050 setText(QStringLiteral("No selection")); 0051 return; 0052 } 0053 setText(m_model->index(0, 0).data().toString()); 0054 } 0055 0056 void CurrentItemLabel::modelReset() 0057 { 0058 if (!m_model->hasChildren()) { 0059 setText(QStringLiteral("No selection")); 0060 } 0061 setText(m_model->index(0, 0).data().toString()); 0062 } 0063 0064 KBreadcrumbNavigationProxyModel::KBreadcrumbNavigationProxyModel(QItemSelectionModel *selectionModel, QObject *parent) 0065 : KSelectionProxyModel(selectionModel, parent) 0066 { 0067 } 0068 0069 QVariant KBreadcrumbNavigationProxyModel::data(const QModelIndex &index, int role) const 0070 { 0071 if (rowCount() > 2 && index.row() == 0 && role == Qt::DisplayRole) { 0072 QModelIndex sourceIndex = mapToSource(index); 0073 QStringList dataList; 0074 while (sourceIndex.isValid()) { 0075 dataList.prepend(sourceIndex.data().toString()); 0076 sourceIndex = sourceIndex.parent(); 0077 } 0078 return dataList.join(QLatin1String(" > ")); 0079 } 0080 return KSelectionProxyModel::data(index, role); 0081 } 0082 0083 void KBreadcrumbNavigationProxyModel::setShowHiddenAscendantData(bool showHiddenAscendantData) 0084 { 0085 m_showHiddenAscendantData = showHiddenAscendantData; 0086 } 0087 0088 bool KBreadcrumbNavigationProxyModel::showHiddenAscendantData() const 0089 { 0090 return m_showHiddenAscendantData; 0091 } 0092 0093 KNavigatingProxyModel::KNavigatingProxyModel(QItemSelectionModel *selectionModel, QObject *parent) 0094 : KSelectionProxyModel(selectionModel, parent) 0095 , m_selectionModel(selectionModel) 0096 { 0097 } 0098 0099 void KNavigatingProxyModel::setSourceModel(QAbstractItemModel *sourceModel) 0100 { 0101 connect(m_selectionModel, SIGNAL(selectionChanged(QItemSelection, QItemSelection)), SLOT(navigationSelectionChanged(QItemSelection, QItemSelection))); 0102 0103 KSelectionProxyModel::setSourceModel(sourceModel); 0104 updateNavigation(); 0105 } 0106 0107 void KNavigatingProxyModel::navigationSelectionChanged(const QItemSelection &, const QItemSelection &) 0108 { 0109 updateNavigation(); 0110 } 0111 0112 void KNavigatingProxyModel::updateNavigation() 0113 { 0114 if (!sourceModel()) { 0115 return; 0116 } 0117 0118 if (m_selectionModel->selection().isEmpty()) { 0119 setFilterBehavior(KSelectionProxyModel::ExactSelection); 0120 QModelIndex top = sourceModel()->index(0, 0); 0121 QModelIndex bottom = sourceModel()->index(sourceModel()->rowCount() - 1, 0); 0122 0123 disconnect(m_selectionModel, 0124 SIGNAL(selectionChanged(QItemSelection, QItemSelection)), 0125 this, 0126 SLOT(navigationSelectionChanged(QItemSelection, QItemSelection))); 0127 m_selectionModel->select(QItemSelection(top, bottom), QItemSelectionModel::Select); 0128 connect(m_selectionModel, SIGNAL(selectionChanged(QItemSelection, QItemSelection)), SLOT(navigationSelectionChanged(QItemSelection, QItemSelection))); 0129 } else if (filterBehavior() != KSelectionProxyModel::ChildrenOfExactSelection) { 0130 setFilterBehavior(KSelectionProxyModel::ChildrenOfExactSelection); 0131 } 0132 } 0133 0134 void KNavigatingProxyModel::modelReset() 0135 { 0136 updateNavigation(); 0137 } 0138 0139 QVariant KNavigatingProxyModel::data(const QModelIndex &index, int role) const 0140 { 0141 if (role == Qt::DisplayRole && sourceModel()->hasChildren(mapToSource(index))) { 0142 return QString("+ " + KSelectionProxyModel::data(index, role).toString()); 0143 } 0144 return KSelectionProxyModel::data(index, role); 0145 } 0146 0147 KForwardingItemSelectionModel::KForwardingItemSelectionModel(QAbstractItemModel *model, QItemSelectionModel *selectionModel, QObject *parent) 0148 : QItemSelectionModel(model, parent) 0149 , m_selectionModel(selectionModel) 0150 , m_direction(Forward) 0151 { 0152 Q_ASSERT(model == selectionModel->model()); 0153 connect(selectionModel, SIGNAL(selectionChanged(QItemSelection, QItemSelection)), SLOT(navigationSelectionChanged(QItemSelection, QItemSelection))); 0154 } 0155 0156 KForwardingItemSelectionModel::KForwardingItemSelectionModel(QAbstractItemModel *model, 0157 QItemSelectionModel *selectionModel, 0158 Direction direction, 0159 QObject *parent) 0160 : QItemSelectionModel(model, parent) 0161 , m_selectionModel(selectionModel) 0162 , m_direction(direction) 0163 { 0164 Q_ASSERT(model == selectionModel->model()); 0165 if (m_direction == Forward) { 0166 connect(selectionModel, SIGNAL(selectionChanged(QItemSelection, QItemSelection)), SLOT(navigationSelectionChanged(QItemSelection, QItemSelection))); 0167 } 0168 } 0169 0170 void KForwardingItemSelectionModel::select(const QModelIndex &index, QItemSelectionModel::SelectionFlags command) 0171 { 0172 if (m_direction == Reverse) { 0173 m_selectionModel->select(index, command); 0174 } else { 0175 QItemSelectionModel::select(index, command); 0176 } 0177 } 0178 0179 void KForwardingItemSelectionModel::select(const QItemSelection &selection, QItemSelectionModel::SelectionFlags command) 0180 { 0181 if (m_direction == Reverse) { 0182 m_selectionModel->select(selection, command); 0183 } else { 0184 QItemSelectionModel::select(selection, command); 0185 } 0186 } 0187 0188 void KForwardingItemSelectionModel::navigationSelectionChanged(const QItemSelection &selected, const QItemSelection &) 0189 { 0190 select(selected, ClearAndSelect); 0191 } 0192 0193 BreadcrumbNavigationWidget::BreadcrumbNavigationWidget(QWidget *parent, Qt::WindowFlags f) 0194 : QWidget(parent, f) 0195 { 0196 DynamicTreeModel *rootModel = new DynamicTreeModel(this); 0197 QSplitter *splitter = new QSplitter(this); 0198 QHBoxLayout *layout = new QHBoxLayout(this); 0199 layout->addWidget(splitter); 0200 0201 DynamicTreeWidget *dynamicTree = new DynamicTreeWidget(rootModel, splitter); 0202 dynamicTree->treeView()->setSelectionMode(QAbstractItemView::SingleSelection); 0203 dynamicTree->setInitialTree( 0204 QLatin1String("- 1" 0205 "- - 2" 0206 "- - 2" 0207 "- - - 3" 0208 "- - - - 4" 0209 "- - - - - 5" 0210 "- - 2" 0211 "- 6" 0212 "- 6" 0213 "- 6" 0214 "- - 7" 0215 "- - - 8" 0216 "- - - 8" 0217 "- - - - 9" 0218 "- - - - - 10" 0219 "- - - 8" 0220 "- - - 8" 0221 "- - 8" 0222 "- 16" 0223 "- - 17" 0224 "- - - 18" 0225 "- - - - 19" 0226 "- - - - - 20")); 0227 0228 QList<QItemSelectionModel *> selectionModelList; 0229 0230 QSplitter *vSplitter = new QSplitter(Qt::Vertical, splitter); 0231 0232 QItemSelectionModel *rootSelectionModel = new QItemSelectionModel(rootModel, this); 0233 SON(rootSelectionModel); 0234 0235 dynamicTree->treeView()->setSelectionModel(rootSelectionModel); 0236 0237 KBreadcrumbSelectionModel *breadcrumbOnlyProxySelector2 = 0238 new KBreadcrumbSelectionModel(rootSelectionModel, KBreadcrumbSelectionModel::MakeBreadcrumbSelectionInOther, this); 0239 SON(breadcrumbOnlyProxySelector2); 0240 breadcrumbOnlyProxySelector2->setActualSelectionIncluded(false); 0241 0242 KBreadcrumbNavigationProxyModel *breadcrumbNavigationModel = new KBreadcrumbNavigationProxyModel(breadcrumbOnlyProxySelector2, this); 0243 SON(breadcrumbNavigationModel); 0244 breadcrumbNavigationModel->setSourceModel(rootModel); 0245 breadcrumbNavigationModel->setFilterBehavior(KSelectionProxyModel::ExactSelection); 0246 0247 QListView *breadcrumbView = new QListView(vSplitter); 0248 // SON(breadcrumbNavigationModel); 0249 breadcrumbView->setModel(breadcrumbNavigationModel); 0250 0251 // This shouldn't operate on rootSelectionModel. It should operate on oneway instead? 0252 KLinkItemSelectionModel *breadcrumbViewSelectionModel = new KLinkItemSelectionModel(breadcrumbNavigationModel, rootSelectionModel, this); 0253 SON(breadcrumbViewSelectionModel); 0254 0255 KForwardingItemSelectionModel *oneway2 = 0256 new KForwardingItemSelectionModel(breadcrumbNavigationModel, breadcrumbViewSelectionModel, KForwardingItemSelectionModel::Reverse); 0257 SON(oneway2); 0258 0259 breadcrumbView->setSelectionModel(oneway2); 0260 0261 KSelectionProxyModel *currentItemSelectionModel = new KSelectionProxyModel(rootSelectionModel, this); 0262 currentItemSelectionModel->setFilterBehavior(KSelectionProxyModel::ExactSelection); 0263 currentItemSelectionModel->setSourceModel(rootModel); 0264 SON(currentItemSelectionModel); 0265 0266 new CurrentItemLabel(currentItemSelectionModel, vSplitter); 0267 0268 QListView *selectionView = new QListView(vSplitter); 0269 0270 // Need a one-way connection from rootSelectionModel to rootSelectionModel2 0271 0272 KForwardingItemSelectionModel *oneway = new KForwardingItemSelectionModel(rootModel, rootSelectionModel); 0273 0274 KNavigatingProxyModel *navigatingProxyModel = new KNavigatingProxyModel(oneway, this); 0275 SON(navigatingProxyModel); 0276 navigatingProxyModel->setSourceModel(rootModel); 0277 selectionView->setModel(navigatingProxyModel); 0278 0279 KLinkItemSelectionModel *selectedChildrenSelectionModel = new KLinkItemSelectionModel(navigatingProxyModel, rootSelectionModel, this); 0280 0281 selectionView->setSelectionModel(selectedChildrenSelectionModel); 0282 } 0283 0284 #include "moc_breadcrumbnavigationwidget.cpp"