File indexing completed on 2024-05-05 05:00:27

0001 /*  This file is part of the KDE project
0002     SPDX-FileCopyrightText: 1999 Simon Hausmann <hausmann@kde.org>
0003     SPDX-FileCopyrightText: 2007 Eduardo Robles Elvira <edulix@gmail.com>
0004 
0005     SPDX-License-Identifier: GPL-2.0-or-later
0006 */
0007 
0008 #include "konqviewmanager.h"
0009 
0010 #include "konqcloseditem.h"
0011 #include "konqundomanager.h"
0012 #include "konqmisc.h"
0013 #include "konqview.h"
0014 #include "konqframestatusbar.h"
0015 #include "konqtabs.h"
0016 #include "konqsettingsxt.h"
0017 #include "konqframevisitor.h"
0018 #include <konq_events.h>
0019 #include "konqurl.h"
0020 #include <KX11Extras>
0021 
0022 #include <QFileInfo>
0023 #include <QDBusMessage>
0024 #include <QDBusConnection>
0025 
0026 #include <KParts/PartActivateEvent>
0027 
0028 #include <kactionmenu.h>
0029 
0030 #include <kstringhandler.h>
0031 #include "konqdebug.h"
0032 #include <QTemporaryFile>
0033 #include <KLocalizedString>
0034 #include <kmessagebox.h>
0035 #include <QMenu>
0036 #include <QApplication>
0037 #include <QStandardPaths>
0038 #include <KSharedConfig>
0039 #include <KWindowConfig>
0040 #include <QMimeDatabase>
0041 #include <QMimeType>
0042 #include <QScreen>
0043 
0044 //#define DEBUG_VIEWMGR
0045 
0046 KonqViewManager::KonqViewManager(KonqMainWindow *mainWindow)
0047     : KParts::PartManager(mainWindow)
0048 {
0049     m_pMainWindow = mainWindow;
0050 
0051     m_bLoadingProfile = false;
0052     m_tabContainer = nullptr;
0053 
0054     setIgnoreExplictFocusRequests(true);
0055 
0056     connect(this, SIGNAL(activePartChanged(KParts::Part*)),
0057             this, SLOT(slotActivePartChanged(KParts::Part*)));
0058 
0059     //When closing a window, tabs will be removed one by one, meaning each one will be activated:
0060     //this would trigger their delayed loading, which we don't want. So, when the main window is closed
0061     //disconnect the delayedLoadTab slot
0062     connect(mainWindow, &KonqMainWindow::closing, this, [this](){
0063             disconnect(m_tabContainer, &QTabWidget::currentChanged, this, &KonqViewManager::delayedLoadTab);
0064         }
0065     );
0066 }
0067 
0068 KonqView *KonqViewManager::createFirstView(const QString &mimeType, const QString &serviceName)
0069 {
0070     //qCDebug(KONQUEROR_LOG) << serviceName;
0071     KPluginMetaData service;
0072     QVector<KPluginMetaData> partServiceOffers;
0073     KService::List appServiceOffers;
0074     KonqViewFactory newViewFactory = createView(mimeType, serviceName, service, partServiceOffers, appServiceOffers, true /*forceAutoEmbed*/);
0075     if (newViewFactory.isNull()) {
0076         qCDebug(KONQUEROR_LOG) << "No suitable factory found.";
0077         return nullptr;
0078     }
0079 
0080     KonqView *childView = setupView(tabContainer(), newViewFactory, service, partServiceOffers, appServiceOffers, mimeType, false);
0081 
0082     setActivePart(childView->part());
0083 
0084     m_tabContainer->asQWidget()->show();
0085     return childView;
0086 }
0087 
0088 KonqViewManager::~KonqViewManager()
0089 {
0090     clear();
0091 }
0092 
0093 KonqView *KonqViewManager::splitView(KonqView *currentView,
0094                                      Qt::Orientation orientation,
0095                                      bool newOneFirst, bool forceAutoEmbed)
0096 {
0097 #ifdef DEBUG_VIEWMGR
0098     qCDebug(KONQUEROR_LOG);
0099     m_pMainWindow->dumpViewList();
0100     printFullHierarchy();
0101 #endif
0102 
0103     KonqFrame *splitFrame = currentView->frame();
0104     const QString serviceType = currentView->serviceType();
0105 
0106     KPluginMetaData service;
0107     QVector<KPluginMetaData> partServiceOffers;
0108     KService::List appServiceOffers;
0109 
0110     KonqViewFactory newViewFactory = createView(serviceType, currentView->service().pluginId(), service, partServiceOffers, appServiceOffers, forceAutoEmbed);
0111 
0112     if (newViewFactory.isNull()) {
0113         return nullptr;    //do not split at all if we can't create the new view
0114     }
0115 
0116     Q_ASSERT(splitFrame);
0117 
0118     KonqFrameContainerBase *parentContainer = splitFrame->parentContainer();
0119 
0120     // We need the sizes of the views in the parentContainer to restore these after the new container is inserted.
0121     // To access the sizes via QSplitter::sizes(), a pointer to a KonqFrameContainerBase is not sufficient.
0122     // We need a pointer to a KonqFrameContainer which is derived from QSplitter.
0123     KonqFrameContainer *parentKonqFrameContainer = dynamic_cast<KonqFrameContainer *>(parentContainer);
0124     QList<int> parentSplitterSizes;
0125     if (parentKonqFrameContainer) {
0126         parentSplitterSizes = parentKonqFrameContainer->sizes();
0127     }
0128 
0129     KonqFrameContainer *newContainer = parentContainer->splitChildFrame(splitFrame, orientation);
0130 
0131     //qCDebug(KONQUEROR_LOG) << "Create new child";
0132     KonqView *newView = setupView(newContainer, newViewFactory, service, partServiceOffers, appServiceOffers, serviceType, false);
0133 
0134 #ifndef DEBUG
0135     //printSizeInfo( splitFrame, parentContainer, "after child insert" );
0136 #endif
0137 
0138     newContainer->insertWidget(newOneFirst ? 0 : 1, newView->frame());
0139     if (newOneFirst) {
0140         newContainer->swapChildren();
0141     }
0142 
0143     Q_ASSERT(newContainer->count() == 2);
0144 
0145     int width = std::max(newContainer->widget(0)->minimumSizeHint().width(), newContainer->widget(1)->minimumSizeHint().width());
0146     newContainer->setSizes(QList<int>{width, width});
0147 
0148     splitFrame->show();
0149     newContainer->show();
0150 
0151     if (parentKonqFrameContainer) {
0152         parentKonqFrameContainer->setSizes(parentSplitterSizes);
0153     }
0154 
0155     Q_ASSERT(newView->frame());
0156     Q_ASSERT(newView->part());
0157     newContainer->setActiveChild(newView->frame());
0158     setActivePart(newView->part());
0159 
0160 #ifdef DEBUG_VIEWMGR
0161     m_pMainWindow->dumpViewList();
0162     printFullHierarchy();
0163     qCDebug(KONQUEROR_LOG) << "done";
0164 #endif
0165 
0166     return newView;
0167 }
0168 
0169 KonqView *KonqViewManager::splitMainContainer(KonqView *currentView,
0170         Qt::Orientation orientation,
0171         const QString &serviceType, // This can be Browser/View, not necessarily a mimetype
0172         const QString &serviceName,
0173         bool newOneFirst)
0174 {
0175     //qCDebug(KONQUEROR_LOG);
0176 
0177     KPluginMetaData service;
0178     QVector<KPluginMetaData> partServiceOffers;
0179     KService::List appServiceOffers;
0180 
0181     KonqViewFactory newViewFactory = createView(serviceType, serviceName, service, partServiceOffers, appServiceOffers);
0182 
0183     if (newViewFactory.isNull()) {
0184         return nullptr;    //do not split at all if we can't create the new view
0185     }
0186 
0187     // Get main frame. Note: this is NOT necessarily m_tabContainer!
0188     // When having tabs plus a konsole, the main frame is a splitter (KonqFrameContainer).
0189     KonqFrameBase *mainFrame = m_pMainWindow->childFrame();
0190 
0191     KonqFrameContainer *newContainer = m_pMainWindow->splitChildFrame(mainFrame, orientation);
0192 
0193     KonqView *childView = setupView(newContainer, newViewFactory, service, partServiceOffers, appServiceOffers, serviceType, true);
0194 
0195     newContainer->insertWidget(newOneFirst ? 0 : 1, childView->frame());
0196     if (newOneFirst) {
0197         newContainer->swapChildren();
0198     }
0199 
0200     newContainer->show();
0201     newContainer->setActiveChild(mainFrame);
0202 
0203     childView->duplicateView(currentView);
0204     // childView->openUrl(currentView->url(), currentView->locationBarURL());
0205 
0206 #ifdef DEBUG_VIEWMGR
0207     m_pMainWindow->dumpViewList();
0208     printFullHierarchy();
0209     qCDebug(KONQUEROR_LOG) << "done";
0210 #endif
0211 
0212     return childView;
0213 }
0214 
0215 KonqView *KonqViewManager::addTab(const QString &serviceType, const QString &serviceName, bool passiveMode, bool openAfterCurrentPage, int pos)
0216 {
0217 #ifdef DEBUG_VIEWMGR
0218     qCDebug(KONQUEROR_LOG) << "------------- KonqViewManager::addTab starting -------------";
0219     m_pMainWindow->dumpViewList();
0220     printFullHierarchy();
0221 #endif
0222 
0223     KPluginMetaData service;
0224     QVector<KPluginMetaData> partServiceOffers;
0225     KService::List appServiceOffers;
0226 
0227     Q_ASSERT(!serviceType.isEmpty());
0228 
0229     QString actualServiceName = serviceName;
0230     if (actualServiceName.isEmpty()) {
0231         // Use same part as the current view (e.g. khtml/webkit).
0232         // This is down here in this central method because it should work for
0233         // MMB-opens-tab, window.open (createNewWindow), and more.
0234         KonqView *currentView = m_pMainWindow->currentView();
0235         // Don't use supportsMimeType("text/html"), it's true for katepart too.
0236         // (Testcase: view text file, ctrl+shift+n, was showing about page in katepart)
0237         if (currentView) {
0238             QMimeType mime = currentView->mimeType();
0239             if (mime.isValid() && mime.inherits(serviceType)) {
0240                 actualServiceName = currentView->service().pluginId();
0241             }
0242         }
0243     }
0244 
0245     KonqViewFactory newViewFactory = createView(serviceType, actualServiceName, service, partServiceOffers, appServiceOffers, true /*forceAutoEmbed*/);
0246 
0247     if (newViewFactory.isNull()) {
0248         return nullptr;    //do not split at all if we can't create the new view
0249     }
0250 
0251     KonqView *childView = setupView(tabContainer(), newViewFactory, service, partServiceOffers, appServiceOffers, serviceType, passiveMode, openAfterCurrentPage, pos);
0252 
0253 #ifdef DEBUG_VIEWMGR
0254     m_pMainWindow->dumpViewList();
0255     printFullHierarchy();
0256     qCDebug(KONQUEROR_LOG) << "------------- KonqViewManager::addTab done -------------";
0257 #endif
0258 
0259     return childView;
0260 }
0261 
0262 KonqView *KonqViewManager::addTabFromHistory(KonqView *currentView, int steps, bool openAfterCurrentPage)
0263 {
0264     int oldPos = currentView->historyIndex();
0265     int newPos = oldPos + steps;
0266 
0267     const HistoryEntry *he = currentView->historyAt(newPos);
0268     if (!he) {
0269         return nullptr;
0270     }
0271 
0272     KonqView *newView = nullptr;
0273     newView  = addTab(he->strServiceType, he->strServiceName, false, openAfterCurrentPage);
0274 
0275     if (!newView) {
0276         return nullptr;
0277     }
0278 
0279     newView->copyHistory(currentView);
0280     newView->setHistoryIndex(newPos);
0281     newView->restoreHistory();
0282 
0283     return newView;
0284 }
0285 
0286 void KonqViewManager::duplicateTab(int tabIndex, bool openAfterCurrentPage)
0287 {
0288 #ifdef DEBUG_VIEWMGR
0289     qCDebug(KONQUEROR_LOG) << tabIndex;
0290     m_pMainWindow->dumpViewList();
0291     printFullHierarchy();
0292 #endif
0293 
0294     QTemporaryFile tempFile;
0295     tempFile.open();
0296     KConfig config(tempFile.fileName());
0297     KConfigGroup profileGroup(&config, "Profile");
0298 
0299     KonqFrameBase *tab = tabContainer()->tabAt(tabIndex);
0300     QString prefix = KonqFrameBase::frameTypeToString(tab->frameType()) + QString::number(0); // always T0
0301     profileGroup.writeEntry("RootItem", prefix);
0302     prefix.append(QLatin1Char('_'));
0303     KonqFrameBase::Options flags = KonqFrameBase::SaveHistoryItems;
0304     tab->saveConfig(profileGroup, prefix, flags, nullptr, 0, 1);
0305 
0306     loadRootItem(profileGroup, tabContainer(), QUrl(), true, QUrl(), QString(), openAfterCurrentPage);
0307 
0308     if (openAfterCurrentPage) {
0309         m_tabContainer->setCurrentIndex(m_tabContainer->currentIndex() + 1);
0310     } else {
0311         m_tabContainer->setCurrentIndex(m_tabContainer->count() - 1);
0312     }
0313 
0314 #ifdef DEBUG_VIEWMGR
0315     m_pMainWindow->dumpViewList();
0316     printFullHierarchy();
0317 #endif
0318 }
0319 
0320 KonqMainWindow *KonqViewManager::breakOffTab(int tab, const QSize &windowSize)
0321 {
0322 #ifdef DEBUG_VIEWMGR
0323     qCDebug(KONQUEROR_LOG) << "tab=" << tab;
0324     m_pMainWindow->dumpViewList();
0325     printFullHierarchy();
0326 #endif
0327 
0328     QTemporaryFile tempFile;
0329     tempFile.open();
0330     KSharedConfigPtr config = KSharedConfig::openConfig(tempFile.fileName());
0331     KConfigGroup profileGroup(config, "Profile");
0332 
0333     KonqFrameBase *tabFrame = tabContainer()->tabAt(tab);
0334     QString prefix = KonqFrameBase::frameTypeToString(tabFrame->frameType()) + QString::number(0); // always T0
0335     profileGroup.writeEntry("RootItem", prefix);
0336     prefix.append(QLatin1Char('_'));
0337     KonqFrameBase::Options flags = KonqFrameBase::SaveHistoryItems;
0338     tabFrame->saveConfig(profileGroup, prefix, flags, nullptr, 0, 1);
0339 
0340     KonqMainWindow *mainWindow = new KonqMainWindow;
0341 
0342     KonqFrameTabs *newTabContainer = mainWindow->viewManager()->tabContainer();
0343     mainWindow->viewManager()->loadRootItem(profileGroup, newTabContainer, QUrl(), true, QUrl());
0344 
0345     removeTab(tabFrame, false);
0346 
0347     mainWindow->enableAllActions(true);
0348     mainWindow->resize(windowSize);
0349     mainWindow->activateChild();
0350     mainWindow->show();
0351 
0352 #ifdef DEBUG_VIEWMGR
0353     m_pMainWindow->dumpViewList();
0354     printFullHierarchy();
0355 #endif
0356 
0357     return mainWindow;
0358 }
0359 
0360 void KonqViewManager::openClosedWindow(const KonqClosedWindowItem &closedWindowItem)
0361 {
0362     openSavedWindow(closedWindowItem.configGroup())->show();
0363 }
0364 
0365 KonqMainWindow *KonqViewManager::openSavedWindow(const KConfigGroup &configGroup)
0366 {
0367     // TODO factorize to avoid code duplication with loadViewProfileFromGroup
0368     KonqMainWindow *mainWindow = new KonqMainWindow;
0369 
0370     if (configGroup.readEntry("FullScreen", false)) {
0371         // Full screen on
0372         mainWindow->showFullScreen();
0373     } else {
0374         // Full screen off
0375         if (mainWindow->isFullScreen()) {
0376             mainWindow->showNormal();
0377         }
0378         // Window size comes from the applyMainWindowSettings call below
0379     }
0380 
0381     mainWindow->viewManager()->loadRootItem(configGroup, mainWindow, QUrl(), true, QUrl());
0382     mainWindow->applyMainWindowSettings(configGroup);
0383     mainWindow->activateChild();
0384 
0385 #ifdef DEBUG_VIEWMGR
0386     mainWindow->viewManager()->printFullHierarchy();
0387 #endif
0388     return mainWindow;
0389 }
0390 
0391 KonqMainWindow *KonqViewManager::openSavedWindow(const KConfigGroup &configGroup,
0392         bool openTabsInsideCurrentWindow)
0393 {
0394     if (!openTabsInsideCurrentWindow) {
0395         return KonqViewManager::openSavedWindow(configGroup);
0396     } else {
0397         loadRootItem(configGroup, tabContainer(), QUrl(), true, QUrl());
0398 #ifndef NDEBUG
0399         printFullHierarchy();
0400 #endif
0401         return m_pMainWindow;
0402     }
0403 }
0404 
0405 void KonqViewManager::removeTab(KonqFrameBase *currentFrame, bool emitAboutToRemoveSignal)
0406 {
0407     Q_ASSERT(currentFrame);
0408 #ifdef DEBUG_VIEWMGR
0409     qCDebug(KONQUEROR_LOG) << currentFrame;
0410     m_pMainWindow->dumpViewList();
0411     printFullHierarchy();
0412 #endif
0413 
0414     if (m_tabContainer->count() == 1) {
0415         m_pMainWindow->slotAddTab();    // #214378
0416     }
0417 
0418     if (emitAboutToRemoveSignal) {
0419         emit aboutToRemoveTab(currentFrame);
0420     }
0421 
0422     if (currentFrame->asQWidget() == m_tabContainer->currentWidget()) {
0423         setActivePart(nullptr);
0424     }
0425 
0426     const QList<KonqView *> viewList = KonqViewCollector::collect(currentFrame);
0427     for (KonqView *view: viewList) {
0428         if (view == m_pMainWindow->currentView()) {
0429             setActivePart(nullptr);
0430         }
0431         m_pMainWindow->removeChildView(view);
0432         delete view;
0433     }
0434 
0435     m_tabContainer->childFrameRemoved(currentFrame);
0436 
0437     delete currentFrame;
0438 
0439     m_tabContainer->slotCurrentChanged(m_tabContainer->currentIndex());
0440 
0441     m_pMainWindow->viewCountChanged();
0442 
0443 #ifdef DEBUG_VIEWMGR
0444     m_pMainWindow->dumpViewList();
0445     printFullHierarchy();
0446 #endif
0447 }
0448 
0449 void KonqViewManager::reloadAllTabs()
0450 {
0451     for(KonqFrameBase *frame: tabContainer()->childFrameList()) {
0452         if (frame && frame->activeChildView()) {
0453             if (!frame->activeChildView()->locationBarURL().isEmpty()) {
0454                 //TODO KF6: check whether requestedUrl or realUrl is more suitable here. Do we want to download again a file? I think so
0455                 frame->activeChildView()->openUrl(frame->activeChildView()->url(), frame->activeChildView()->locationBarURL());
0456             }
0457         }
0458     }
0459 }
0460 
0461 void KonqViewManager::removeOtherTabs(int tabIndex)
0462 {
0463     QList<KonqFrameBase *> tabs = m_tabContainer->childFrameList();
0464     for (int i = 0; i < tabs.count(); ++i) {
0465         if (i != tabIndex) {
0466             removeTab(tabs.at(i));
0467         }
0468     }
0469 }
0470 
0471 void KonqViewManager::moveTabBackward()
0472 {
0473     if (m_tabContainer->count() == 1) {
0474         return;
0475     }
0476 
0477     int iTab = m_tabContainer->currentIndex();
0478     m_tabContainer->moveTabBackward(iTab);
0479 }
0480 
0481 void KonqViewManager::moveTabForward()
0482 {
0483     if (m_tabContainer->count() == 1) {
0484         return;
0485     }
0486 
0487     int iTab = m_tabContainer->currentIndex();
0488     m_tabContainer->moveTabForward(iTab);
0489 }
0490 
0491 void KonqViewManager::activateNextTab()
0492 {
0493     if (m_tabContainer->count() == 1) {
0494         return;
0495     }
0496 
0497     int iTab = m_tabContainer->currentIndex();
0498 
0499     iTab++;
0500 
0501     if (iTab == m_tabContainer->count()) {
0502         iTab = 0;
0503     }
0504 
0505     m_tabContainer->setCurrentIndex(iTab);
0506 }
0507 
0508 void KonqViewManager::activatePrevTab()
0509 {
0510     if (m_tabContainer->count() == 1) {
0511         return;
0512     }
0513 
0514     int iTab = m_tabContainer->currentIndex();
0515 
0516     iTab--;
0517 
0518     if (iTab == -1) {
0519         iTab = m_tabContainer->count() - 1;
0520     }
0521 
0522     m_tabContainer->setCurrentIndex(iTab);
0523 }
0524 
0525 int KonqViewManager::currentTabIndex() const
0526 {
0527     return m_tabContainer->currentIndex();
0528 }
0529 
0530 int KonqViewManager::tabsCount() const
0531 {
0532     return m_tabContainer->count();
0533 }
0534 
0535 void KonqViewManager::activateTab(int position)
0536 {
0537     if (position < 0 || m_tabContainer->count() == 1 || position >= m_tabContainer->count()) {
0538         return;
0539     }
0540 
0541     m_tabContainer->setCurrentIndex(position);
0542 }
0543 
0544 void KonqViewManager::showTab(KonqView *view)
0545 {
0546     if (m_tabContainer->currentWidget() != view->frame()) {
0547         m_tabContainer->setCurrentIndex(m_tabContainer->indexOf(view->frame()));
0548     }
0549 }
0550 
0551 void KonqViewManager::showTab(int tabIndex)
0552 {
0553     if (m_tabContainer->currentIndex() != tabIndex) {
0554         m_tabContainer->setCurrentIndex(tabIndex);
0555     }
0556 }
0557 
0558 void KonqViewManager::updatePixmaps()
0559 {
0560     const QList<KonqView *> viewList = KonqViewCollector::collect(tabContainer());
0561     for (KonqView *view: viewList) {
0562         view->setTabIcon(QUrl::fromUserInput(view->locationBarURL()));
0563     }
0564 }
0565 
0566 void KonqViewManager::openClosedTab(const KonqClosedTabItem &closedTab)
0567 {
0568     qCDebug(KONQUEROR_LOG);
0569     loadRootItem(closedTab.configGroup(), m_tabContainer, QUrl(), true, QUrl(), QString(), false, closedTab.pos());
0570 
0571     int pos = (closedTab.pos() < m_tabContainer->count()) ? closedTab.pos() : m_tabContainer->count() - 1;
0572     qCDebug(KONQUEROR_LOG) << "pos, m_tabContainer->count():" << pos << m_tabContainer->count() - 1;
0573 
0574     m_tabContainer->setCurrentIndex(pos);
0575 }
0576 
0577 void KonqViewManager::removeView(KonqView *view)
0578 {
0579 #ifdef DEBUG_VIEWMGR
0580     qCDebug(KONQUEROR_LOG) << view;
0581     m_pMainWindow->dumpViewList();
0582     printFullHierarchy();
0583 #endif
0584 
0585     if (!view) {
0586         return;
0587     }
0588 
0589     KonqFrame *frame = view->frame();
0590     KonqFrameContainerBase *parentContainer = frame->parentContainer();
0591 
0592     qCDebug(KONQUEROR_LOG) << "view=" << view << "frame=" << frame << "parentContainer=" << parentContainer;
0593 
0594     if (parentContainer->frameType() == KonqFrameBase::Container) {
0595         setActivePart(nullptr);
0596 
0597         qCDebug(KONQUEROR_LOG) << "parentContainer is a KonqFrameContainer";
0598 
0599         KonqFrameContainerBase *grandParentContainer = parentContainer->parentContainer();
0600         qCDebug(KONQUEROR_LOG) << "grandParentContainer=" << grandParentContainer;
0601 
0602         KonqFrameBase *otherFrame = static_cast<KonqFrameContainer *>(parentContainer)->otherChild(frame);
0603         if (!otherFrame) {
0604             qCWarning(KONQUEROR_LOG) << "This shouldn't happen!";
0605             return;
0606         }
0607 
0608         static_cast<KonqFrameContainer *>(parentContainer)->setAboutToBeDeleted();
0609 
0610         // If the grand parent is a KonqFrameContainer, we need the sizes of the views inside it to restore these after
0611         // the parent is replaced. To access the sizes via QSplitter::sizes(), a pointer to a KonqFrameContainerBase
0612         //  is not sufficient. We need a pointer to a KonqFrameContainer which is derived from QSplitter.
0613         KonqFrameContainer *grandParentKonqFrameContainer = dynamic_cast<KonqFrameContainer *>(grandParentContainer);
0614         QList<int> grandParentSplitterSizes;
0615         if (grandParentKonqFrameContainer) {
0616             grandParentSplitterSizes = grandParentKonqFrameContainer->sizes();
0617         }
0618 
0619         m_pMainWindow->removeChildView(view);
0620 
0621         //qCDebug(KONQUEROR_LOG) << "--- Deleting view" << view;
0622         grandParentContainer->replaceChildFrame(parentContainer, otherFrame);
0623 
0624         //qCDebug(KONQUEROR_LOG) << "--- Removing otherFrame from parentContainer";
0625         parentContainer->childFrameRemoved(otherFrame);
0626 
0627         delete view; // This deletes the view, which deletes the part, which deletes its widget
0628 
0629         delete parentContainer;
0630 
0631         if (grandParentKonqFrameContainer) {
0632             grandParentKonqFrameContainer->setSizes(grandParentSplitterSizes);
0633         }
0634 
0635         grandParentContainer->setActiveChild(otherFrame);
0636         grandParentContainer->activateChild();
0637         m_pMainWindow->viewCountChanged();
0638     } else if (parentContainer->frameType() == KonqFrameBase::Tabs) {
0639         qCDebug(KONQUEROR_LOG) << "parentContainer" << parentContainer << "is a KonqFrameTabs";
0640 
0641         removeTab(frame);
0642     } else if (parentContainer->frameType() == KonqFrameBase::MainWindow) {
0643         qCDebug(KONQUEROR_LOG) << "parentContainer is a KonqMainWindow.  This shouldn't be removable, not removing.";
0644     } else {
0645         qCDebug(KONQUEROR_LOG) << "Unrecognized frame type, not removing.";
0646     }
0647 
0648 #ifdef DEBUG_VIEWMGR
0649     printFullHierarchy();
0650     m_pMainWindow->dumpViewList();
0651 
0652     qCDebug(KONQUEROR_LOG) << "done";
0653 #endif
0654 }
0655 
0656 // reimplemented from PartManager
0657 void KonqViewManager::removePart(KParts::Part *part)
0658 {
0659     //qCDebug(KONQUEROR_LOG) << part;
0660     // This is called when a part auto-deletes itself (case 1), or when
0661     // the "delete view" above deletes, in turn, the part (case 2)
0662 
0663     KParts::PartManager::removePart(part);
0664 
0665     // If we were called by PartManager::slotObjectDestroyed, then the inheritance has
0666     // been deleted already... Can't use inherits().
0667 
0668     KonqView *view = m_pMainWindow->childView(static_cast<KParts::ReadOnlyPart *>(part));
0669     if (view) { // the child view still exists, so we are in case 1
0670         qCDebug(KONQUEROR_LOG) << "Found a child view";
0671 
0672         // Make sure that deleting the frame won't delete the part's widget;
0673         // that's already taken care of by the part.
0674         view->part()->widget()->hide();
0675         view->part()->widget()->setParent(nullptr);
0676 
0677         view->partDeleted(); // tell the child view that the part auto-deletes itself
0678 
0679         if (m_pMainWindow->mainViewsCount() == 1) {
0680             qCDebug(KONQUEROR_LOG) << "Deleting last view -> closing the window";
0681             clear();
0682             qCDebug(KONQUEROR_LOG) << "Closing m_pMainWindow" << m_pMainWindow;
0683             m_pMainWindow->close(); // will delete it
0684             return;
0685         } else { // normal case
0686             removeView(view);
0687         }
0688     }
0689 
0690     //qCDebug(KONQUEROR_LOG) << part << "done";
0691 }
0692 
0693 void KonqViewManager::slotPassiveModePartDeleted()
0694 {
0695     // Passive mode parts aren't registered to the part manager,
0696     // so we have to handle suicidal ones ourselves
0697     KParts::ReadOnlyPart *part = const_cast<KParts::ReadOnlyPart *>(static_cast<const KParts::ReadOnlyPart *>(sender()));
0698     disconnect(part, SIGNAL(destroyed()), this, SLOT(slotPassiveModePartDeleted()));
0699     qCDebug(KONQUEROR_LOG) << "part=" << part;
0700     KonqView *view = m_pMainWindow->childView(part);
0701     qCDebug(KONQUEROR_LOG) << "view=" << view;
0702     if (view != nullptr) { // the child view still exists, so the part suicided
0703         view->partDeleted(); // tell the child view that the part deleted itself
0704         removeView(view);
0705     }
0706 }
0707 
0708 void KonqViewManager::viewCountChanged()
0709 {
0710     bool bShowActiveViewIndicator = (m_pMainWindow->viewCount() > 1);
0711     bool bShowLinkedViewIndicator = (m_pMainWindow->linkableViewsCount() > 1);
0712 
0713     const KonqMainWindow::MapViews mapViews = m_pMainWindow->viewMap();
0714     KonqMainWindow::MapViews::ConstIterator it = mapViews.begin();
0715     KonqMainWindow::MapViews::ConstIterator end = mapViews.end();
0716     for (; it != end; ++it) {
0717         KonqFrameStatusBar *sb = it.value()->frame()->statusbar();
0718         sb->showActiveViewIndicator(bShowActiveViewIndicator && !it.value()->isPassiveMode());
0719         sb->showLinkedViewIndicator(bShowLinkedViewIndicator && !it.value()->isFollowActive());
0720     }
0721 }
0722 
0723 void KonqViewManager::clear()
0724 {
0725     //qCDebug(KONQUEROR_LOG);
0726     setActivePart(nullptr);
0727 
0728     if (m_pMainWindow->childFrame() == nullptr) {
0729         return;
0730     }
0731 
0732     const QList<KonqView *> viewList = KonqViewCollector::collect(m_pMainWindow);
0733     if (!viewList.isEmpty()) {
0734         //qCDebug(KONQUEROR_LOG) << viewList.count() << "items";
0735 
0736         for (KonqView *view: viewList) {
0737             m_pMainWindow->removeChildView(view);
0738             //qCDebug(KONQUEROR_LOG) << "Deleting" << view;
0739             delete view;
0740         }
0741     }
0742 
0743     KonqFrameBase *frame = m_pMainWindow->childFrame();
0744     Q_ASSERT(frame);
0745     //qCDebug(KONQUEROR_LOG) << "deleting mainFrame ";
0746     m_pMainWindow->childFrameRemoved(frame);   // will set childFrame() to NULL
0747     delete frame;
0748     // tab container was deleted by the above
0749     m_tabContainer = nullptr;
0750     m_pMainWindow->viewCountChanged();
0751 }
0752 
0753 KonqView *KonqViewManager::chooseNextView(KonqView *view)
0754 {
0755     //qCDebug(KONQUEROR_LOG) << view;
0756 
0757     int it = 0;
0758     const QList<KonqView *> viewList = KonqViewCollector::collect(m_pMainWindow);
0759     if (viewList.isEmpty()) {
0760         return nullptr; // We have no view at all - this used to happen with totally-empty-profiles
0761     }
0762 
0763     if (view) { // find it in the list
0764         it = viewList.indexOf(view);
0765     }
0766 
0767     // the view should always be in the list
0768     if (it == -1) {
0769         qCWarning(KONQUEROR_LOG) << "View" << view << "is not in list!";
0770         it = 0;
0771     }
0772 
0773     bool rewinded = false;
0774     const int startIndex = it;
0775     const int end = viewList.count();
0776 
0777     //qCDebug(KONQUEROR_LOG) << "count=" << end;
0778     while (true) {
0779         //qCDebug(KONQUEROR_LOG) << "going next";
0780         if (++it == end) { // move to next
0781             // end reached: restart from begin (but only once)
0782             if (!rewinded) {
0783                 it = 0;
0784                 rewinded = true;
0785             } else {
0786                 break; // nothing found, probably buggy profile
0787             }
0788         }
0789 
0790         if (it == startIndex && view) {
0791             break;    // no next view found
0792         }
0793 
0794         KonqView *nextView = viewList.at(it);;
0795         if (nextView && !nextView->isPassiveMode()) {
0796             return nextView;
0797         }
0798         //qCDebug(KONQUEROR_LOG) << "nextView=" << nextView << "passive=" << nextView->isPassiveMode();
0799     }
0800 
0801     //qCDebug(KONQUEROR_LOG) << "returning 0";
0802     return nullptr; // no next view found
0803 }
0804 
0805 KonqViewFactory KonqViewManager::createView(const QString &serviceType,
0806         const QString &serviceName,
0807         KPluginMetaData &service,
0808         QVector<KPluginMetaData> &partServiceOffers,
0809         KService::List &appServiceOffers,
0810         bool forceAutoEmbed)
0811 {
0812     KonqViewFactory viewFactory;
0813 
0814     QString _serviceType(serviceType);
0815     QString _serviceName(serviceName);
0816 
0817     if (serviceType.isEmpty() && m_pMainWindow->currentView()) {
0818         //clone current view
0819         KonqView *cv = m_pMainWindow->currentView();
0820         if (cv->service().pluginId() == QLatin1String("konq_sidebartng")) {
0821             _serviceType = QStringLiteral("text/html");
0822             _serviceName.clear();
0823         } else {
0824             _serviceType = cv->serviceType();
0825             _serviceName = cv->service().pluginId();
0826         }
0827     }
0828 
0829     KonqFactory konqFactory;
0830     viewFactory = konqFactory.createView(_serviceType, _serviceName, &service, &partServiceOffers, &appServiceOffers, forceAutoEmbed);
0831 
0832     return viewFactory;
0833 }
0834 
0835 KonqView* KonqViewManager::setupView(KonqFrameContainerBase* parentContainer, bool passiveMode, bool openAfterCurrentPage, int pos)
0836 {
0837     KonqViewFactory factory;
0838     return setupView(parentContainer, factory, {}, {}, {}, {}, passiveMode, openAfterCurrentPage, pos);
0839 }
0840 
0841 KonqView *KonqViewManager::setupView(KonqFrameContainerBase *parentContainer,
0842                                      KonqViewFactory &viewFactory,
0843                                      const KPluginMetaData &service,
0844                                      const QVector<KPluginMetaData> &partServiceOffers,
0845                                      const KService::List &appServiceOffers,
0846                                      const QString &serviceType,
0847                                      bool passiveMode,
0848                                      bool openAfterCurrentPage,
0849                                      int pos)
0850 {
0851     //qCDebug(KONQUEROR_LOG) << "passiveMode=" << passiveMode;
0852 
0853     QString sType = serviceType;
0854 
0855     if (sType.isEmpty() && m_pMainWindow->currentView()) { // TODO remove this -- after checking all callers; splitMainContainer seems to need this logic
0856         sType = m_pMainWindow->currentView()->serviceType();
0857     }
0858 
0859     //qCDebug(KONQUEROR_LOG) << "creating KonqFrame with parent=" << parentContainer;
0860     KonqFrame *newViewFrame = new KonqFrame(parentContainer->asQWidget(), parentContainer);
0861     newViewFrame->setGeometry(0, 0, m_pMainWindow->width(), m_pMainWindow->height());
0862 
0863     //qCDebug(KONQUEROR_LOG) << "Creating KonqView";
0864     // KonqView *v = new KonqView(newViewFrame, m_pMainWindow);
0865     KonqView *v = nullptr;
0866     if (!viewFactory.isNull()) {
0867         v = new KonqView(viewFactory, newViewFrame, m_pMainWindow, service, partServiceOffers, appServiceOffers, sType, passiveMode);
0868     } else {
0869         v = new KonqView(newViewFrame, m_pMainWindow);
0870     }
0871     //qCDebug(KONQUEROR_LOG) << "KonqView created - v=" << v << "v->part()=" << v->part();
0872 
0873     connect(v, &KonqView::sigPartChanged, m_pMainWindow, &KonqMainWindow::slotPartChanged);
0874 //     QObject::connect(v, SIGNAL(sigPartChanged(KonqView*,KParts::ReadOnlyPart*,KParts::ReadOnlyPart*)),
0875 //                      m_pMainWindow, SLOT(slotPartChanged(KonqView*,KParts::ReadOnlyPart*,KParts::ReadOnlyPart*)));
0876 
0877     m_pMainWindow->insertChildView(v);
0878 
0879     int index = -1;
0880     if (openAfterCurrentPage) {
0881         index = m_tabContainer->currentIndex() + 1;
0882     } else if (pos > -1) {
0883         index = pos;
0884     }
0885 
0886     parentContainer->insertChildFrame(newViewFrame, index);
0887 
0888     if (parentContainer->frameType() != KonqFrameBase::Tabs) {
0889         newViewFrame->show();
0890     }
0891 
0892     // Don't register passive views to the part manager
0893     if (!v->isPassiveMode()) { // note that KonqView's constructor could set this to true even if passiveMode is false
0894         addPart(v->part(), false);
0895     } else {
0896         // Passive views aren't registered, but we still want to detect the suicidal ones
0897         connect(v->part(), SIGNAL(destroyed()), this, SLOT(slotPassiveModePartDeleted()));
0898     }
0899 
0900     if (!m_bLoadingProfile) {
0901         m_pMainWindow->viewCountChanged();
0902     }
0903 
0904     //qCDebug(KONQUEROR_LOG) << "done";
0905     return v;
0906 }
0907 
0908 
0909 void KonqViewManager::saveViewConfigToGroup(KConfigGroup &profileGroup, KonqFrameBase::Options options)
0910 {
0911     if (m_pMainWindow->childFrame()) {
0912         QString prefix = KonqFrameBase::frameTypeToString(m_pMainWindow->childFrame()->frameType())
0913                          + QString::number(0);
0914         profileGroup.writeEntry("RootItem", prefix);
0915         prefix.append(QLatin1Char('_'));
0916         m_pMainWindow->saveConfig(profileGroup, prefix, options, tabContainer(), 0, 1);
0917     }
0918 
0919     profileGroup.writeEntry("FullScreen", m_pMainWindow->fullScreenMode());
0920 
0921     m_pMainWindow->saveMainWindowSettings(profileGroup);
0922 }
0923 
0924 void KonqViewManager::loadViewConfigFromGroup(const KConfigGroup &profileGroup, const QString &filename,
0925         const QUrl &forcedUrl, const KonqOpenURLRequest &req,
0926         bool openUrl)
0927 {
0928     Q_UNUSED(filename); // could be useful in case of error messages
0929 
0930     QUrl defaultURL;
0931     if (m_pMainWindow->currentView()) {
0932         defaultURL = m_pMainWindow->currentView()->url();
0933     }
0934 
0935     clear();
0936 
0937     if (!KonqUrl::isKonqBlank(forcedUrl)) {
0938         loadRootItem(profileGroup, m_pMainWindow, defaultURL, openUrl && forcedUrl.isEmpty(), forcedUrl, req.serviceName);
0939     } else {
0940         // ## in this case we won't resize the window, so bool resetWindow could be useful after all?
0941         m_pMainWindow->disableActionsNoView();
0942         m_pMainWindow->action("clear_location")->trigger();
0943     }
0944 
0945     //qCDebug(KONQUEROR_LOG) << "after loadRootItem";
0946 
0947     // Set an active part first so that we open the URL in the current view
0948     // (to set the location bar correctly and asap)
0949     KonqView *nextChildView = nullptr;
0950     nextChildView = m_pMainWindow->activeChildView();
0951     if (nextChildView == nullptr) {
0952         nextChildView = chooseNextView(nullptr);
0953     }
0954     setActivePart(nextChildView ? nextChildView->part() : nullptr);
0955 
0956     // #71164
0957     if (!req.browserArgs.frameName.isEmpty() && nextChildView) {
0958         nextChildView->setViewName(req.browserArgs.frameName);
0959     }
0960 
0961     if (openUrl && !forcedUrl.isEmpty()) {
0962         KonqOpenURLRequest _req(req);
0963         _req.openAfterCurrentPage = KonqSettings::openAfterCurrentPage();
0964         _req.forceAutoEmbed = true; // it's a new window, let's use it
0965 
0966         m_pMainWindow->openUrl(nextChildView /* can be 0 for an empty profile */,
0967                                forcedUrl, _req.args.mimeType(), _req, _req.browserArgs.trustedSource);
0968 
0969         // TODO choose a linked view if any (instead of just the first one),
0970         // then open the same URL in any non-linked one
0971     } else {
0972         if (forcedUrl.isEmpty() && m_pMainWindow->locationBarURL().isEmpty()) {
0973             // No URL -> the user will want to type one
0974             m_pMainWindow->focusLocationBar();
0975         }
0976     }
0977 
0978     // Window size
0979     if (profileGroup.readEntry("FullScreen", false)) {
0980         // Full screen on
0981         m_pMainWindow->setWindowState(m_pMainWindow->windowState() | Qt::WindowFullScreen);
0982     } else {
0983         // Full screen off
0984         m_pMainWindow->setWindowState(m_pMainWindow->windowState() & ~Qt::WindowFullScreen);
0985         applyWindowSize(profileGroup);
0986     }
0987 
0988     //qCDebug(KONQUEROR_LOG) << "done";
0989 }
0990 
0991 void KonqViewManager::setActivePart(KParts::Part *part, QWidget *)
0992 {
0993     doSetActivePart(static_cast<KParts::ReadOnlyPart *>(part));
0994 }
0995 
0996 void KonqViewManager::doSetActivePart(KParts::ReadOnlyPart *part)
0997 {
0998     if (part) {
0999         qCDebug(KONQUEROR_LOG) << part << part->url();
1000     }
1001 
1002     KParts::Part *mainWindowActivePart = m_pMainWindow->currentView()
1003                                          ? m_pMainWindow->currentView()->part() : nullptr;
1004     if (part == activePart() && mainWindowActivePart == part) {
1005         //qCDebug(KONQUEROR_LOG) << "Part is already active!";
1006         return;
1007     }
1008 
1009     // ## is this the right currentView() already?
1010     if (m_pMainWindow->currentView()) {
1011         m_pMainWindow->currentView()->setLocationBarURL(m_pMainWindow->locationBarURL());
1012     }
1013 
1014     KParts::PartManager::setActivePart(part);
1015 
1016     if (part && part->widget()) {
1017         part->widget()->setFocus();
1018 
1019         // However in case of an error URL we want to make it possible for the user to fix it
1020         KonqView *view = m_pMainWindow->viewMap().value(part);
1021         if (view && view->isErrorUrl()) {
1022             m_pMainWindow->focusLocationBar();
1023         }
1024     }
1025 
1026     emitActivePartChanged(); // This is what triggers KonqMainWindow::slotPartActivated
1027 }
1028 
1029 void KonqViewManager::slotActivePartChanged(KParts::Part *newPart)
1030 {
1031     //qCDebug(KONQUEROR_LOG) << newPart;
1032     if (newPart == nullptr) {
1033         //qCDebug(KONQUEROR_LOG) << "newPart = 0L , returning";
1034         return;
1035     }
1036     // Send event to mainwindow - this is useful for plugins (like searchbar)
1037     KParts::PartActivateEvent ev(true, newPart, newPart->widget());
1038     QApplication::sendEvent(m_pMainWindow, &ev);
1039     
1040     KonqView *view = m_pMainWindow->childView(static_cast<KParts::ReadOnlyPart *>(newPart));
1041     if (view == nullptr) {
1042         qCDebug(KONQUEROR_LOG) << "No view associated with this part";
1043         return;
1044     }
1045     if (view->frame()->parentContainer() == nullptr) {
1046         return;
1047     }
1048     if (!m_bLoadingProfile)  {
1049         view->frame()->statusbar()->updateActiveStatus();
1050         view->frame()->parentContainer()->setActiveChild(view->frame());
1051     }
1052     //qCDebug(KONQUEROR_LOG) << "done";
1053 }
1054 
1055 void KonqViewManager::emitActivePartChanged()
1056 {
1057     m_pMainWindow->slotPartActivated(activePart());
1058 }
1059 
1060 // Read default size from profile (e.g. Width=80%)
1061 static QSize readDefaultSize(const KConfigGroup &cfg, QWidget *widget)
1062 {
1063     QString widthStr = cfg.readEntry("Width");
1064     QString heightStr = cfg.readEntry("Height");
1065     int width = -1;
1066     int height = -1;
1067     const QRect geom = widget->screen()->geometry();
1068 
1069     bool ok;
1070     if (widthStr.endsWith('%')) {
1071         widthStr.truncate(widthStr.length() - 1);
1072         const int relativeWidth = widthStr.toInt(&ok);
1073         if (ok) {
1074             width = relativeWidth * geom.width() / 100;
1075         }
1076     } else {
1077         width = widthStr.toInt(&ok);
1078         if (!ok) {
1079             width = -1;
1080         }
1081     }
1082 
1083     if (heightStr.endsWith('%')) {
1084         heightStr.truncate(heightStr.length() - 1);
1085         int relativeHeight = heightStr.toInt(&ok);
1086         if (ok) {
1087             height = relativeHeight * geom.height() / 100;
1088         }
1089     } else {
1090         height = heightStr.toInt(&ok);
1091         if (!ok) {
1092             height = -1;
1093         }
1094     }
1095 
1096     return QSize(width, height);
1097 }
1098 
1099 void KonqViewManager::applyWindowSize(const KConfigGroup &profileGroup)
1100 {
1101     const QSize size = readDefaultSize(profileGroup, m_pMainWindow); // example: "Width=80%"
1102     if (size.isValid()) {
1103         m_pMainWindow->resize(size);
1104     }
1105     KWindowConfig::restoreWindowSize(m_pMainWindow->windowHandle(), profileGroup); // example: "Width 1400=1120"
1106 }
1107 
1108 void KonqViewManager::loadRootItem(const KConfigGroup &cfg, KonqFrameContainerBase *parent,
1109                                    const QUrl &defaultURL, bool openUrl,
1110                                    const QUrl &forcedUrl, const QString &forcedService,
1111                                    bool openAfterCurrentPage,
1112                                    int pos)
1113 {
1114     const QString rootItem = cfg.readEntry("RootItem", "empty");
1115 
1116     // This flag is used by KonqView, to distinguish manual view creation
1117     // from profile loading (e.g. in switchView)
1118     m_bLoadingProfile = true;
1119 
1120     loadItem(cfg, parent, rootItem, {defaultURL, forcedUrl, forcedService, openUrl}, openAfterCurrentPage, pos);
1121 
1122     m_bLoadingProfile = false;
1123 
1124     //Actually perform delayed loading of the current tab
1125     if (m_tabContainer) {
1126         KonqFrameBase *frm = m_tabContainer->currentTab();
1127         QList<KonqView*> views = KonqViewCollector::collect(frm);
1128         for (KonqView *v : views) {
1129             v->loadDelayed();
1130         }
1131     }
1132 
1133     m_pMainWindow->enableAllActions(true);
1134 
1135     // This flag disables calls to viewCountChanged while creating the views,
1136     // so we do it once at the end:
1137     viewCountChanged();
1138 }
1139 
1140 void KonqViewManager::loadItem(const KConfigGroup &cfg, KonqFrameContainerBase *parent,
1141                                const QString &name, const LoadViewUrlData &viewData,
1142                                bool openAfterCurrentPage, int pos)
1143 {
1144     QString prefix;
1145     if (name != QLatin1String("InitialView")) { // InitialView is old stuff, not in use anymore
1146         prefix = name + QLatin1Char('_');
1147     }
1148 
1149 #ifdef DEBUG_VIEWMGR
1150     qCDebug(KONQUEROR_LOG) << "begin name=" << name << "openUrl=" << openUrl;
1151 #endif
1152 
1153     if (name.startsWith(QLatin1String("View")) || name == QLatin1String("empty")) {
1154         loadViewItem(cfg, prefix, parent, name, viewData, openAfterCurrentPage, pos);
1155     } else if (name.startsWith(QLatin1String("Container"))) {
1156         //qCDebug(KONQUEROR_LOG) << "Item is Container";
1157         loadContainerItem(cfg, prefix, parent, name, openAfterCurrentPage, pos, viewData);
1158     } else if (name.startsWith(QLatin1String("Tabs"))) {
1159         //qCDebug(KONQUEROR_LOG) << "Item is a Tabs";
1160         loadTabsItem(cfg, prefix, parent, viewData);
1161     } else {
1162         qCWarning(KONQUEROR_LOG) << "Profile Loading Error: Unknown item" << name;
1163     }
1164 
1165     //qCDebug(KONQUEROR_LOG) << "end" << name;
1166 }
1167 
1168 void KonqViewManager::loadTabsItem(const KConfigGroup& cfg, const QString& prefix, KonqFrameContainerBase *parent,
1169                                    const LoadViewUrlData &viewData)
1170 {
1171     int index = cfg.readEntry(QStringLiteral("activeChildIndex").prepend(prefix), 0);
1172     if (!m_tabContainer) {
1173         createTabContainer(parent->asQWidget(), parent);
1174         parent->insertChildFrame(m_tabContainer);
1175     }
1176 
1177     const QStringList childList = cfg.readEntry(QStringLiteral("Children").prepend(prefix), QStringList());
1178     for (QStringList::const_iterator it = childList.begin(); it != childList.end(); ++it) {
1179         loadItem(cfg, tabContainer(), *it, viewData);
1180         QWidget *currentPage = m_tabContainer->currentWidget();
1181         if (currentPage != nullptr) {
1182             KonqView *activeChildView = dynamic_cast<KonqFrameBase *>(currentPage)->activeChildView();
1183             if (activeChildView != nullptr) {
1184                 activeChildView->setCaption(activeChildView->caption());
1185                 activeChildView->setTabIcon(activeChildView->url());
1186             }
1187         }
1188     }
1189 
1190     QWidget *w = m_tabContainer->widget(index);
1191     if (w) {
1192         m_tabContainer->setActiveChild(dynamic_cast<KonqFrameBase *>(w));
1193         m_tabContainer->setCurrentIndex(index);
1194         m_tabContainer->show();
1195     } else {
1196         qCWarning(KONQUEROR_LOG) << "Profile Loading Error: Unknown current item index" << index;
1197     }
1198 }
1199 
1200 void KonqViewManager::loadContainerItem(const KConfigGroup& cfg, const QString& prefix, KonqFrameContainerBase* parent,
1201                                         const QString &name, bool openAfterCurrentPage, int pos, const LoadViewUrlData& viewData)
1202 {
1203     //load container config
1204     QString ostr = cfg.readEntry(QStringLiteral("Orientation").prepend(prefix), QString());
1205     //qCDebug(KONQUEROR_LOG) << "Orientation:" << ostr;
1206     Qt::Orientation o;
1207     if (ostr == QLatin1String("Vertical")) {
1208         o = Qt::Vertical;
1209     } else if (ostr == QLatin1String("Horizontal")) {
1210         o = Qt::Horizontal;
1211     } else {
1212         qCWarning(KONQUEROR_LOG) << "Profile Loading Error: No orientation specified in" << name;
1213         o = Qt::Horizontal;
1214     }
1215 
1216     QList<int> sizes = cfg.readEntry(QStringLiteral("SplitterSizes").prepend(prefix), QList<int>());
1217 
1218     int index = cfg.readEntry(QStringLiteral("activeChildIndex").prepend(prefix), -1);
1219     QStringList childList = cfg.readEntry(QStringLiteral("Children").prepend(prefix), QStringList());
1220 
1221     if (childList.count() < 2) {
1222         qCWarning(KONQUEROR_LOG) << "Profile Loading Error: Less than two children in" << name;
1223         // fallback to defaults
1224         loadItem(cfg, parent, QStringLiteral("InitialView"), viewData);
1225         return;
1226     }
1227 
1228     KonqFrameContainer *newContainer = new KonqFrameContainer(o, parent->asQWidget(), parent);
1229 
1230     int tabindex = pos;
1231     if (openAfterCurrentPage && parent->frameType() == KonqFrameBase::Tabs) { // Need to honor it, if possible
1232         tabindex = static_cast<KonqFrameTabs *>(parent)->currentIndex() + 1;
1233     }
1234     parent->insertChildFrame(newContainer, tabindex);
1235 
1236     loadItem(cfg, newContainer, childList.at(0), viewData);
1237     loadItem(cfg, newContainer, childList.at(1), viewData);
1238 
1239     //qCDebug(KONQUEROR_LOG) << "setSizes" << sizes;
1240     newContainer->setSizes(sizes);
1241 
1242     if (index == 1) {
1243         newContainer->setActiveChild(newContainer->secondChild());
1244     } else if (index == 0) {
1245         newContainer->setActiveChild(newContainer->firstChild());
1246     }
1247 
1248     newContainer->show();
1249 }
1250 
1251 //Helper function for KonqViewManager::loadViewItem which determines whether the
1252 // given frame is the tab container or is (directly or not) contained in the tab container
1253 bool hasTabAncestor(KonqFrameContainerBase *frm) {
1254     while (frm) {
1255         if (frm && frm->frameType() == KonqFrameBase::Tabs) {
1256             return true;
1257         }
1258         frm = frm->parentContainer();
1259     }
1260     return false;
1261 }
1262 
1263 void KonqViewManager::loadViewItem(const KConfigGroup& cfg, const QString &prefix, KonqFrameContainerBase* parent,
1264                                    const QString& name, const LoadViewUrlData &data, bool openAfterCurrentPage, int pos)
1265 {
1266     // load view config
1267 
1268     QString serviceType;
1269     QString serviceName;
1270     if (name == QLatin1String("empty")) {
1271         // An empty profile is an empty KHTML part. Makes all KHTML actions available, avoids crashes,
1272         // makes it easy to DND a URL onto it, and makes it fast to load a website from there.
1273         serviceType = QStringLiteral("text/html");
1274         serviceName = data.forcedService; // coming e.g. from the cmdline, otherwise empty
1275     } else {
1276         serviceType = cfg.readEntry(QStringLiteral("ServiceType").prepend(prefix), QStringLiteral("inode/directory"));
1277         serviceName = cfg.readEntry(QStringLiteral("ServiceName").prepend(prefix), QString());
1278         if (serviceName == QLatin1String("konq_aboutpage")) {
1279             if ((!data.forcedUrl.isEmpty() && !KonqUrl::hasKonqScheme(data.forcedUrl)) ||
1280                     (data.forcedUrl.isEmpty() && data.openUrl == false)) { // e.g. window.open
1281                 // No point in loading the about page if we're going to replace it with a KHTML part right away
1282                 serviceType = QStringLiteral("text/html");
1283                 serviceName = data.forcedService; // coming e.g. from the cmdline, otherwise empty
1284             }
1285         }
1286     }
1287 
1288     //qCDebug(KONQUEROR_LOG) << "serviceType" << serviceType << serviceName;
1289 
1290     bool passiveMode = cfg.readEntry(QStringLiteral("PassiveMode").prepend(prefix), false);
1291 
1292     //qCDebug(KONQUEROR_LOG) << "Creating View Stuff; parent=" << parent;
1293     if (parent == m_pMainWindow) {
1294         parent = tabContainer();
1295     }
1296 
1297     QUrl url;
1298     if (data.openUrl) {
1299         const QString urlKey = QStringLiteral("URL").prepend(prefix);
1300         if (cfg.hasKey(urlKey)) {
1301             url = QUrl(cfg.readPathEntry(urlKey, KonqUrl::string(KonqUrl::Type::Blank)));
1302         } else {
1303             url = data.defaultUrl;
1304         }
1305     }
1306 
1307     bool lockedLocation = cfg.readEntry(QStringLiteral("LockedLocation").prepend(prefix), false);
1308     bool linkedView = cfg.readEntry(QStringLiteral("LinkedView").prepend(prefix), false);
1309     const bool isToggleView = cfg.readEntry(QStringLiteral("ToggleView").prepend(prefix), false);
1310 
1311     KonqView *childView = nullptr;
1312 
1313     //Don't use delayed loading for views which aren't (directly or indirectly) contained in the tabs widget
1314     //This is the case, for example, of the sidebar view or the terminal emulator. Since they don't belong
1315     //to any tab, they're always visible, so there's no reason to delay loading them (besides, it wouldn't
1316     //work, as the delayed loading would never trigger). See BUG 478255
1317     if (hasTabAncestor(parent)) {
1318         childView = setupView(parent, passiveMode, openAfterCurrentPage, pos);
1319         childView->storeDelayedLoadingData(serviceType, serviceName, data.openUrl, url, lockedLocation, cfg, prefix);
1320     }
1321     else {
1322         KPluginMetaData service;
1323         QVector<KPluginMetaData> partServiceOffers;
1324         KService::List appServiceOffers;
1325         KonqFactory konqFactory;
1326         KonqViewFactory viewFactory = konqFactory.createView(serviceType, serviceName, &service, &partServiceOffers, &appServiceOffers, true /*forceAutoEmbed*/);
1327         if (viewFactory.isNull()) {
1328             qCWarning(KONQUEROR_LOG) << "Profile Loading Error: View creation failed";
1329             return; //ugh..
1330         }
1331         childView = setupView(parent, viewFactory, service, partServiceOffers, appServiceOffers, serviceType, passiveMode, openAfterCurrentPage, pos);
1332         if (data.openUrl) {
1333             restoreViewOutsideTabContainer(childView, cfg, prefix, data.defaultUrl, serviceType);
1334         }
1335     }
1336 
1337     if (!childView->isFollowActive()) {
1338         childView->setLinkedView(linkedView);
1339     }
1340     childView->setToggleView(isToggleView);
1341     if (isToggleView /*100373*/ || !cfg.readEntry(QStringLiteral("ShowStatusBar").prepend(prefix), true)) {
1342         childView->frame()->statusbar()->hide();
1343     }
1344 
1345     if (parent == m_tabContainer && m_tabContainer->count() == 1) {
1346         // First tab, make it the active one
1347         parent->setActiveChild(childView->frame());
1348     }
1349 }
1350 
1351 void KonqViewManager::restoreViewOutsideTabContainer(KonqView* view, const KConfigGroup& cfg, const QString &prefix, const QUrl &defaultURL, const QString &serviceType)
1352 {
1353     const QString keyHistoryItems = QStringLiteral("NumberOfHistoryItems").prepend(prefix);
1354     if (cfg.hasKey(keyHistoryItems)) {
1355         view->loadHistoryConfig(cfg, prefix);
1356         m_pMainWindow->updateHistoryActions();
1357     } else {
1358         // determine URL
1359         const QString urlKey = QStringLiteral("URL").prepend(prefix);
1360         QUrl url;
1361         if (cfg.hasKey(urlKey)) {
1362             url = QUrl(cfg.readPathEntry(urlKey, KonqUrl::string(KonqUrl::Type::Blank)));
1363         } else if (urlKey == QLatin1String("empty_URL")) { // old stuff, not in use anymore
1364             url = KonqUrl::url(KonqUrl::Type::Blank);
1365         } else {
1366             url = defaultURL;
1367         }
1368 
1369         if (!url.isEmpty()) {
1370             //qCDebug(KONQUEROR_LOG) << "calling openUrl" << url;
1371             //childView->openUrl( url, url.toDisplayString() );
1372             // We need view-follows-view (for the dirtree, for instance)
1373             KonqOpenURLRequest req;
1374             if (!KonqUrl::hasKonqScheme(url)) {
1375                 req.typedUrl = url.toDisplayString();
1376             }
1377             m_pMainWindow->openView(serviceType, url, view, req);
1378         }
1379         //else qCDebug(KONQUEROR_LOG) << "url is empty";
1380     }
1381 }
1382 
1383 void KonqViewManager::setLoading(KonqView *view, bool loading)
1384 {
1385     tabContainer()->setLoading(view->frame(), loading);
1386 }
1387 
1388 ///////////////// Debug stuff ////////////////
1389 
1390 #ifndef NDEBUG
1391 void KonqViewManager::printSizeInfo(KonqFrameBase *frame,
1392                                     KonqFrameContainerBase *parent,
1393                                     const char *msg)
1394 {
1395     const QRect r = frame->asQWidget()->geometry();
1396     qCDebug(KONQUEROR_LOG) << "Child size" << msg << r;
1397     if (parent->frameType() == KonqFrameBase::Container) {
1398         const QList<int> sizes = static_cast<KonqFrameContainer *>(parent)->sizes();
1399         printf("Parent sizes %s :", msg);
1400         for (int i: sizes) {
1401             printf(" %d", i);
1402         }
1403         printf("\n");
1404     }
1405 }
1406 
1407 class KonqDebugFrameVisitor : public KonqFrameVisitor
1408 {
1409 public:
1410     KonqDebugFrameVisitor() {}
1411     bool visit(KonqFrame *frame) override
1412     {
1413         QString className;
1414         if (!frame->part()) {
1415             className = QStringLiteral("NoPart!");
1416         } else if (!frame->part()->widget()) {
1417             className = QStringLiteral("NoWidget!");
1418         } else {
1419             className = frame->part()->widget()->metaObject()->className();
1420         }
1421         qCDebug(KONQUEROR_LOG) << m_spaces << frame
1422                  << "parent=" << frame->parentContainer()
1423                  << (frame->isHidden() ? "hidden" : "shown")
1424                  << "containing view" << frame->childView()
1425                  << "and part" << frame->part()
1426                  << "whose widget is a" << className;
1427         return true;
1428     }
1429     bool visit(KonqFrameContainer *container) override
1430     {
1431         qCDebug(KONQUEROR_LOG) << m_spaces << container
1432                  << (container->isHidden() ? "hidden" : "shown")
1433                  << (container->orientation() == Qt::Horizontal ? "horizontal" : "vertical")
1434                  << "sizes=" << container->sizes()
1435                  << "parent=" << container->parentContainer()
1436                  << "activeChild=" << container->activeChild();
1437 
1438         if (!container->activeChild()) {
1439             qCDebug(KONQUEROR_LOG) << "WARNING:" << container << "has a null active child!";
1440         }
1441 
1442         m_spaces += QLatin1String("  ");
1443         return true;
1444     }
1445     bool visit(KonqFrameTabs *tabs) override
1446     {
1447         qCDebug(KONQUEROR_LOG) << m_spaces << "KonqFrameTabs" << tabs
1448                  << "visible=" << tabs->isVisible()
1449                  << "activeChild=" << tabs->activeChild();
1450         if (!tabs->activeChild()) {
1451             qCDebug(KONQUEROR_LOG) << "WARNING:" << tabs << "has a null active child!";
1452         }
1453         m_spaces += QLatin1String("  ");
1454         return true;
1455     }
1456     bool visit(KonqMainWindow *) override
1457     {
1458         return true;
1459     }
1460     bool endVisit(KonqFrameTabs *) override
1461     {
1462         m_spaces.resize(m_spaces.size() - 2);
1463         return true;
1464     }
1465     bool endVisit(KonqFrameContainer *) override
1466     {
1467         m_spaces.resize(m_spaces.size() - 2);
1468         return true;
1469     }
1470     bool endVisit(KonqMainWindow *) override
1471     {
1472         return true;
1473     }
1474 private:
1475     QString m_spaces;
1476 };
1477 
1478 void KonqViewManager::printFullHierarchy()
1479 {
1480     qCDebug(KONQUEROR_LOG) << "currentView=" << m_pMainWindow->currentView();
1481     KonqDebugFrameVisitor visitor;
1482     m_pMainWindow->accept(&visitor);
1483 }
1484 #endif
1485 
1486 KonqFrameTabs *KonqViewManager::tabContainer()
1487 {
1488     if (!m_tabContainer) {
1489         createTabContainer(m_pMainWindow /*as widget*/, m_pMainWindow /*as container*/);
1490         m_pMainWindow->insertChildFrame(m_tabContainer);
1491     }
1492     return m_tabContainer;
1493 }
1494 
1495 bool KonqViewManager::isTabBarVisible() const
1496 {
1497     if (!m_tabContainer) {
1498         return false;
1499     }
1500     return !m_tabContainer->tabBar()->isHidden();
1501 }
1502 
1503 void KonqViewManager::forceHideTabBar(bool force)
1504 {
1505     if (m_tabContainer) {
1506         m_tabContainer->forceHideTabBar(force);
1507     }
1508 }
1509 
1510 
1511 void KonqViewManager::createTabContainer(QWidget *parent, KonqFrameContainerBase *parentContainer)
1512 {
1513 #ifdef DEBUG_VIEWMGR
1514     qCDebug(KONQUEROR_LOG) << "createTabContainer" << parent << parentContainer;
1515 #endif
1516     m_tabContainer = new KonqFrameTabs(parent, parentContainer, this);
1517     // Delay the opening of the URL for #106641
1518     bool ok = connect(m_tabContainer, SIGNAL(openUrl(KonqView*,QUrl)), m_pMainWindow, SLOT(openUrl(KonqView*,QUrl)), Qt::QueuedConnection);
1519     connect(m_tabContainer, &QTabWidget::currentChanged, this, &KonqViewManager::delayedLoadTab);
1520     Q_ASSERT(ok);
1521     Q_UNUSED(ok);
1522     applyConfiguration();
1523 }
1524 
1525 void KonqViewManager::applyConfiguration()
1526 {
1527     tabContainer()->setAlwaysTabbedMode(KonqSettings::alwaysTabbedMode());
1528     tabContainer()->setTabsClosable(KonqSettings::permanentCloseButton());
1529 }
1530 
1531 KonqMainWindow *KonqViewManager::duplicateWindow()
1532 {
1533     QTemporaryFile tempFile;
1534     tempFile.open();
1535     KConfig config(tempFile.fileName());
1536     KConfigGroup group(&config, "Profile");
1537     KonqFrameBase::Options flags = KonqFrameBase::SaveHistoryItems;
1538     saveViewConfigToGroup(group, flags);
1539 
1540     KonqMainWindow *mainWindow = openSavedWindow(group);
1541 #ifndef NDEBUG
1542     mainWindow->viewManager()->printFullHierarchy();
1543 #endif
1544     return mainWindow;
1545 }
1546 
1547 void KonqViewManager::reparseConfiguration()
1548 {
1549     if (m_tabContainer) {
1550         m_tabContainer->reparseConfiguration();
1551     }
1552 }
1553 
1554 void KonqViewManager::delayedLoadTab(int idx)
1555 {
1556     if (!m_tabContainer || m_bLoadingProfile) {
1557         return;
1558     }
1559     KonqFrameBase *frm = m_tabContainer->tabAt(idx);
1560     QList<KonqView*> views = KonqViewCollector::collect(frm);
1561     for (KonqView *v : views) {
1562         if (v && v->isDelayed()) {
1563             v->loadDelayed();
1564         }
1565     }
1566 }