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 }