File indexing completed on 2025-01-05 04:47:09

0001 /*
0002     SPDX-FileCopyrightText: 2006-2007 Volker Krause <vkrause@kde.org>
0003     SPDX-FileCopyrightText: 2008 Stephen Kelly <steveire@gmail.com>
0004     SPDX-FileCopyrightText: 2009 Kevin Ottens <ervin@kde.org>
0005 
0006     SPDX-License-Identifier: LGPL-2.0-or-later
0007 */
0008 
0009 #include "entitylistview.h"
0010 
0011 #include "dragdropmanager_p.h"
0012 
0013 #include <QDragMoveEvent>
0014 #include <QMenu>
0015 
0016 #include "akonadiwidgets_debug.h"
0017 #include <KXMLGUIClient>
0018 #include <KXMLGUIFactory>
0019 
0020 #include "collection.h"
0021 #include "controlgui.h"
0022 #include "entitytreemodel.h"
0023 #include "item.h"
0024 #include "progressspinnerdelegate_p.h"
0025 
0026 using namespace Akonadi;
0027 
0028 /**
0029  * @internal
0030  */
0031 class Akonadi::EntityListViewPrivate
0032 {
0033 public:
0034     explicit EntityListViewPrivate(EntityListView *parent)
0035         : mParent(parent)
0036 #ifndef QT_NO_DRAGANDDROP
0037         , mDragDropManager(new DragDropManager(mParent))
0038 #endif
0039     {
0040     }
0041 
0042     void init();
0043     void itemClicked(const QModelIndex &index) const;
0044     void itemDoubleClicked(const QModelIndex &index) const;
0045     void itemCurrentChanged(const QModelIndex &index) const;
0046 
0047     EntityListView *const mParent;
0048     DragDropManager *mDragDropManager = nullptr;
0049     KXMLGUIClient *mXmlGuiClient = nullptr;
0050 };
0051 
0052 void EntityListViewPrivate::init()
0053 {
0054     mParent->setEditTriggers(QAbstractItemView::EditKeyPressed);
0055     mParent->setAcceptDrops(true);
0056 #ifndef QT_NO_DRAGANDDROP
0057     mParent->setDropIndicatorShown(true);
0058     mParent->setDragDropMode(EntityListView::DragDrop);
0059     mParent->setDragEnabled(true);
0060 #endif
0061     mParent->connect(mParent, &QAbstractItemView::clicked, mParent, [this](const auto &index) {
0062         itemClicked(index);
0063     });
0064     mParent->connect(mParent, &QAbstractItemView::doubleClicked, mParent, [this](const auto &index) {
0065         itemDoubleClicked(index);
0066     });
0067 
0068     auto animator = new DelegateAnimator(mParent);
0069     auto customDelegate = new ProgressSpinnerDelegate(animator, mParent);
0070     mParent->setItemDelegate(customDelegate);
0071 
0072     ControlGui::widgetNeedsAkonadi(mParent);
0073 }
0074 
0075 void EntityListViewPrivate::itemClicked(const QModelIndex &index) const
0076 {
0077     if (!index.isValid()) {
0078         return;
0079     }
0080 
0081     const auto collection = index.model()->data(index, EntityTreeModel::CollectionRole).value<Collection>();
0082     if (collection.isValid()) {
0083         Q_EMIT mParent->clicked(collection);
0084     } else {
0085         const Item item = index.model()->data(index, EntityTreeModel::ItemRole).value<Item>();
0086         if (item.isValid()) {
0087             Q_EMIT mParent->clicked(item);
0088         }
0089     }
0090 }
0091 
0092 void EntityListViewPrivate::itemDoubleClicked(const QModelIndex &index) const
0093 {
0094     if (!index.isValid()) {
0095         return;
0096     }
0097 
0098     const auto collection = index.model()->data(index, EntityTreeModel::CollectionRole).value<Collection>();
0099     if (collection.isValid()) {
0100         Q_EMIT mParent->doubleClicked(collection);
0101     } else {
0102         const Item item = index.model()->data(index, EntityTreeModel::ItemRole).value<Item>();
0103         if (item.isValid()) {
0104             Q_EMIT mParent->doubleClicked(item);
0105         }
0106     }
0107 }
0108 
0109 void EntityListViewPrivate::itemCurrentChanged(const QModelIndex &index) const
0110 {
0111     if (!index.isValid()) {
0112         return;
0113     }
0114 
0115     const auto collection = index.model()->data(index, EntityTreeModel::CollectionRole).value<Collection>();
0116     if (collection.isValid()) {
0117         Q_EMIT mParent->currentChanged(collection);
0118     } else {
0119         const Item item = index.model()->data(index, EntityTreeModel::ItemRole).value<Item>();
0120         if (item.isValid()) {
0121             Q_EMIT mParent->currentChanged(item);
0122         }
0123     }
0124 }
0125 
0126 EntityListView::EntityListView(QWidget *parent)
0127     : QListView(parent)
0128     , d(new EntityListViewPrivate(this))
0129 {
0130     setSelectionMode(QAbstractItemView::SingleSelection);
0131     d->init();
0132 }
0133 
0134 EntityListView::EntityListView(KXMLGUIClient *xmlGuiClient, QWidget *parent)
0135     : QListView(parent)
0136     , d(new EntityListViewPrivate(this))
0137 {
0138     d->mXmlGuiClient = xmlGuiClient;
0139     d->init();
0140 }
0141 
0142 EntityListView::~EntityListView()
0143 {
0144     delete d->mDragDropManager;
0145 }
0146 
0147 void EntityListView::setModel(QAbstractItemModel *model)
0148 {
0149     if (selectionModel()) {
0150         disconnect(selectionModel(), &QItemSelectionModel::currentChanged, this, nullptr);
0151     }
0152 
0153     QListView::setModel(model);
0154 
0155     connect(selectionModel(), &QItemSelectionModel::currentChanged, this, [this](const QModelIndex &index) {
0156         d->itemCurrentChanged(index);
0157     });
0158 }
0159 
0160 #ifndef QT_NO_DRAGANDDROP
0161 void EntityListView::dragMoveEvent(QDragMoveEvent *event)
0162 {
0163     if (d->mDragDropManager->dropAllowed(event)) {
0164         // All urls are supported. process the event.
0165         QListView::dragMoveEvent(event);
0166         return;
0167     }
0168 
0169     event->setDropAction(Qt::IgnoreAction);
0170 }
0171 
0172 void EntityListView::dropEvent(QDropEvent *event)
0173 {
0174     bool menuCanceled = false;
0175     if (d->mDragDropManager->processDropEvent(event, menuCanceled) && !menuCanceled) {
0176         QListView::dropEvent(event);
0177     }
0178 }
0179 #endif
0180 
0181 #ifndef QT_NO_CONTEXTMENU
0182 void EntityListView::contextMenuEvent(QContextMenuEvent *event)
0183 {
0184     if (!d->mXmlGuiClient) {
0185         return;
0186     }
0187 
0188     const QModelIndex index = indexAt(event->pos());
0189 
0190     QMenu *popup = nullptr;
0191 
0192     // check if the index under the cursor is a collection or item
0193     const auto collection = model()->data(index, EntityTreeModel::CollectionRole).value<Collection>();
0194     if (collection.isValid()) {
0195         popup = static_cast<QMenu *>(d->mXmlGuiClient->factory()->container(QStringLiteral("akonadi_favoriteview_contextmenu"), d->mXmlGuiClient));
0196     } else {
0197         popup =
0198             static_cast<QMenu *>(d->mXmlGuiClient->factory()->container(QStringLiteral("akonadi_favoriteview_emptyselection_contextmenu"), d->mXmlGuiClient));
0199     }
0200 
0201     if (popup) {
0202         popup->exec(event->globalPos());
0203     }
0204 }
0205 #endif
0206 
0207 void EntityListView::setXmlGuiClient(KXMLGUIClient *xmlGuiClient)
0208 {
0209     d->mXmlGuiClient = xmlGuiClient;
0210 }
0211 
0212 KXMLGUIClient *EntityListView::xmlGuiClient() const
0213 {
0214     return d->mXmlGuiClient;
0215 }
0216 
0217 #ifndef QT_NO_DRAGANDDROP
0218 void EntityListView::startDrag(Qt::DropActions supportedActions)
0219 {
0220     d->mDragDropManager->startDrag(supportedActions);
0221 }
0222 #endif
0223 
0224 void EntityListView::setDropActionMenuEnabled(bool enabled)
0225 {
0226 #ifndef QT_NO_DRAGANDDROP
0227     d->mDragDropManager->setShowDropActionMenu(enabled);
0228 #endif
0229 }
0230 
0231 bool EntityListView::isDropActionMenuEnabled() const
0232 {
0233 #ifndef QT_NO_DRAGANDDROP
0234     return d->mDragDropManager->showDropActionMenu();
0235 #else
0236     return false;
0237 #endif
0238 }
0239 
0240 #include "moc_entitylistview.cpp"