File indexing completed on 2025-02-09 07:11:32

0001 /*
0002     This file is part of the Kasten Framework, made within the KDE community.
0003 
0004     SPDX-FileCopyrightText: 2011-2012 Friedrich W. H. Kossebau <kossebau@kde.org>
0005 
0006     SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0007 */
0008 
0009 #include "singleviewwindow_p.hpp"
0010 
0011 // this lib
0012 #include "singleviewarea.hpp"
0013 #include <abstractxmlguicontroller.hpp>
0014 #include <toolviewdockwidget.hpp>
0015 #include <abstracttoolview.hpp>
0016 #include <abstractview.hpp>
0017 // Kasten core
0018 #include <Kasten/AbstractTool>
0019 #include <Kasten/AbstractModelSynchronizer>
0020 // Std
0021 #include <utility>
0022 
0023 namespace Kasten {
0024 
0025 SingleViewWindowPrivate::SingleViewWindowPrivate(SingleViewWindow* parent,
0026                                                  AbstractView* view)
0027     : q_ptr(parent)
0028     , mViewArea(new SingleViewArea())
0029 {
0030     parent->setCentralWidget(mViewArea->widget());
0031 
0032     setView(view);
0033 }
0034 
0035 SingleViewWindowPrivate::~SingleViewWindowPrivate()
0036 {
0037     // we have to explicitly reset any inline tool view before first deleting all tools
0038     // and then the view area, because on destruction of the inline tool view it
0039     // operates on the tool, which then has been no longer ->crash
0040     // The other option would be to first delete the view, but for reasons if do not
0041     // remember currently I prefer the destruction in this order
0042     // TODO: make this call unneeded
0043     mViewArea->setCurrentToolInlineView(nullptr);
0044 
0045     qDeleteAll(mControllers);
0046     qDeleteAll(mDockWidgets);
0047     qDeleteAll(mTools);
0048 
0049     delete mViewArea;
0050 }
0051 
0052 void SingleViewWindowPrivate::setView(AbstractView* view)
0053 {
0054     Q_Q(SingleViewWindow);
0055 
0056     if (mView == view) {
0057         return;
0058     }
0059 
0060     if (mView) {
0061         mView->disconnect(q);
0062     }
0063 
0064     // TODO: what to do with the old one if existing?
0065     mView = view;
0066     mViewArea->setView(view);
0067 
0068     for (AbstractXmlGuiController* controller : std::as_const(mControllers)) {
0069         controller->setTargetModel(view);
0070     }
0071 
0072     for (ToolViewDockWidget* dockWidget : std::as_const(mDockWidgets)) {
0073         if (dockWidget->isShown()) {
0074             dockWidget->toolView()->tool()->setTargetModel(view);
0075         }
0076     }
0077 
0078     AbstractDocument* oldDocument = mDocument;
0079     mDocument = view ? view->findBaseModel<AbstractDocument*>() : nullptr;
0080     const bool isNewDocument = (mDocument != oldDocument);
0081 
0082     AbstractModelSynchronizer* oldSynchronizer = mSynchronizer;
0083     mSynchronizer = mDocument ? mDocument->synchronizer() : nullptr;
0084     const bool isNewSynchronizer = (mSynchronizer != oldSynchronizer);
0085 
0086     if (oldSynchronizer) {
0087         if (isNewSynchronizer) {
0088             oldSynchronizer->disconnect(q);
0089         }
0090     } else {
0091         if (oldDocument && isNewDocument) {
0092             oldDocument->disconnect(q);
0093         }
0094     }
0095 
0096     const QString title = view ? view->title() : QString();
0097     const bool hasChanges =
0098         mSynchronizer ? (mSynchronizer->localSyncState() == LocalHasChanges) :
0099         mDocument ?     mDocument->contentFlags().testFlag(ContentHasUnstoredChanges) :
0100                         false;
0101     q->setCaption(title, hasChanges);
0102 
0103     if (view) {
0104         QObject::connect(view, &AbstractModel::titleChanged,
0105                          q, [&](const QString& Title) { onTitleChanged(Title); });
0106     }
0107 
0108     if (mSynchronizer) {
0109         if (isNewSynchronizer) {
0110             QObject::connect(mSynchronizer, &AbstractModelSynchronizer::localSyncStateChanged,
0111                              q, [&](LocalSyncState localSyncState) { onLocalSyncStateChanged(localSyncState); });
0112             QObject::connect(mSynchronizer, &QObject::destroyed,
0113                              q, [&](QObject* object) { onSynchronizerDeleted(object); });
0114         }
0115     } else if (mDocument) {
0116         if (isNewDocument) {
0117             QObject::connect(mDocument, &AbstractDocument::contentFlagsChanged,
0118                              q, [&](ContentFlags contentFlags) { onContentFlagsChanged(contentFlags); });
0119         }
0120     }
0121 }
0122 
0123 void SingleViewWindowPrivate::addXmlGuiController(AbstractXmlGuiController* controller)
0124 {
0125     mControllers.append(controller);
0126 }
0127 
0128 void SingleViewWindowPrivate::addTool(AbstractToolView* toolView)
0129 {
0130     Q_Q(SingleViewWindow);
0131 
0132     auto* dockWidget = new ToolViewDockWidget(toolView, q);
0133     // TODO: where to set the initial area?
0134     q->addDockWidget(Qt::RightDockWidgetArea, dockWidget);
0135 
0136     mTools.append(toolView->tool());
0137     mDockWidgets.append(dockWidget);
0138 
0139     if (dockWidget->isVisible() && mView) {
0140         toolView->tool()->setTargetModel(mView);
0141     }
0142 
0143     QObject::connect(dockWidget, &QDockWidget::visibilityChanged,
0144                      q, [&](bool visible) { onToolVisibilityChanged(visible); });
0145 }
0146 
0147 void SingleViewWindowPrivate::onTitleChanged(const QString& newTitle)
0148 {
0149     Q_Q(SingleViewWindow);
0150 
0151     if (mView) {
0152         auto* document = mView->findBaseModel<AbstractDocument*>();
0153         AbstractModelSynchronizer* synchronizer = document->synchronizer();
0154         const bool hasChanges =
0155             synchronizer ? (synchronizer->localSyncState() == LocalHasChanges) :
0156             document ?     document->contentFlags().testFlag(ContentHasUnstoredChanges) :
0157                            false;
0158         q->setCaption(newTitle, hasChanges);
0159     }
0160 }
0161 
0162 void SingleViewWindowPrivate::onContentFlagsChanged(ContentFlags contentFlags)
0163 {
0164     Q_Q(SingleViewWindow);
0165 
0166     if (mView) {
0167         const bool hasChanges = (contentFlags & ContentHasUnstoredChanges);
0168         q->setCaption(mView->title(), hasChanges);
0169     }
0170 }
0171 
0172 void SingleViewWindowPrivate::onLocalSyncStateChanged(LocalSyncState newState)
0173 {
0174     Q_Q(SingleViewWindow);
0175 
0176     if (mView) {
0177         const bool hasChanges = (newState == LocalHasChanges);
0178         q->setCaption(mView->title(), hasChanges);
0179     }
0180 }
0181 
0182 void SingleViewWindowPrivate::onSynchronizerDeleted(QObject* synchronizer)
0183 {
0184     Q_Q(SingleViewWindow);
0185 
0186     if (synchronizer != mSynchronizer) {
0187         return;
0188     }
0189 
0190     mSynchronizer = nullptr;
0191 
0192     // switch to document state
0193     QObject::connect(mDocument, &AbstractDocument::contentFlagsChanged,
0194                      q, [&](ContentFlags contentFlags) { onContentFlagsChanged(contentFlags); });
0195 
0196     onContentFlagsChanged(mDocument->contentFlags());
0197 }
0198 
0199 void SingleViewWindowPrivate::onToolVisibilityChanged(bool isVisible)
0200 {
0201     Q_Q(SingleViewWindow);
0202 
0203     auto* dockWidget = qobject_cast<ToolViewDockWidget*>(q->sender());
0204     if (dockWidget) {
0205         AbstractView* view = isVisible ? mView : nullptr;
0206         dockWidget->toolView()->tool()->setTargetModel(view);
0207     }
0208 }
0209 
0210 }