File indexing completed on 2025-01-19 04:56:40

0001 /*
0002  * SPDX-FileCopyrightText: 2014 Kevin Ottens <ervin@kde.org>
0003  * SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0004  */
0005 
0006 
0007 #include "applicationcomponents.h"
0008 
0009 #include <memory>
0010 
0011 #include <QBoxLayout>
0012 #include <QLabel>
0013 #include <QMimeData>
0014 #include <QVariant>
0015 #include <QWidget>
0016 #include <QWidgetAction>
0017 
0018 #include <KLocalizedString>
0019 #include <KWindowSystem>
0020 
0021 #include "availablepagesview.h"
0022 #include "availablesourcesview.h"
0023 #include "editorview.h"
0024 #include "pageview.h"
0025 #include "pageviewerrorhandler.h"
0026 #include "quickselectdialog.h"
0027 #include "runningtaskwidget.h"
0028 
0029 #include "presentation/runningtaskmodelinterface.h"
0030 
0031 using namespace Widgets;
0032 
0033 ApplicationComponents::ApplicationComponents(QWidget *parent)
0034     : QObject(parent),
0035       m_parent(parent),
0036       m_availableSourcesView(nullptr),
0037       m_availablePagesView(nullptr),
0038       m_pageView(nullptr),
0039       m_editorView(nullptr),
0040       m_errorHandler(new PageViewErrorHandler)
0041 {
0042     m_quickSelectDialogFactory = [] (QWidget *parent) {
0043         return QuickSelectDialogPtr(new QuickSelectDialog(parent));
0044     };
0045 
0046     auto moveItemAction = new QAction(this);
0047     moveItemAction->setObjectName(QLatin1StringView("moveItemAction"));
0048     moveItemAction->setText(i18n("Move Task"));
0049     moveItemAction->setShortcut(Qt::Key_M);
0050     connect(moveItemAction, &QAction::triggered, this, &ApplicationComponents::onMoveItemsRequested);
0051 
0052     m_actions.insert(QStringLiteral("page_view_move"), moveItemAction);
0053 }
0054 
0055 ApplicationComponents::~ApplicationComponents()
0056 {
0057     setModel({});
0058 }
0059 
0060 QHash<QString, QAction*> ApplicationComponents::globalActions() const
0061 {
0062     auto actions = QHash<QString, QAction*>();
0063     actions.insert(availableSourcesView()->globalActions());
0064     actions.insert(availablePagesView()->globalActions());
0065     actions.insert(pageView()->globalActions());
0066     actions.insert(m_actions);
0067 
0068     return actions;
0069 }
0070 
0071 QObjectPtr ApplicationComponents::model() const
0072 {
0073     return m_model;
0074 }
0075 
0076 AvailableSourcesView *ApplicationComponents::availableSourcesView() const
0077 {
0078     if (!m_availableSourcesView) {
0079         auto view = new AvailableSourcesView(m_parent);
0080         if (m_model) {
0081             view->setModel(m_model->property("availableSources").value<QObject*>());
0082         }
0083 
0084         ApplicationComponents *self = const_cast<ApplicationComponents*>(this);
0085         self->m_availableSourcesView = view;
0086     }
0087 
0088     return m_availableSourcesView;
0089 }
0090 
0091 AvailablePagesView *ApplicationComponents::availablePagesView() const
0092 {
0093     if (!m_availablePagesView) {
0094         auto availablePagesView = new AvailablePagesView(m_parent);
0095         if (m_model) {
0096             availablePagesView->setModel(m_model->property("availablePages").value<QObject*>());
0097             auto availableSources = m_model->property("availableSources").value<QObject*>();
0098             if (availableSources)
0099                 availablePagesView->setProjectSourcesModel(availableSources->property("sourceListModel").value<QAbstractItemModel*>());
0100         }
0101 
0102         ApplicationComponents *self = const_cast<ApplicationComponents*>(this);
0103         self->m_availablePagesView = availablePagesView;
0104 
0105         connect(self->m_availablePagesView, &AvailablePagesView::currentPageChanged, self, &ApplicationComponents::onCurrentPageChanged);
0106     }
0107 
0108     return m_availablePagesView;
0109 }
0110 
0111 PageView *ApplicationComponents::pageView() const
0112 {
0113     if (!m_pageView) {
0114         auto pageView = new PageView(m_parent);
0115         if (m_model) {
0116             pageView->setModel(m_model->property("currentPage").value<QObject*>());
0117             pageView->setRunningTaskModel(m_model->property("runningTaskModel").value<Presentation::RunningTaskModelInterface*>());
0118             connect(m_model.data(), SIGNAL(currentPageChanged(QObject*)),
0119                     pageView, SLOT(setModel(QObject*)));
0120         }
0121 
0122         ApplicationComponents *self = const_cast<ApplicationComponents*>(this);
0123         self->m_pageView = pageView;
0124         self->m_errorHandler->setPageView(pageView);
0125 
0126         connect(self->m_pageView, &PageView::currentTaskChanged, self, &ApplicationComponents::onCurrentTaskChanged);
0127     }
0128 
0129     return m_pageView;
0130 }
0131 
0132 EditorView *ApplicationComponents::editorView() const
0133 {
0134     if (!m_editorView) {
0135         auto editorView = new EditorView(m_parent);
0136         if (m_model) {
0137             editorView->setModel(m_model->property("editor").value<QObject*>());
0138         }
0139 
0140         auto self = const_cast<ApplicationComponents*>(this);
0141         self->m_editorView = editorView;
0142     }
0143 
0144     return m_editorView;
0145 }
0146 
0147 RunningTaskWidget *ApplicationComponents::runningTaskView() const
0148 {
0149     if (!m_runningTaskView) {
0150         auto runningTaskView = new RunningTaskWidget(m_parent);
0151         if (m_model) {
0152             runningTaskView->setModel(m_model->property("runningTaskModel").value<Presentation::RunningTaskModelInterface*>());
0153         }
0154 
0155         auto self = const_cast<ApplicationComponents*>(this);
0156         self->m_runningTaskView = runningTaskView;
0157     }
0158 
0159     return m_runningTaskView;
0160 }
0161 
0162 ApplicationComponents::QuickSelectDialogFactory ApplicationComponents::quickSelectDialogFactory() const
0163 {
0164     return m_quickSelectDialogFactory;
0165 }
0166 
0167 void ApplicationComponents::setModel(const QObjectPtr &model)
0168 {
0169     if (m_model == model)
0170         return;
0171 
0172     if (m_model) {
0173         if (m_pageView)
0174             disconnect(m_model.data(), 0, m_pageView, 0);
0175         m_model->setProperty("errorHandler", 0);
0176     }
0177 
0178     // Delay deletion of the old model until we're out of scope
0179     auto tmp = m_model;
0180     Q_UNUSED(tmp);
0181 
0182     m_model = model;
0183 
0184     if (m_model) {
0185         m_model->setProperty("errorHandler", QVariant::fromValue(errorHandler()));
0186     }
0187 
0188     if (m_availableSourcesView) {
0189         m_availableSourcesView->setModel(m_model ? m_model->property("availableSources").value<QObject*>()
0190                                                  : nullptr);
0191     }
0192 
0193     if (m_availablePagesView) {
0194         m_availablePagesView->setModel(m_model ? m_model->property("availablePages").value<QObject*>()
0195                                                : nullptr);
0196         m_availablePagesView->setProjectSourcesModel(m_model ? m_model->property("dataSourcesModel").value<QAbstractItemModel*>()
0197                                                              : nullptr);
0198     }
0199 
0200     if (m_pageView) {
0201         m_pageView->setModel(m_model ? m_model->property("currentPage").value<QObject*>()
0202                                      : nullptr);
0203         m_pageView->setRunningTaskModel(m_model ? m_model->property("runningTaskModel").value<Presentation::RunningTaskModelInterface*>()
0204                                                 : nullptr);
0205 
0206         if (m_model) {
0207             connect(m_model.data(), SIGNAL(currentPageChanged(QObject*)),
0208                     m_pageView, SLOT(setModel(QObject*)));
0209         }
0210     }
0211 
0212     if (m_editorView) {
0213         m_editorView->setModel(m_model ? m_model->property("editor").value<QObject*>()
0214                                        : nullptr);
0215     }
0216 
0217     if (m_runningTaskView) {
0218         m_runningTaskView->setModel(m_model ? m_model->property("runningTaskModel").value<Presentation::RunningTaskModelInterface*>()
0219                                             : nullptr);
0220     } else if (m_model) {
0221         if (!KWindowSystem::isPlatformWayland()) {
0222             runningTaskView(); // We got a model so make sure this view exists now
0223         }
0224     }
0225 }
0226 
0227 void ApplicationComponents::setQuickSelectDialogFactory(const QuickSelectDialogFactory &factory)
0228 {
0229     m_quickSelectDialogFactory = factory;
0230 }
0231 
0232 void ApplicationComponents::onCurrentPageChanged(QObject *page)
0233 {
0234     if (!m_model)
0235         return;
0236 
0237     m_model->setProperty("currentPage", QVariant::fromValue(page));
0238 
0239     QObject *editorModel = m_model->property("editor").value<QObject*>();
0240     if (editorModel)
0241         editorModel->setProperty("task", QVariant::fromValue(Domain::Task::Ptr()));
0242 }
0243 
0244 void ApplicationComponents::onCurrentTaskChanged(const Domain::Task::Ptr &task)
0245 {
0246     if (!m_model)
0247         return;
0248 
0249     auto editorModel = m_model->property("editor").value<QObject*>();
0250     if (editorModel)
0251         editorModel->setProperty("task", QVariant::fromValue(task));
0252 }
0253 
0254 void ApplicationComponents::onMoveItemsRequested()
0255 {
0256     if (!m_model)
0257         return;
0258 
0259     if (m_pageView->selectedIndexes().size() == 0)
0260         return;
0261 
0262     auto pageListModel = m_availablePagesView->model()->property("pageListModel").value<QAbstractItemModel*>();
0263     Q_ASSERT(pageListModel);
0264 
0265     QuickSelectDialogInterface::Ptr dlg = m_quickSelectDialogFactory(m_pageView);
0266     dlg->setModel(pageListModel);
0267     if (dlg->exec() == QDialog::Accepted)
0268         moveItems(dlg->selectedIndex(), m_pageView->selectedIndexes());
0269 }
0270 
0271 Presentation::ErrorHandler *ApplicationComponents::errorHandler() const
0272 {
0273     return m_errorHandler.data();
0274 }
0275 
0276 void ApplicationComponents::moveItems(const QModelIndex &destination, const QModelIndexList &droppedItems)
0277 {
0278     Q_ASSERT(destination.isValid());
0279     Q_ASSERT(!droppedItems.isEmpty());
0280 
0281     auto centralListModel = droppedItems.first().model();
0282     auto availablePagesModel = const_cast<QAbstractItemModel*>(destination.model());
0283 
0284     // drag
0285     const auto data = std::unique_ptr<QMimeData>(centralListModel->mimeData(droppedItems));
0286 
0287     // drop
0288     availablePagesModel->dropMimeData(data.get(), Qt::MoveAction, -1, -1, destination);
0289 }
0290 
0291 
0292 #include "moc_applicationcomponents.cpp"