File indexing completed on 2024-05-12 16:07:26

0001 /* This file is part of the TikZKit project
0002  *
0003  * Copyright (C) 2014 Dominik Haumann <dhaumann@kde.org>
0004  * Copyright (C) 2001 Christoph Cullmann <cullmann@kde.org>
0005  *
0006  * This program is free software; you can redistribute it and/or modify
0007  * it under the terms of the GNU General Public License as published by
0008  * the Free Software Foundation, either version 2 or the License, or
0009  * (at your option) any later version.
0010  *
0011  * This program is distributed in the hope that it will be useful,
0012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0014  * Library General Public License for more details.
0015  *
0016  * You should have received a copy of the GNU General Public License
0017  * along with this program; If not, see <http://www.gnu.org/licenses/>.
0018  */
0019 
0020 #include "ViewManager.h"
0021 
0022 #include "TikzKit.h"
0023 #include "MainWindow.h"
0024 #include "DocumentManager.h"
0025 
0026 #include <tikz/ui/Editor.h>
0027 #include <tikz/ui/View.h>
0028 #include <tikz/ui/Document.h>
0029 
0030 #include <QUrl>
0031 #include <QTabBar>
0032 #include <QStackedWidget>
0033 #include <QVBoxLayout>
0034 
0035 ViewManager::ViewManager(MainWindow * mainWin, QWidget * parent)
0036     : QWidget(parent)
0037     , m_mainWindow(mainWin)
0038     , m_activeView(nullptr)
0039 {
0040     auto vbox = new QVBoxLayout(this);
0041     vbox->setContentsMargins(0, 0, 0, 0);
0042     vbox->setSpacing(0);
0043 
0044     m_tabBar = new QTabBar(this);
0045     m_tabBar->setDocumentMode(true);
0046     m_tabBar->setTabsClosable(true);
0047     m_tabBar->setDrawBase(false);
0048     connect(m_tabBar, SIGNAL(currentChanged(int)), this, SLOT(activateTab(int)));
0049     connect(m_tabBar, SIGNAL(tabCloseRequested(int)), this, SLOT(closeRequest(int)), Qt::QueuedConnection);
0050     m_stack = new QStackedWidget(this);
0051 
0052     vbox->addWidget(m_tabBar);
0053     vbox->addWidget(m_stack);
0054 
0055     connect(this, SIGNAL(viewChanged(tikz::ui::View*)), this, SLOT(slotViewChanged()));
0056     connect(TikzKit::self()->documentManager(), SIGNAL(documentCreated(tikz::ui::Document*)), this, SLOT(slotDocumentCreated(tikz::ui::Document*)));
0057 
0058     // a-priori track document deletion
0059     connect(TikzKit::self()->documentManager(), SIGNAL(aboutToDeleteDocument(tikz::ui::Document*)),
0060             this, SLOT(slotAboutToDeleteDocument(tikz::ui::Document*)));
0061 
0062     // unregister document
0063     connect(TikzKit::self()->documentManager(), SIGNAL(documentDeleted(tikz::ui::Document*)),
0064             this, SLOT(slotDocumentDeleted(tikz::ui::Document*)));
0065 
0066     // register existing documents
0067     for (auto doc : TikzKit::self()->documentManager()->documentList()) {
0068         slotDocumentCreated(doc);
0069     }
0070 }
0071 
0072 ViewManager::~ViewManager()
0073 {
0074 }
0075 
0076 MainWindow *ViewManager::mainWindow()
0077 {
0078     return m_mainWindow;
0079 }
0080 
0081 void ViewManager::slotDocumentCreated(tikz::ui::Document *doc)
0082 {
0083     if (!activeView()) {
0084         activateView(doc);
0085     }
0086 
0087     connect(doc, SIGNAL(documentNameChanged(tikz::core::Document*)), this, SLOT(updateDocumentName(tikz::core::Document*)));
0088 
0089     // hide tabbar if there are less than 2 tabs
0090     if (m_tabBar->count() <= 1) {
0091         m_tabBar->hide();
0092     }
0093 }
0094 
0095 void ViewManager::slotAboutToDeleteDocument(tikz::ui::Document *doc)
0096 {
0097     // kill all connections (namely, documentNameChanged(), modifiedChanged(), ...)
0098     disconnect(doc, nullptr, this, nullptr);
0099 
0100     // collect all views of that document that belong to this manager
0101     QList<tikz::ui::View *> closeList;
0102     for (auto view : doc->views()) {
0103         if (m_views.contains(view)) {
0104             closeList.append(view);
0105         }
0106     }
0107 
0108     for (auto view : qAsConst(closeList)) {
0109         deleteView(view);
0110     }
0111 }
0112 
0113 void ViewManager::slotDocumentDeleted(tikz::ui::Document * doc)
0114 {
0115     // for now, nothing to do
0116 }
0117 
0118 tikz::ui::View * ViewManager::createView(tikz::ui::Document *doc)
0119 {
0120     // require a valid doc
0121     Q_ASSERT(doc);
0122 
0123     // pass the view the correct main window
0124     tikz::ui::View *view = doc->createView(m_stack, mainWindow()->wrapper());
0125 
0126     m_views.append(view);
0127 
0128     // insert View into stack
0129     m_stack->addWidget(view);
0130 
0131     // register tab
0132     addTab(view);
0133 
0134 //     connect(view, SIGNAL(focusIn(tikz::ui::View*)), this, SLOT(activateSpace(tikz::ui::View*)));
0135 
0136     Q_EMIT viewCreated(view);
0137 
0138     if (!activeView()) {
0139         activateView(view);
0140     }
0141 
0142     return view;
0143 }
0144 
0145 bool ViewManager::deleteView(tikz::ui::View *view)
0146 {
0147     Q_ASSERT(view);
0148 
0149     // unregister tab
0150     removeTab(view);
0151 
0152     // deleting the active view automatically activates another tab, which
0153     // in turn activates another view
0154     Q_ASSERT(m_activeView != view);
0155 
0156     // remove view from mapping and memory !!
0157     m_views.remove(m_views.indexOf(view));
0158     delete view;
0159     return true;
0160 }
0161 
0162 tikz::ui::View *ViewManager::activeView()
0163 {
0164     return m_activeView;
0165 }
0166 
0167 QVector<tikz::ui::View*> ViewManager::views() const
0168 {
0169     return m_views;
0170 }
0171 
0172 void ViewManager::activateView(tikz::ui::View * view)
0173 {
0174     Q_ASSERT(view);
0175     Q_ASSERT(m_views.contains(view));
0176 
0177     if (m_activeView == view) {
0178         Q_ASSERT(m_stack->currentWidget() == view);
0179         return;
0180     }
0181 
0182     // make sure the correct tab is activated
0183     int index = -1;
0184     for (int i = 0; i < m_tabBar->count(); ++i) {
0185         if (m_tabBar->tabData(i).value<tikz::ui::View*>() == view) {
0186             index = i;
0187             break;
0188         }
0189     }
0190     Q_ASSERT(index >= 0);
0191 
0192     auto wasBlocked = m_tabBar->blockSignals(true);
0193     m_tabBar->setCurrentIndex(index);
0194     m_tabBar->blockSignals(wasBlocked);
0195 
0196     // make sure the correct view is visible
0197     m_activeView = view;
0198     m_stack->setCurrentWidget(view);
0199 
0200     Q_EMIT viewChanged(view);
0201 }
0202 
0203 tikz::ui::View *ViewManager::activateView(tikz::ui::Document * doc)
0204 {
0205     // no doc with this id found
0206     if (!doc) {
0207         return activeView();
0208     }
0209 
0210     // activate existing view if possible
0211     int index = -1;
0212     for (int i = 0; i < m_tabBar->count(); ++i) {
0213         if (m_tabBar->tabData(i).value<tikz::ui::View*>()->document() == doc) {
0214             index = i;
0215             break;
0216         }
0217     }
0218 
0219     if (index >= 0) {
0220         auto view = m_tabBar->tabData(index).value<tikz::ui::View*>();
0221         activateView(view);
0222         return view;
0223     }
0224 
0225     // create new view otherwise
0226     auto view = createView(doc);
0227     activateView(view);
0228     Q_ASSERT(view == activeView());
0229 
0230     return view;
0231 }
0232 
0233 void ViewManager::slotViewChanged()
0234 {
0235     if (activeView() && !activeView()->hasFocus()) {
0236         activeView()->setFocus();
0237     }
0238 }
0239 
0240 void ViewManager::closeView(tikz::ui::View *view)
0241 {
0242     deleteView(view);
0243 }
0244 
0245 void ViewManager::addTab(tikz::ui::View * view)
0246 {
0247     int index = -1;
0248     for (int i = 0; i < m_tabBar->count(); ++i) {
0249         if (m_tabBar->tabData(i).value<tikz::ui::View*>() == view) {
0250             index = i;
0251             break;
0252         }
0253     }
0254     Q_ASSERT(index == -1);
0255 
0256     auto wasBlocked = m_tabBar->blockSignals(true);
0257     index = m_tabBar->addTab(view->document()->documentName());
0258     m_tabBar->setTabData(index, QVariant::fromValue<tikz::ui::View*>(view));
0259     m_tabBar->blockSignals(wasBlocked);
0260 
0261     // show tabbar only if there are at least 2 tabs
0262     if (m_tabBar->count() > 1) {
0263         m_tabBar->show();
0264     }
0265 }
0266 
0267 void ViewManager::removeTab(tikz::ui::View * view)
0268 {
0269     int index = -1;
0270     for (int i = 0; i < m_tabBar->count(); ++i) {
0271         if (m_tabBar->tabData(i).value<tikz::ui::View*>() == view) {
0272             index = i;
0273             break;
0274         }
0275     }
0276     Q_ASSERT(index >= 0);
0277 
0278     m_tabBar->removeTab(index);
0279 
0280     // hide tabbar if there are less than 2 tabs
0281     if (m_tabBar->count() <= 1) {
0282         m_tabBar->hide();
0283     }
0284 }
0285 
0286 void ViewManager::activateTab(int index)
0287 {
0288     // if there are no tabs, just return
0289     if (index < 0) {
0290         m_activeView = nullptr;
0291         Q_EMIT viewChanged(m_activeView);
0292         return;
0293     }
0294 
0295     auto view = m_tabBar->tabData(index).value<tikz::ui::View*>();
0296 
0297     // a View *must* always be registered at the Editor.
0298     // Otherwise, it's a dangling pointer!
0299     Q_ASSERT(tikz::ui::Editor::instance()->views().contains(view));
0300 
0301     // the view *must* be in the widget stack, otherwise something is wrong
0302     Q_ASSERT(m_stack->indexOf(view) >= 0);
0303 
0304     // finally raise view
0305     activateView(view);
0306 }
0307 
0308 void ViewManager::closeRequest(int index)
0309 {
0310     auto view = m_tabBar->tabData(index).value<tikz::ui::View*>();
0311 
0312     // a View *must* always be registered at the Editor.
0313     // Otherwise, it's a dangling pointer!
0314     Q_ASSERT(tikz::ui::Editor::instance()->views().contains(view));
0315 
0316     Q_EMIT closeDocumentRequested(view->document());
0317 }
0318 
0319 void ViewManager::updateDocumentName(tikz::core::Document * doc)
0320 {
0321     for (int i = 0; i < m_tabBar->count(); ++i) {
0322         if (m_tabBar->tabData(i).value<tikz::ui::View*>()->document() == doc) {
0323             m_tabBar->setTabText(i, doc->documentName());
0324         }
0325     }
0326 }
0327 
0328 // kate: indent-width 4; replace-tabs on;