File indexing completed on 2024-06-02 06:03:22

0001 /*
0002     This file is part of the Kasten Framework, made within the KDE community.
0003 
0004     SPDX-FileCopyrightText: 2009 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 "multiviewareas_p.hpp"
0010 
0011 // lib
0012 #include "viewbox.hpp"
0013 #include "toolinlineviewwidget.hpp"
0014 #include <abstracttoolinlineview.hpp>
0015 #include <abstractview.hpp>
0016 // Kasten core
0017 #include <Kasten/AbstractDocument>
0018 
0019 // Qt
0020 #include <QMimeData>
0021 // Std
0022 #include <utility>
0023 
0024 namespace Kasten {
0025 // TODO: catch area focus change!
0026 MultiViewAreasPrivate::MultiViewAreasPrivate(MultiViewAreas* parent)
0027     : AbstractGroupedViewsPrivate(parent)
0028 {
0029 }
0030 
0031 MultiViewAreasPrivate::~MultiViewAreasPrivate()
0032 {
0033     qDeleteAll(mViewAreaList);
0034     delete mMainSplitter;
0035 }
0036 
0037 void MultiViewAreasPrivate::init()
0038 {
0039     Q_Q(MultiViewAreas);
0040 
0041     mMainSplitter = new QSplitter();
0042 
0043     // create start view area
0044     auto* viewArea = new TabbedViews();
0045     QObject::connect(viewArea, &AbstractViewArea::focusChanged,
0046                      q, [&](bool hasFocus) { onViewAreaFocusChanged(hasFocus); });
0047     QObject::connect(viewArea, &AbstractGroupedViews::viewFocusChanged,
0048                      q, &AbstractGroupedViews::viewFocusChanged);
0049     QObject::connect(viewArea, &AbstractGroupedViews::closeRequest,
0050                      q, &AbstractGroupedViews::closeRequest);
0051     QObject::connect(viewArea, &AbstractGroupedViews::removing,
0052                      q, [&]() { onViewsRemoved(); });
0053 
0054     QObject::connect(viewArea, &TabbedViews::contextMenuRequested,
0055                      q, [&](AbstractView* view, QPoint pos) { onContextMenuRequested(view, pos); });
0056     QObject::connect(viewArea, &TabbedViews::dataOffered,
0057                      q, &MultiViewAreas::dataOffered);
0058     QObject::connect(viewArea, &TabbedViews::dataDropped,
0059                      q, &MultiViewAreas::dataDropped);
0060     QObject::connect(viewArea, &TabbedViews::newDocumentRequested,
0061                      q, &MultiViewAreas::newDocumentRequested);
0062 
0063     mViewAreaList.append(viewArea);
0064     mCurrentViewArea = viewArea;
0065 
0066     mMainSplitter->addWidget(viewArea->widget());
0067 }
0068 
0069 AbstractViewArea* MultiViewAreasPrivate::splitViewArea(AbstractViewArea* _viewArea, Qt::Orientation orientation)
0070 {
0071     Q_Q(MultiViewAreas);
0072 
0073     auto* firstViewArea = static_cast<TabbedViews*>(_viewArea);
0074     QWidget* firstViewAreaWidget = firstViewArea->widget();
0075     auto* baseSplitter = static_cast<QSplitter*>(firstViewAreaWidget->parentWidget());
0076 
0077     QSplitter* splitter;
0078     if (baseSplitter->count() == 1) { // only valid with mMainSplitter
0079         splitter = baseSplitter;
0080     } else {
0081         const QList<int> baseSplitterSizes = baseSplitter->sizes();
0082         const int index = baseSplitter->indexOf(firstViewAreaWidget);
0083         splitter = new QSplitter(baseSplitter);
0084         baseSplitter->insertWidget(index, splitter);
0085         splitter->addWidget(firstViewAreaWidget);
0086         baseSplitter->setSizes(baseSplitterSizes);
0087     }
0088 
0089     auto* secondViewArea = new TabbedViews();
0090     QObject::connect(secondViewArea, &AbstractViewArea::focusChanged,
0091                      q, [&](bool hasFocus) { onViewAreaFocusChanged(hasFocus); });
0092     QObject::connect(secondViewArea, &AbstractGroupedViews::viewFocusChanged,
0093                      q, &AbstractGroupedViews::viewFocusChanged);
0094     QObject::connect(secondViewArea, &AbstractGroupedViews::closeRequest,
0095                      q, &AbstractGroupedViews::closeRequest);
0096     QObject::connect(secondViewArea, &AbstractGroupedViews::removing,
0097                      q, [&]() { onViewsRemoved(); });
0098 
0099     QObject::connect(secondViewArea, &TabbedViews::contextMenuRequested,
0100                      q, [&](AbstractView* view, QPoint pos) { onContextMenuRequested(view, pos); });
0101     QObject::connect(secondViewArea, &TabbedViews::dataOffered,
0102                      q, &MultiViewAreas::dataOffered);
0103     QObject::connect(secondViewArea, &TabbedViews::dataDropped,
0104                      q, &MultiViewAreas::dataDropped);
0105 
0106     mViewAreaList.append(secondViewArea);
0107     mCurrentViewArea = secondViewArea;
0108 
0109     splitter->setOrientation(orientation == Qt::Horizontal ? Qt::Vertical : Qt::Horizontal);
0110     splitter->addWidget(secondViewArea->widget());
0111     // set to equal sizes
0112     QList<int> splitterSizes = splitter->sizes();
0113     // TODO: check if there are more, style-dependent spaces
0114     const int equalSize = (splitterSizes[0] + splitterSizes[1] - splitter->handleWidth()) / 2;
0115     splitterSizes[1] = splitterSizes[0] = equalSize;
0116     splitter->setSizes(splitterSizes);
0117 
0118     const QVector<AbstractViewArea*> viewAreas { secondViewArea };
0119     Q_EMIT q->viewAreasAdded(viewAreas);
0120     Q_EMIT q->viewAreaFocusChanged(secondViewArea);
0121 
0122     return secondViewArea;
0123 }
0124 
0125 void MultiViewAreasPrivate::onViewsRemoved()
0126 {
0127     Q_Q(MultiViewAreas);
0128 
0129     // keep a minimum of one area
0130     if (mViewAreaList.size() < 2) {
0131         return;
0132     }
0133 
0134     auto* viewArea = qobject_cast<TabbedViews*>(q->sender());
0135 
0136     if (viewArea->viewCount() == 0) {
0137         QWidget* viewAreaWidget = viewArea->widget();
0138         auto* baseSplitter = static_cast<QSplitter*>(viewAreaWidget->parentWidget());
0139 
0140         const int index = baseSplitter->indexOf(viewAreaWidget);
0141         const int otherIndex = 1 - index;
0142 
0143         QWidget* otherWidget = baseSplitter->widget(otherIndex);
0144         // do not delete the main splitter
0145         if (baseSplitter != mMainSplitter) {
0146             auto* baseOfBaseSplitter = static_cast<QSplitter*>(baseSplitter->parentWidget());
0147 
0148             const QList<int> baseOfBaseSplitterSizes = baseOfBaseSplitter->sizes();
0149             const int indexOfBaseSplitter = baseOfBaseSplitter->indexOf(baseSplitter);
0150             baseOfBaseSplitter->insertWidget(indexOfBaseSplitter, otherWidget);
0151             viewAreaWidget->setParent(nullptr);
0152             delete baseSplitter;
0153             baseOfBaseSplitter->setSizes(baseOfBaseSplitterSizes);
0154         }
0155 
0156         mViewAreaList.removeOne(viewArea);
0157 
0158         if (mCurrentInlineToolViewArea == viewArea) {
0159             mCurrentInlineToolViewArea = nullptr;
0160         }
0161 
0162         if (mCurrentViewArea == viewArea) {
0163             // search for the previous widget which is the next or the previous, using index
0164             while (true) {
0165                 auto* splitter = qobject_cast<QSplitter*>(otherWidget);
0166                 if (splitter) {
0167                     otherWidget = splitter->widget(index);
0168                 } else {
0169                     break;
0170                 }
0171             }
0172 
0173             for (TabbedViews* viewArea : std::as_const(mViewAreaList)) {
0174                 if (viewArea->widget() == otherWidget) {
0175                     viewArea->setFocus();
0176                     break;
0177                 }
0178             }
0179         }
0180 
0181         const QVector<AbstractViewArea*> viewAreas { viewArea };
0182         Q_EMIT q->viewAreasRemoved(viewAreas);
0183 
0184         delete viewArea;
0185     }
0186 }
0187 
0188 void MultiViewAreasPrivate::onViewAreaFocusChanged(bool hasFocus)
0189 {
0190     Q_Q(MultiViewAreas);
0191 
0192     auto* viewArea = qobject_cast<TabbedViews*>(q->sender());
0193 
0194     if (mCurrentViewArea == viewArea) {
0195         return;
0196     }
0197 
0198     if (mCurrentInlineToolViewArea && mCurrentInlineToolViewArea == mCurrentViewArea) {
0199         mCurrentInlineToolViewArea->setCurrentToolInlineView(nullptr);
0200     }
0201 
0202     // TODO: care for ! hasFocus?
0203     if (hasFocus) {
0204         mCurrentViewArea = viewArea;
0205 
0206         Q_EMIT q->viewAreaFocusChanged(viewArea);
0207         Q_EMIT q->viewFocusChanged(viewArea->viewFocus());
0208     }
0209 }
0210 
0211 void MultiViewAreasPrivate::onContextMenuRequested(AbstractView* view, QPoint pos)
0212 {
0213     Q_Q(MultiViewAreas);
0214 
0215     auto* viewArea = qobject_cast<TabbedViews*>(q->sender());
0216 
0217     auto* viewAreaWidget = viewArea->widget();
0218     Q_EMIT q->contextMenuRequested(viewArea, view, viewAreaWidget->mapTo(mMainSplitter, pos));
0219 }
0220 
0221 #if 0
0222 void MultiViewAreasPrivate::onModifiedChanged(AbstractDocument::SyncStates newStates)
0223 {
0224     Q_UNUSED(newStates)
0225     AbstractView * view = qobject_cast<AbstractView*>(sender());
0226     if (view) {
0227         const int index = indexOf(view);
0228         if (index != -1) {
0229 //             mViewsTab->setIcon( index, newTitle ); //modificationSymbol
0230             if (index == mViewsTab->currentIndex()) {
0231                 setCaption(view->title(), view->document()->hasLocalChanges());
0232             }
0233         }
0234     }
0235 
0236 }
0237 #endif
0238 
0239 }