File indexing completed on 2024-04-21 03:56: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 #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"