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

0001 /*
0002     This file is part of the Kasten Framework, made within the KDE community.
0003 
0004     SPDX-FileCopyrightText: 2007, 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 "tabbedviews_p.hpp"
0010 
0011 // lib
0012 #include "toolinlineviewwidget.hpp"
0013 #include <abstracttoolinlineview.hpp>
0014 #include <logging.hpp>
0015 // Kasten core
0016 #include <Kasten/AbstractDocument>
0017 // Qt
0018 #include <QDragMoveEvent>
0019 #include <QDropEvent>
0020 #include <QTabBar>
0021 #include <QApplication>
0022 #include <QClipboard>
0023 
0024 namespace Kasten {
0025 
0026 TabbedViewsPrivate::TabbedViewsPrivate(TabbedViews* parent)
0027     : AbstractGroupedViewsPrivate(parent)
0028 {
0029 }
0030 
0031 TabbedViewsPrivate::~TabbedViewsPrivate()
0032 {
0033     delete mViewAreaBox;
0034 }
0035 
0036 void TabbedViewsPrivate::init()
0037 {
0038     Q_Q(TabbedViews);
0039 
0040     mTabWidget = new TabWidget();
0041     mTabWidget->setMovable(true);
0042     mTabWidget->setContextMenuPolicy(Qt::CustomContextMenu);
0043 
0044     mViewAreaBox = new ViewAreaBox(mTabWidget);
0045 
0046     QObject::connect(mTabWidget, &QTabWidget::tabCloseRequested,
0047                      q, [&](int index) { onTabCloseRequest(index); });
0048     QObject::connect(mTabWidget, &QTabWidget::currentChanged,
0049                      q, [&](int index) { onCurrentChanged(index); });
0050 
0051     QObject::connect(mTabWidget, &QWidget::customContextMenuRequested,
0052                      q, [&](const QPoint& pos) { onContextMenuRequested(pos); });
0053 
0054     QObject::connect(mTabWidget, &TabWidget::testCanDecode,
0055                      q, [&](const QDragMoveEvent* event, bool& accept) { onDragMoveEvent(event, accept); });
0056     QObject::connect(mTabWidget, &TabWidget::receivedDropEvent,
0057                      q, [&](QDropEvent* event) { onDropEvent(event); });
0058     QObject::connect(mTabWidget, &TabWidget::mouseMiddleClick,
0059                      q, [&]() { onMouseMiddleClick(); });
0060     QObject::connect(mTabWidget, &TabWidget::emptySpaceMouseDoubleClicked,
0061                      q, [&]() { onEmptySpaceMouseDoubleClicked(); });
0062 }
0063 
0064 QVector<AbstractView*> TabbedViewsPrivate::viewList() const
0065 {
0066     QVector<AbstractView*> result;
0067 
0068     const int count = mTabWidget->count();
0069     result.reserve(count);
0070     for (int i = 0; i < count; ++i) {
0071         const auto* viewBox = static_cast<const ViewBox*>(mTabWidget->widget(i));
0072         AbstractView* view = viewBox->view();
0073         result.append(view);
0074     }
0075 
0076     return result;
0077 }
0078 
0079 int TabbedViewsPrivate::indexOf(AbstractView* view) const
0080 {
0081     int result = -1;
0082 
0083     const int tabCount = mTabWidget->count();
0084     for (int i = 0; i < tabCount; ++i) {
0085         const auto* viewBox = static_cast<const ViewBox*>(mTabWidget->widget(i));
0086         if (view == viewBox->view()) {
0087             result = i;
0088             break;
0089         }
0090     }
0091 
0092     return result;
0093 }
0094 
0095 void TabbedViewsPrivate::addViews(const QVector<AbstractView*>& views)
0096 {
0097     Q_Q(TabbedViews);
0098 
0099     if (views.size() == 0) {
0100         return;
0101     }
0102 
0103     int insertIndex = mTabWidget->currentIndex() + 1;
0104     for (AbstractView* view : views) {
0105         QObject::connect(view, &AbstractModel::titleChanged,
0106                          q, [&](const QString& title) { onTitleChanged(title); });
0107 
0108         auto* viewBox = new ViewBox(view, mTabWidget);
0109         mTabWidget->insertTab(insertIndex, viewBox, view->title());
0110         ++insertIndex;
0111     }
0112 
0113     mTabWidget->setCurrentIndex(insertIndex - 1);
0114 
0115     // fix for Qt bug:
0116     if (mTabWidget->count() == 1) {
0117         // simulate signal reaction
0118         onCurrentChanged(0);
0119     }
0120 
0121     Q_EMIT q->added(views);
0122 }
0123 
0124 void TabbedViewsPrivate::removeViews(const QVector<AbstractView*>& views)
0125 {
0126     Q_Q(TabbedViews);
0127 
0128     int index = -1;
0129 
0130     // TODO: check if contained
0131     for (AbstractView* view : views) {
0132         view->disconnect(q);
0133 
0134         index = indexOf(view);
0135         if (index != -1) {
0136             auto* viewBox = static_cast<ViewBox*>(mTabWidget->widget(index));
0137 
0138             mTabWidget->removeTab(index);
0139             delete viewBox;
0140         }
0141     }
0142 
0143     // fix for Qt bug:
0144     const int currentIndex = mTabWidget->currentIndex();
0145     // last removed or no change in index (not bound to widget)?
0146     if (currentIndex == -1 || currentIndex == index) {
0147         // simulate signal reaction
0148         onCurrentChanged(currentIndex);
0149     }
0150 
0151     Q_EMIT q->removing(views);
0152 }
0153 
0154 void TabbedViewsPrivate::setCurrentToolInlineView(AbstractToolInlineView* view)
0155 {
0156     if (mCurrentToolInlineView != view) {
0157         mCurrentToolInlineView = view;
0158         QWidget* toolInlineViewWidget = mCurrentToolInlineView ? mCurrentToolInlineView->widget() : nullptr;
0159         mViewAreaBox->setBottomToolWidget(toolInlineViewWidget);
0160     }
0161 
0162     if (mCurrentToolInlineView) {
0163         mViewAreaBox->showBottomToolWidget();
0164     }
0165 }
0166 
0167 void TabbedViewsPrivate::onCurrentChanged(int index)
0168 {
0169     Q_Q(TabbedViews);
0170 
0171     const auto* viewBox = static_cast<const ViewBox*>(mTabWidget->widget(index));
0172     AbstractView* view = viewBox ? viewBox->view() : nullptr;
0173 
0174     if (view == mCurrentView) {
0175         return;
0176     }
0177 
0178     setCurrentToolInlineView(nullptr);
0179 
0180     if (mCurrentView) {
0181         mCurrentView->disconnect(q);
0182     }
0183 
0184     mCurrentView = view;
0185 
0186     if (view) {
0187         QObject::connect(view, &AbstractView::focusChanged,
0188                          q, [&](bool hasFocus) { onViewFocusChanged(hasFocus); });
0189         view->widget()->setFocus();
0190     }
0191 
0192     Q_EMIT q->viewFocusChanged(view);
0193 }
0194 
0195 void TabbedViewsPrivate::onTabCloseRequest(int tabIndex)
0196 {
0197     Q_Q(TabbedViews);
0198 
0199     const QWidget* widget = mTabWidget->widget(tabIndex);
0200     const auto* viewBox = static_cast<const ViewBox*>(widget);
0201     AbstractView* view = viewBox->view();
0202 
0203     const QVector<Kasten::AbstractView*> views { view };
0204     Q_EMIT q->closeRequest(views);
0205 }
0206 
0207 void TabbedViewsPrivate::onTitleChanged(const QString& newTitle)
0208 {
0209     Q_Q(TabbedViews);
0210 
0211     auto* view = qobject_cast<AbstractView*>(q->sender());
0212     if (view) {
0213         const int index = indexOf(view);
0214         if (index != -1) {
0215             mTabWidget->setTabText(index, newTitle);
0216         }
0217     }
0218 }
0219 
0220 #if 0
0221 void TabbedViewsPrivate::onModifiedChanged(AbstractDocument::SyncStates newStates)
0222 {
0223     Q_UNUSED(newStates)
0224     AbstractView * view = qobject_cast<AbstractView*>(sender());
0225     if (view) {
0226         const int index = indexOf(view);
0227         if (index != -1) {
0228 //             mViewsTab->setIcon( index, newTitle ); //modificationSymbol
0229             if (index == mViewsTab->currentIndex()) {
0230                 setCaption(view->title(), view->document()->hasLocalChanges());
0231             }
0232         }
0233     }
0234 
0235 }
0236 #endif
0237 
0238 // TODO: could be just a signal forwarder
0239 void TabbedViewsPrivate::onViewFocusChanged(bool hasFocus)
0240 {
0241     Q_Q(TabbedViews);
0242 
0243 //     AbstractView* view = qobject_cast<AbstractView *>( q->sender() );
0244 // qCDebug(LOG_KASTEN_GUI)<<view<<view->title()<<hasFocus;
0245 
0246     Q_EMIT q->focusChanged(hasFocus);
0247 }
0248 
0249 void TabbedViewsPrivate::onContextMenuRequested(QPoint pos)
0250 {
0251     Q_Q(TabbedViews);
0252 
0253     AbstractView* view = nullptr;
0254     QTabBar* tabBar = mTabWidget->tabBar();
0255     const int tabIndex = tabBar->tabAt(tabBar->mapFrom(mTabWidget, pos));
0256     if (tabIndex != -1) {
0257         const QWidget* widget = mTabWidget->widget(tabIndex);
0258         const auto* viewBox = static_cast<const ViewBox*>(widget);
0259         view = viewBox->view();
0260     }
0261     Q_EMIT q->contextMenuRequested(view, mTabWidget->mapTo(mViewAreaBox, pos));
0262 }
0263 
0264 void TabbedViewsPrivate::onMouseMiddleClick()
0265 {
0266     Q_Q(TabbedViews);
0267 
0268     const QMimeData* mimeData = QApplication::clipboard()->mimeData(QClipboard::Selection);
0269 
0270     Q_EMIT q->dataDropped(mimeData);
0271 }
0272 
0273 void TabbedViewsPrivate::onEmptySpaceMouseDoubleClicked()
0274 {
0275     Q_Q(TabbedViews);
0276 
0277     Q_EMIT q->newDocumentRequested();
0278 }
0279 
0280 void TabbedViewsPrivate::onDragMoveEvent(const QDragMoveEvent* event, bool& accepted)
0281 {
0282     Q_Q(TabbedViews);
0283 
0284     const QMimeData* mimeData = event->mimeData();
0285 
0286     Q_EMIT q->dataOffered(mimeData, accepted);
0287 }
0288 
0289 void TabbedViewsPrivate::onDropEvent(QDropEvent* event)
0290 {
0291     Q_Q(TabbedViews);
0292 
0293     const QMimeData* mimeData = event->mimeData();
0294 
0295     Q_EMIT q->dataDropped(mimeData);
0296 }
0297 
0298 }