File indexing completed on 2024-04-21 04:58:19

0001 /* This file is part of the KDE project
0002     SPDX-FileCopyrightText: 1998, 1999 Simon Hausmann <hausmann@kde.org>
0003     SPDX-FileCopyrightText: 2000 Carsten Pfeiffer <pfeiffer@kde.org>
0004     SPDX-FileCopyrightText: 2000-2005 David Faure <faure@kde.org>
0005     SPDX-FileCopyrightText: 2007 Eduardo Robles Elvira <edulix@gmail.com>
0006     SPDX-FileCopyrightText: 2007 Daniel GarcĂ­a Moreno <danigm@gmail.com>
0007 
0008     SPDX-License-Identifier: GPL-2.0-or-later
0009 */
0010 
0011 #include "konqmainwindow.h"
0012 #include "konqmouseeventfilter.h"
0013 #include "konqclosedwindowsmanager.h"
0014 #include "konqsessionmanager.h"
0015 #include "konqsessiondlg.h"
0016 #include "konqdraggablelabel.h"
0017 #include "konqcloseditem.h"
0018 #include "konqapplication.h"
0019 #include "konqguiclients.h"
0020 #include "konqmainwindowfactory.h"
0021 #include "KonqMainWindowAdaptor.h"
0022 #include "KonquerorAdaptor.h"
0023 #include "konqview.h"
0024 #include "konqmisc.h"
0025 #include "konqviewmanager.h"
0026 #include "konqframestatusbar.h"
0027 #include "konqtabs.h"
0028 #include "konqactions.h"
0029 #include "konqsettingsxt.h"
0030 #include "konqextensionmanager.h"
0031 #include "konqueror_interface.h"
0032 #include "delayedinitializer.h"
0033 #include "konqextendedbookmarkowner.h"
0034 #include "konqframevisitor.h"
0035 #include "konqbookmarkbar.h"
0036 #include "konqundomanager.h"
0037 #include "konqhistorydialog.h"
0038 #include <config-konqueror.h>
0039 #include <kstringhandler.h>
0040 #include "konqurl.h"
0041 #include "implementations/konqbrowserwindowinterface.h"
0042 #include "urlloader.h"
0043 #include "pluginmetadatautils.h"
0044 #include "browseropenorsavequestion.h"
0045 #include "configdialog.h"
0046 #include "browserextension.h"
0047 
0048 #include <konq_events.h>
0049 #include <konqpixmapprovider.h>
0050 #include <konqsettings.h>
0051 #include <konq_spellcheckingconfigurationdispatcher.h>
0052 #include <kcmutils_version.h>
0053 #include "libkonq_utils.h"
0054 
0055 #include <kwidgetsaddons_version.h>
0056 #include <kxmlgui_version.h>
0057 #include <kparts_version.h>
0058 #include <kbookmarkmanager.h>
0059 #include <klineedit.h>
0060 #include <kzip.h>
0061 #include <pwd.h>
0062 // we define STRICT_ANSI to get rid of some warnings in glibc
0063 #ifndef __STRICT_ANSI__
0064 #define __STRICT_ANSI__
0065 #define _WE_DEFINED_IT_
0066 #endif
0067 #include <netdb.h>
0068 #ifdef _WE_DEFINED_IT_
0069 #undef __STRICT_ANSI__
0070 #undef _WE_DEFINED_IT_
0071 #endif
0072 #include <assert.h>
0073 #include <stdlib.h>
0074 #include <time.h>
0075 #include <sys/types.h>
0076 #include <sys/stat.h>
0077 #include <KIO/ApplicationLauncherJob>
0078 #include <KIO/OpenUrlJob>
0079 
0080 #include <QDesktopServices>
0081 #include <QFile>
0082 #include <QClipboard>
0083 #include <QStackedWidget>
0084 #include <QFileInfo>
0085 #include <QEvent>
0086 
0087 #if QT_VERSION_MAJOR < 6
0088 #include <QX11Info>
0089 #else
0090 #include <QtGui/private/qtx11extras_p.h>
0091 #endif
0092 
0093 #include <QKeyEvent>
0094 #include <QPixmap>
0095 #include <QLineEdit>
0096 #include <QNetworkProxy>
0097 
0098 #include <KPluginMetaData>
0099 #include <kaboutdata.h>
0100 #include <ktoolbar.h>
0101 #include <konqbookmarkmenu.h>
0102 #include <kcmultidialog.h>
0103 #include "konqdebug.h"
0104 #include <kdesktopfile.h>
0105 #include <kedittoolbar.h>
0106 #include <klocalizedstring.h>
0107 #include <kmessagebox.h>
0108 #include <knewfilemenu.h>
0109 #include <konq_popupmenu.h>
0110 #include "konqsettings.h"
0111 #include "konqanimatedlogo_p.h"
0112 #include <kprotocolinfo.h>
0113 #include <kprotocolmanager.h>
0114 #include <kstandardshortcut.h>
0115 #include <kstandardaction.h>
0116 #include <ksycoca.h>
0117 #include <QTemporaryFile>
0118 #include <ktogglefullscreenaction.h>
0119 #include <ktoolbarpopupaction.h>
0120 #include <kurlcompletion.h>
0121 #include <kurlrequesterdialog.h>
0122 #include <kurlrequester.h>
0123 #include <KJobWidgets>
0124 #include <KLocalizedString>
0125 #include <QIcon>
0126 #include <kiconloader.h>
0127 #include <QMenu>
0128 #include <kprocess.h>
0129 #include <KIO/JobUiDelegate>
0130 #include <KIO/CopyJob>
0131 #include <KIO/Job>
0132 #include <KIO/StatJob>
0133 #include <KIO/FileUndoManager>
0134 #include <KParts/OpenUrlEvent>
0135 #include <KCompletionMatches>
0136 #include <kacceleratormanager.h>
0137 #include <kuser.h>
0138 #include <kxmlguifactory.h>
0139 #include <sonnet/configdialog.h>
0140 #include <kwindowsystem.h>
0141 #include <netwm.h>
0142 #include <kio_version.h>
0143 #include <KIO/JobUiDelegateFactory>
0144 
0145 #include <kauthorized.h>
0146 #include <QDBusConnection>
0147 #include <QDBusMessage>
0148 #include <kconfiggroup.h>
0149 #include <kurlauthorized.h>
0150 #include <QFontDatabase>
0151 #include <QMenuBar>
0152 #include <QStandardPaths>
0153 #include <KSharedConfig>
0154 
0155 #include <KProtocolManager>
0156 #include <KParts/PartLoader>
0157 #include <KApplicationTrader>
0158 #include <KX11Extras>
0159 #include <KWindowInfo>
0160 
0161 #include <QMetaObject>
0162 #include <QMetaMethod>
0163 #include <QActionGroup>
0164 #include <QNetworkProxyFactory>
0165 #include <QNetworkProxyQuery>
0166 
0167 #include <KCModule>
0168 
0169 template class QList<QPixmap *>;
0170 template class QList<KToggleAction *>;
0171 
0172 static KBookmarkManager *s_bookmarkManager = nullptr;
0173 QList<KonqMainWindow *> *KonqMainWindow::s_lstMainWindows = nullptr;
0174 KConfig *KonqMainWindow::s_comboConfig = nullptr;
0175 KCompletion *KonqMainWindow::s_pCompletion = nullptr;
0176 
0177 KonqOpenURLRequest KonqOpenURLRequest::null;
0178 
0179 static const unsigned short int s_closedItemsListLength = 10;
0180 
0181 static void raiseWindow(KonqMainWindow *window)
0182 {
0183     if (!window) {
0184         return;
0185     }
0186 
0187     if (window->isMinimized()) {
0188         KX11Extras::unminimizeWindow(window->winId());
0189     }
0190     window->activateWindow();
0191     window->raise();
0192 }
0193 
0194 KonqExtendedBookmarkOwner::KonqExtendedBookmarkOwner(KonqMainWindow *w)
0195 {
0196     m_pKonqMainWindow = w;
0197 }
0198 
0199 KonqMainWindow::KonqMainWindow(const QUrl &initialURL)
0200     : KParts::MainWindow()
0201     , m_paClosedItems(nullptr)
0202     , m_fullyConstructed(false)
0203     , m_bLocationBarConnected(false)
0204     , m_bURLEnterLock(false)
0205     , m_urlCompletionStarted(false)
0206     , m_fullScreenData{FullScreenState::NoFullScreen, FullScreenState::NoFullScreen, true, true, false}
0207     , m_goBuffer(0)
0208     , m_pBookmarkMenu(nullptr)
0209     , m_configureDialog(nullptr)
0210     , m_pURLCompletion(nullptr)
0211     , m_isPopupWithProxyWindow(false)
0212     , m_uuid(QUuid::createUuid().toString())
0213 {
0214     Q_INIT_RESOURCE(konqueror);
0215     if (!s_lstMainWindows) {
0216         s_lstMainWindows = new QList<KonqMainWindow *>;
0217     }
0218 
0219     s_lstMainWindows->append(this);
0220 
0221     KonqMouseEventFilter::self(); // create it
0222 
0223     m_pChildFrame = nullptr;
0224     m_pActiveChild = nullptr;
0225     m_workingTab = 0;
0226     (void) new KonqMainWindowAdaptor(this);
0227     m_paBookmarkBar = nullptr;
0228 
0229     m_viewModesGroup = new QActionGroup(this);
0230     m_viewModesGroup->setExclusive(true);
0231     connect(m_viewModesGroup, SIGNAL(triggered(QAction*)),
0232             this, SLOT(slotViewModeTriggered(QAction*)),
0233             Qt::QueuedConnection); // Queued so that we don't delete the action from the code that triggered it.
0234 
0235     // This has to be called before any action is created for this mainwindow
0236     const KAboutData applicationData = KAboutData::applicationData();
0237     setComponentName(applicationData.componentName(), applicationData.displayName());
0238 
0239     m_pViewManager = new KonqViewManager(this);
0240     m_viewModeMenu = nullptr;
0241     m_openWithMenu = nullptr;
0242     m_paCopyFiles = nullptr;
0243     m_paMoveFiles = nullptr;
0244     m_bookmarkBarInitialized = false;
0245 
0246     m_toggleViewGUIClient = new ToggleViewGUIClient(this);
0247 
0248     m_pBookmarksOwner = new KonqExtendedBookmarkOwner(this);
0249 
0250     // init history-manager, load history, get completion object
0251     if (!s_pCompletion) {
0252         s_bookmarkManager = Konq::userBookmarksManager();
0253 
0254 #if QT_VERSION_MAJOR < 6
0255         // let the KBookmarkManager know that we are a browser, equals to "keditbookmarks --browser"
0256         s_bookmarkManager->setEditorOptions(QStringLiteral("konqueror"), true);
0257 #endif
0258 
0259         KonqHistoryManager *mgr = new KonqHistoryManager(s_bookmarkManager);
0260         s_pCompletion = mgr->completionObject();
0261 
0262         // setup the completion object before createGUI(), so that the combo
0263         // picks up the correct mode from the HistoryManager (in slotComboPlugged)
0264         int mode = KonqSettings::settingsCompletionMode();
0265         s_pCompletion->setCompletionMode(static_cast<KCompletion::CompletionMode>(mode));
0266     }
0267     connect(HistoryProvider::self(), &HistoryProvider::cleared, this, &KonqMainWindow::slotClearComboHistory);
0268 
0269     KonquerorApplication *app = qobject_cast<KonquerorApplication*>(qApp);
0270     if (app) {
0271         connect(this, &KonqMainWindow::aboutToConfigure, app, &KonquerorApplication::aboutToConfigure);
0272     }
0273 
0274     KonqPixmapProvider *prov = KonqPixmapProvider::self();
0275     if (!s_comboConfig) {
0276         s_comboConfig = new KConfig(QStringLiteral("konq_history"), KConfig::NoGlobals);
0277         KonqCombo::setConfig(s_comboConfig);
0278         KConfigGroup locationBarGroup(s_comboConfig, "Location Bar");
0279         prov->load(locationBarGroup, QStringLiteral("ComboIconCache"));
0280     }
0281 
0282     connect(prov, SIGNAL(changed()), SLOT(slotIconsChanged()));
0283 
0284     m_pUndoManager = new KonqUndoManager(KonqClosedWindowsManager::self(), this);
0285     connect(m_pUndoManager, SIGNAL(undoAvailable(bool)),
0286             this, SLOT(slotUndoAvailable(bool)));
0287 
0288     initCombo();
0289     initActions();
0290 
0291     setXMLFile(QStringLiteral("konqueror.rc"));
0292 
0293     setStandardToolBarMenuEnabled(true);
0294 
0295     createGUI(nullptr);
0296 
0297     m_combo->setParent(toolBar(QStringLiteral("locationToolBar")));
0298     m_combo->show();
0299 
0300     checkDisableClearButton();
0301 
0302     connect(toolBarMenuAction(), SIGNAL(triggered()), this, SLOT(slotForceSaveMainWindowSettings()));
0303 
0304     if (!m_toggleViewGUIClient->empty()) {
0305         plugActionList(QStringLiteral("toggleview"), m_toggleViewGUIClient->actions());
0306     } else {
0307         delete m_toggleViewGUIClient;
0308         m_toggleViewGUIClient = nullptr;
0309     }
0310 
0311     m_bNeedApplyKonqMainWindowSettings = true;
0312 
0313     if (!initialURL.isEmpty()) {
0314         openFilteredUrl(initialURL.url());
0315     } else {
0316         // silent
0317         m_bNeedApplyKonqMainWindowSettings = false;
0318     }
0319 
0320     resize(700, 480);
0321 
0322     updateProxyForWebEngine(false);
0323     QDBusConnection::sessionBus().connect("", QStringLiteral("/KIO/Scheduler"), QStringLiteral("org.kde.KIO.Scheduler"),
0324                                           QStringLiteral("reparseSlaveConfiguration"), this, SLOT(updateProxyForWebEngine()));
0325 
0326     KonqSessionManager::self()->registerMainWindow(this);
0327 
0328     setAutoSaveSettings();
0329 
0330     //qCDebug(KONQUEROR_LOG) << this << "created";
0331 
0332     m_fullyConstructed = true;
0333 }
0334 
0335 KonqMainWindow::~KonqMainWindow()
0336 {
0337     //qCDebug(KONQUEROR_LOG) << this;
0338 
0339     delete m_pViewManager;
0340     m_pViewManager = nullptr;
0341 
0342     if (s_lstMainWindows) {
0343         s_lstMainWindows->removeAll(this);
0344         if (s_lstMainWindows->isEmpty()) {
0345             delete s_lstMainWindows;
0346             s_lstMainWindows = nullptr;
0347         } else if (s_lstMainWindows->length() == 1 && s_lstMainWindows->first()->isPreloaded()) {
0348             //If the only remaining window is preloaded, we want to close it. Otherwise,
0349             //the application will remain open, even if there are no visible windows.
0350             //This can be seen, for example, running Konqueror from a terminal with the
0351             //"Always try to have a preloaded instance": even after closing the last
0352             //window, Konqueror won't exit (see bug #258124). To avoid this situation,
0353             //We close the preloaded window here, so that the application can exit,
0354             //and launch another instance of Konqueror from konqmain.
0355             s_lstMainWindows->first()->close();
0356         }
0357     }
0358 
0359     qDeleteAll(m_openWithActions);
0360     m_openWithActions.clear();
0361 
0362     delete m_pBookmarkMenu;
0363     delete m_paBookmarkBar;
0364     delete m_pBookmarksOwner;
0365     delete m_pURLCompletion;
0366     delete m_paClosedItems;
0367 
0368     if (s_lstMainWindows == nullptr) {
0369         delete s_comboConfig;
0370         s_comboConfig = nullptr;
0371     }
0372 
0373     delete m_configureDialog;
0374     m_configureDialog = nullptr;
0375     delete m_combo;
0376     m_combo = nullptr;
0377     delete m_locationLabel;
0378     m_locationLabel = nullptr;
0379     m_pUndoManager->disconnect();
0380     delete m_pUndoManager;
0381 
0382     //qCDebug(KONQUEROR_LOG) << this << "deleted";
0383 }
0384 
0385 QWidget *KonqMainWindow::createContainer(QWidget *parent, int index, const QDomElement &element, QAction *&containerAction)
0386 {
0387     QWidget *res = KParts::MainWindow::createContainer(parent, index, element, containerAction);
0388 
0389     static QString nameBookmarkBar = QStringLiteral("bookmarkToolBar");
0390     static QString tagToolBar = QStringLiteral("ToolBar");
0391     if (res && (element.tagName() == tagToolBar) && (element.attribute(QStringLiteral("name")) == nameBookmarkBar)) {
0392         Q_ASSERT(::qobject_cast<KToolBar *>(res));
0393         if (!KAuthorized::authorizeAction(QStringLiteral("bookmarks"))) {
0394             delete res;
0395             return nullptr;
0396         }
0397 
0398         if (!m_bookmarkBarInitialized) {
0399             // The actual menu needs a different action collection, so that the bookmarks
0400             // don't appear in kedittoolbar
0401             m_bookmarkBarInitialized = true;
0402             DelayedInitializer *initializer = new DelayedInitializer(QEvent::Show, res);
0403             connect(initializer, &DelayedInitializer::initialize, this, &KonqMainWindow::initBookmarkBar);
0404         }
0405     }
0406 
0407     if (res && element.tagName() == QLatin1String("Menu")) {
0408         const QString &menuName = element.attribute(QStringLiteral("name"));
0409         if (menuName == QLatin1String("edit") || menuName == QLatin1String("tools")) {
0410             Q_ASSERT(qobject_cast<QMenu *>(res));
0411             KAcceleratorManager::manage(static_cast<QMenu *>(res));
0412         }
0413     }
0414 
0415     return res;
0416 }
0417 
0418 void KonqMainWindow::initBookmarkBar()
0419 {
0420     KToolBar *bar = this->findChild<KToolBar *>(QStringLiteral("bookmarkToolBar"));
0421 
0422     if (!bar) {
0423         return;
0424     }
0425 
0426     const bool wasVisible = bar->isVisible();
0427 
0428     delete m_paBookmarkBar;
0429     m_paBookmarkBar = new KBookmarkBar(s_bookmarkManager, m_pBookmarksOwner, bar, this);
0430 
0431     // hide if empty
0432     if (bar->actions().count() == 0 || !wasVisible) {
0433         bar->hide();
0434     }
0435 }
0436 
0437 void KonqMainWindow::removeContainer(QWidget *container, QWidget *parent, QDomElement &element, QAction *containerAction)
0438 {
0439     static QString nameBookmarkBar = QStringLiteral("bookmarkToolBar");
0440     static QString tagToolBar = QStringLiteral("ToolBar");
0441 
0442     if (element.tagName() == tagToolBar && element.attribute(QStringLiteral("name")) == nameBookmarkBar) {
0443         Q_ASSERT(::qobject_cast<KToolBar *>(container));
0444         if (m_paBookmarkBar) {
0445             m_paBookmarkBar->clear();
0446         }
0447     }
0448 
0449     KParts::MainWindow::removeContainer(container, parent, element, containerAction);
0450 }
0451 
0452 // Detect a name filter (e.g. *.txt) in the url.
0453 // Note that KShortURIFilter does the same, but we have no way of getting it from there
0454 //
0455 // Note: this removes the filter from the URL.
0456 QString KonqMainWindow::detectNameFilter(QUrl &url)
0457 {
0458     if (!KProtocolManager::supportsListing(url)) {
0459         return QString();
0460     }
0461 
0462     // Look for wildcard selection
0463     QString nameFilter;
0464     QString path = url.path();
0465     int lastSlash = path.lastIndexOf('/');
0466     if (lastSlash > -1) {
0467         if (!url.query().isEmpty() && lastSlash == path.length() - 1) {  //  In /tmp/?foo, foo isn't a query
0468             path += url.query(); // includes the '?'
0469         }
0470         QString fileName = path.mid(lastSlash + 1);
0471         if (fileName.indexOf('*') != -1 || fileName.indexOf('[') != -1 || fileName.indexOf('?') != -1) {
0472             // Check that a file or dir with all the special chars in the filename doesn't exist
0473             if (url.isLocalFile()) {
0474                 if (!QFile(url.toLocalFile()).exists()) {
0475                     nameFilter = fileName;
0476                 }
0477             } else { // not a local file
0478 #if QT_VERSION_MAJOR < 6
0479                 KIO::StatJob *job = KIO::statDetails(url, KIO::StatJob::DestinationSide, KIO::StatBasic, KIO::HideProgressInfo);
0480 #else
0481                 KIO::StatJob *job = KIO::stat(url, KIO::StatJob::DestinationSide, KIO::StatBasic, KIO::HideProgressInfo);
0482 #endif
0483                 // if there's an error stat'ing url, then assume it doesn't exist
0484                 nameFilter = !job->exec() ? fileName : QString();
0485             }
0486 
0487             if (!nameFilter.isEmpty()) {
0488                 url = url.adjusted(QUrl::RemoveFilename | QUrl::RemoveQuery);
0489                 qCDebug(KONQUEROR_LOG) << "Found wildcard. nameFilter=" << nameFilter << "  New url=" << url;
0490             }
0491         }
0492     }
0493 
0494     return nameFilter;
0495 }
0496 
0497 void KonqMainWindow::openFilteredUrl(const QString &url, const KonqOpenURLRequest &req)
0498 {
0499     // Filter URL to build a correct one
0500     if (m_currentDir.isEmpty() && m_currentView) {
0501         m_currentDir = m_currentView->url();
0502     }
0503 
0504     QUrl filteredURL(KonqMisc::konqFilteredURL(this, url, m_currentDir));
0505     qCDebug(KONQUEROR_LOG) << "url" << url << "filtered into" << filteredURL;
0506 
0507     if (filteredURL.isEmpty()) { // initially empty, or error (e.g. ~unknown_user)
0508         return;
0509     }
0510 
0511     m_currentDir.clear();
0512 
0513     openUrl(nullptr, filteredURL, QString(), req);
0514 
0515     // #4070: Give focus to view after URL was entered manually
0516     // Note: we do it here if the view mode (i.e. part) wasn't changed
0517     // If it is changed, then it's done in KonqViewManager::doSetActivePart
0518     if (m_currentView) {
0519         m_currentView->setFocus();
0520     }
0521 }
0522 
0523 void KonqMainWindow::openFilteredUrl(const QString &_url, bool inNewTab, bool tempFile)
0524 {
0525     KonqOpenURLRequest req(_url);
0526     req.browserArgs.setNewTab(inNewTab);
0527     req.newTabInFront = true;
0528     req.tempFile = tempFile;
0529 
0530     openFilteredUrl(_url, req);
0531 }
0532 
0533 void KonqMainWindow::openFilteredUrl(const QString &_url,  const QString &_mimeType, bool inNewTab, bool tempFile)
0534 {
0535     KonqOpenURLRequest req(_url);
0536     req.browserArgs.setNewTab(inNewTab);
0537     req.newTabInFront = true;
0538     req.tempFile = tempFile;
0539     req.args.setMimeType(_mimeType);
0540 
0541     openFilteredUrl(_url, req);
0542 }
0543 
0544 void KonqMainWindow::openUrl(KonqView *_view, const QUrl &_url,
0545                              const QString &_mimeType, const KonqOpenURLRequest &_req,
0546                              bool trustedSource)
0547 {
0548 #ifndef NDEBUG // needed for req.debug()
0549     qCDebug(KONQUEROR_LOG) << "url=" << _url << "mimeType=" << _mimeType
0550              << "_req=" << _req.debug() << "view=" << _view;
0551 #endif
0552     // We like modifying args in this method :)
0553     QUrl url(_url);
0554     QString mimeType(_mimeType);
0555     KonqOpenURLRequest req(_req);
0556 
0557     if (mimeType.isEmpty()) {
0558         mimeType = req.args.mimeType();
0559     }
0560 
0561     static const QStringList s_validProtocols {QStringLiteral("error"), QStringLiteral("mailto"), QStringLiteral("data"), QStringLiteral("blob")};
0562     if (!url.isValid()) {
0563         // I think we can't really get here anymore; I tried and didn't succeed.
0564         // URL filtering catches this case before hand, and in cases without filtering
0565         // (e.g. HTML link), the url is empty here, not invalid.
0566         // But just to be safe, let's keep this code path
0567         url = Konq::makeErrorUrl(KIO::ERR_MALFORMED_URL, url.url(), url);
0568     } else if (!KProtocolInfo::isKnownProtocol(url) && !KonqUrl::hasKonqScheme(url) && !s_validProtocols.contains(url.scheme())) {
0569         url = Konq::makeErrorUrl(KIO::ERR_UNSUPPORTED_PROTOCOL, url.scheme(), url);
0570     }
0571 
0572     const QString nameFilter = detectNameFilter(url);
0573     if (!nameFilter.isEmpty()) {
0574         req.nameFilter = nameFilter;
0575         url = url.adjusted(QUrl::RemoveFilename);
0576     }
0577 
0578     QLineEdit *edit = comboEdit();
0579     if (edit) {
0580         edit->setModified(false);
0581     }
0582 
0583     KonqView *view = _view;
0584 
0585     UrlLoader *loader = new UrlLoader(this, view, url, mimeType, req, trustedSource, false);
0586     connect(loader, &UrlLoader::finished, this, &KonqMainWindow::urlLoaderFinished);
0587 
0588     loader->start();
0589 
0590     // The URL should be opened in a new tab. Let's create the tab right away,
0591     // it gives faster user feedback (#163628). For a short while (kde-4.1-beta1)
0592     // I removed this entire block so that we wouldn't end up with a useless tab when
0593     // launching an external application for this mimetype. But user feedback
0594     // in all cases is more important than empty tabs in some cases.
0595     if (loader->viewToUse() == UrlLoader::ViewToUse::NewTab) {
0596         view = createTabForLoadUrlRequest(loader->url(), loader->request());
0597         if (!view) {
0598             loader->setNewTab(false);
0599         }
0600     } else if (loader->viewToUse() == UrlLoader::ViewToUse::CurrentView) {
0601         view = m_currentView;
0602     }
0603 
0604     const QString oldLocationBarURL = locationBarURL();
0605     if (view) {
0606         if (view == m_currentView) {
0607             //will do all the stuff below plus GUI stuff
0608             abortLoading();
0609         } else {
0610             view->stop();
0611             // Don't change location bar if not current view
0612         }
0613     }
0614     loader->setView(view);
0615     loader->setOldLocationBarUrl(oldLocationBarURL);
0616 
0617     if (loader->isAsync()) {
0618         bool earlySetLocationBarURL = false;
0619         if (!view && !m_currentView) { // no view yet, e.g. starting with url as argument
0620             earlySetLocationBarURL = true;
0621         } else if (view == m_currentView && view->url().isEmpty()) { // opening in current view
0622             earlySetLocationBarURL = true;
0623         }
0624         if (req.browserArgs.newTab()) { // it's going into a new tab anyway
0625             earlySetLocationBarURL = false;
0626         }
0627         if (earlySetLocationBarURL) {
0628             // Show it for now in the location bar, but we'll need to store it in the view
0629             // later on (can't do it yet since either view == 0 or updateHistoryEntry will be called).
0630             qCDebug(KONQUEROR_LOG) << "url=" << url;
0631             setLocationBarURL(url);
0632         }
0633         if (view == m_currentView) {
0634             startAnimation();
0635         }
0636     }
0637     loader->goOn();
0638 }
0639 
0640 void KonqMainWindow::urlLoaderFinished(UrlLoader* loader)
0641 {
0642     if (loader->hasError()) {   // we had an error
0643         QDBusMessage message = QDBusMessage::createSignal(KONQ_MAIN_PATH, QStringLiteral("org.kde.Konqueror.Main"), QStringLiteral("removeFromCombo"));
0644         message << loader->url().toDisplayString();
0645         QDBusConnection::sessionBus().send(message);
0646     }
0647 
0648     KonqView *childView = loader->view();
0649 
0650     // Check if we found a mimetype _and_ we got no error (example: cancel in openwith dialog)
0651     if (!loader->mimeType().isEmpty() && !loader->hasError()) {
0652 
0653         // We do this here and not in the constructor, because
0654         // we are waiting for the first view to be set up before doing this...
0655         // Note: this is only used when konqueror is started from command line.....
0656         if (m_bNeedApplyKonqMainWindowSettings) {
0657             m_bNeedApplyKonqMainWindowSettings = false; // only once
0658             applyKonqMainWindowSettings();
0659         }
0660 
0661         return;
0662     }
0663 
0664     // An error happened in UrlLoader - stop wheel etc.
0665 
0666     if (childView) {
0667         childView->setLoading(false);
0668 
0669         if (childView == m_currentView) {
0670             stopAnimation();
0671 
0672             // Revert to working URL - unless the URL was typed manually
0673             if (loader->request().typedUrl.isEmpty() && childView->currentHistoryEntry()) { // not typed
0674                 childView->setLocationBarURL(childView->currentHistoryEntry()->locationBarURL);
0675             }
0676         }
0677     } else { // No view, e.g. starting up empty
0678         stopAnimation();
0679     }
0680 }
0681 
0682 KonqView * KonqMainWindow::createTabForLoadUrlRequest(const QUrl& url, const KonqOpenURLRequest& request)
0683 {
0684     KonqView *view = m_pViewManager->addTab(QStringLiteral("text/html"),
0685                                     QString(),
0686                                     false,
0687                                     request.openAfterCurrentPage);
0688     if (view) {
0689         view->setCaption(i18nc("@title:tab", "Loading..."));
0690         view->setLocationBarURL(url);
0691         if (!request.browserArgs.frameName.isEmpty()) {
0692             view->setViewName(request.browserArgs.frameName);    // #44961
0693         }
0694 
0695         if (request.newTabInFront) {
0696             m_pViewManager->showTab(view);
0697         }
0698 
0699         updateViewActions(); //A new tab created -- we may need to enable the "remove tab" button (#56318)
0700     }
0701     return view;
0702 }
0703 
0704 
0705 // When opening a new view, for @p mimeType, prefer the part used in @p currentView, if possible.
0706 // Testcase: window.open after manually switching to another web engine, and with "open popups in tabs" off.
0707 static QString preferredService(KonqView *currentView, const QString &mimeType)
0708 {
0709     if (currentView && !mimeType.isEmpty() && currentView->supportsMimeType(mimeType)) {
0710         return currentView->service().pluginId();
0711     }
0712     return QString();
0713 }
0714 
0715 //TODO After removing KonqRun: some of this becomes redundant, at least when called via UrlLoader. Can this be avoided?
0716 bool KonqMainWindow::openView(QString mimeType, const QUrl &_url, KonqView *childView, const KonqOpenURLRequest &req, QUrl requestedUrl)
0717 {
0718     // Second argument is referring URL
0719     if (!KUrlAuthorized::authorizeUrlAction(QStringLiteral("open"), childView ? childView->url() : QUrl(), _url)) {
0720         QString msg = KIO::buildErrorString(KIO::ERR_ACCESS_DENIED, _url.toDisplayString());
0721         QMessageBox::warning(this, i18n("Access denied"), msg);
0722         return true; // Nothing else to do.
0723     }
0724 
0725 //TODO Remove KonqRun: the following lines prevent embedding script files. If the user chose, from UrlLoader, not to
0726 //execute a script but to open it, it should be embedded or opened in a separate viewer according to the user
0727 //preferences. With the check below, instead, it'll always been opened in the external application.
0728 //Are there situations when this check is needed? When this function is called by UrlLoader, it's not necessary
0729 //because UrlLoader only calls it if the user chose to embed the URL. The only other caller of this function
0730 //seems to be KonqViewManager::loadItem, which uses it when restoring or duplicating a view. Since a view can't
0731 //contain an executed program, I think we can assume that the file should be embedded.
0732 //     if (UrlLoader::isExecutable(mimeType)) {
0733 //         return false;    // execute, don't open
0734 //     }
0735 
0736     // Contract: the caller of this method should ensure the view is stopped first.
0737 
0738 #ifndef NDEBUG
0739     qCDebug(KONQUEROR_LOG) << mimeType << _url << "childView=" << childView << "req:" << req.debug();
0740 #endif
0741     bool bOthersFollowed = false;
0742 
0743     if (childView) {
0744         // If we're not already following another view (and if we are not reloading)
0745         if (!req.followMode && !req.args.reload() && !m_pViewManager->isLoadingProfile()) {
0746             // When clicking a 'follow active' view (e.g. childView is the sidebar),
0747             // open the URL in the active view
0748             // (it won't do anything itself, since it's locked to its location)
0749             if (childView->isFollowActive() && childView != m_currentView) {
0750                 abortLoading();
0751                 setLocationBarURL(_url);
0752                 KonqOpenURLRequest newreq;
0753                 newreq.forceAutoEmbed = true;
0754                 newreq.followMode = true;
0755                 newreq.args = req.args;
0756                 newreq.browserArgs = req.browserArgs;
0757                 bOthersFollowed = openView(mimeType, _url, m_currentView, newreq);
0758             }
0759             // "link views" feature, and "sidebar follows active view" feature
0760             bOthersFollowed = makeViewsFollow(_url, req.args, req.browserArgs, mimeType, childView) || bOthersFollowed;
0761         }
0762         if (childView->isLockedLocation() && !req.args.reload() /* allow to reload a locked view*/) {
0763             return bOthersFollowed;
0764         }
0765     }
0766 
0767     QUrl url(_url);
0768 
0769     // In case we open an index.html, we want the location bar
0770     // to still display the original URL (so that 'up' uses that URL,
0771     // and since that's what the user entered).
0772     // changePart will take care of setting and storing that url.
0773     QString originalURL = url.toDisplayString(QUrl::PreferLocalFile);
0774     if (!req.nameFilter.isEmpty()) { // keep filter in location bar
0775         if (!originalURL.endsWith('/')) {
0776             originalURL += '/';
0777         }
0778         originalURL += req.nameFilter;
0779     } else {
0780         //If the part requesting the download wants to perform the download itself,
0781         //url will contain the url of the local file, but in the location bar we
0782         //want to display the remote URL
0783         if (!requestedUrl.isEmpty()) {
0784             originalURL = requestedUrl.toString();
0785         }
0786     }
0787 
0788     QString serviceName = req.serviceName; // default: none provided
0789 
0790     const QString urlStr = url.url();
0791     if (KonqUrl::isValidNotBlank(urlStr)) {
0792         mimeType = QStringLiteral("text/html");
0793         originalURL = req.typedUrl.isEmpty() ? QString() : req.typedUrl;
0794     } else if (KonqUrl::isKonqBlank(urlStr) && req.typedUrl.isEmpty()) {
0795         originalURL.clear();
0796     }
0797 
0798     bool forceAutoEmbed = req.forceAutoEmbed || req.userRequestedReload;
0799     if (!req.typedUrl.isEmpty()) { // the user _typed_ the URL, he wants it in Konq.
0800         forceAutoEmbed = true;
0801     }
0802     if (KonqUrl::hasKonqScheme(url) || url.scheme() == QLatin1String("error")) {
0803         forceAutoEmbed = true;
0804     }
0805     // Related to KonqFactory::createView
0806     if (!forceAutoEmbed && !KonqFMSettings::settings()->shouldEmbed(mimeType)) {
0807         qCDebug(KONQUEROR_LOG) << "KonqFMSettings says: don't embed this servicetype";
0808         return false;
0809     }
0810     // Do we even have a part to embed? Otherwise don't ask, since we'd ask twice.
0811     if (!forceAutoEmbed) {
0812         QVector<KPluginMetaData> partServiceOffers;
0813         KonqFactory::getOffers(mimeType, &partServiceOffers);
0814         if (partServiceOffers.isEmpty()) {
0815             qCDebug(KONQUEROR_LOG) << "No part available for" << mimeType;
0816             return false;
0817         }
0818     }
0819 
0820     // If the protocol doesn't support writing (e.g. HTTP) then we might want to save instead of just embedding.
0821     // So (if embedding would succeed, hence the checks above) we ask the user
0822     // Otherwise the user will get asked 'open or save' in openUrl anyway.
0823     //TODO KF6: remove commented code below. This shouldn't be needed, since UrlLoader
0824     //already asked the user whether to save or to embed
0825     // if (!forceAutoEmbed && !KProtocolManager::supportsWriting(url)) {
0826     //     QString suggestedFileName;
0827     //     UrlLoader *loader = childView ? childView->urlLoader() : nullptr;
0828     //     if (loader) {
0829     //         suggestedFileName = loader->suggestedFileName();
0830     //     }
0831     //
0832     //     BrowserOpenOrSaveQuestion dlg(this, url, mimeType);
0833     //     dlg.setSuggestedFileName(suggestedFileName);
0834     //     const BrowserOpenOrSaveQuestion::Result res = dlg.askEmbedOrSave();
0835     //     if (res == BrowserOpenOrSaveQuestion::Embed) {
0836     //         forceAutoEmbed = true;
0837     //     } else if (res == BrowserOpenOrSaveQuestion::Cancel) {
0838     //         return true;    // handled, don't do anything else
0839     //     } else { // Save
0840     //         KParts::BrowserRun::saveUrl(url, suggestedFileName, this, req.args);
0841     //         return true; // handled
0842     //     }
0843     // }
0844 
0845     bool ok = true;
0846     if (!childView) {
0847         if (req.browserArgs.newTab()) {
0848             KonqFrameTabs *tabContainer = m_pViewManager->tabContainer();
0849             int index = tabContainer->currentIndex();
0850             childView = m_pViewManager->addTab(mimeType, serviceName, false, req.openAfterCurrentPage);
0851 
0852             if (req.newTabInFront && childView) {
0853                 if (req.openAfterCurrentPage) {
0854                     tabContainer->setCurrentIndex(index + 1);
0855                 } else {
0856                     tabContainer->setCurrentIndex(tabContainer->count() - 1);
0857                 }
0858             }
0859         }
0860 
0861         else {
0862             // Create a new view
0863             // createFirstView always uses force auto-embed even if user setting is "separate viewer",
0864             // since this window has no view yet - we don't want to keep an empty mainwindow.
0865             // This can happen with e.g. application/pdf from a target="_blank" link, or window.open.
0866             childView = m_pViewManager->createFirstView(mimeType, serviceName);
0867 
0868             if (childView) {
0869                 enableAllActions(true);
0870                 m_currentView = childView;
0871             }
0872         }
0873 
0874         if (!childView) {
0875             return false;    // It didn't work out.
0876         }
0877 
0878         childView->setViewName(m_initialFrameName.isEmpty() ? req.browserArgs.frameName : m_initialFrameName);
0879         m_initialFrameName.clear();
0880     } else { // We know the child view
0881         if (!childView->isLockedViewMode()) {
0882             if (ok) {
0883 
0884                 // When typing a new URL, the current context doesn't matter anymore
0885                 // -> select the preferred part for a given mimetype (even if the current part can handle this mimetype).
0886                 // This fixes the "get katepart and then type a website URL -> loaded into katepart" problem
0887                 // (first fixed in r168902 from 2002!, see also unittest KonqHtmlTest::textThenHtml())
0888 
0889                 if (!req.typedUrl.isEmpty() || !serviceName.isEmpty()) {
0890                     if (childView->isLoading()) { // Stop the view first, #282641.
0891                         childView->stop();
0892                     }
0893                     ok = childView->changePart(mimeType, serviceName, forceAutoEmbed);
0894                 } else {
0895                     ok = childView->ensureViewSupports(mimeType, forceAutoEmbed);
0896                 }
0897             }
0898         }
0899     }
0900 
0901     if (ok) {
0902         //qCDebug(KONQUEROR_LOG) << "req.nameFilter= " << req.nameFilter;
0903         //qCDebug(KONQUEROR_LOG) << "req.typedUrl= " << req.typedUrl;
0904         //qCDebug(KONQUEROR_LOG) << "Browser extension? " << (childView->browserExtension() ? "YES" : "NO");
0905         //qCDebug(KONQUEROR_LOG) << "Referrer: " << req.args.metaData()["referrer"];
0906         childView->setTypedURL(req.typedUrl);
0907         if (childView->part()) {
0908             childView->part()->setArguments(req.args);
0909         }
0910         if (childView->browserExtension()) {
0911 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
0912             childView->browserExtension()->setBrowserArguments(req.browserArgs);
0913 #else
0914             if (auto browserExt = qobject_cast<BrowserExtension *>(childView->browserExtension())) {
0915                 browserExt->setBrowserArguments(req.browserArgs);
0916             }
0917 #endif
0918         }
0919 
0920         // see dolphinpart
0921         childView->part()->setProperty("filesToSelect", QVariant::fromValue(req.filesToSelect));
0922 
0923         if (!url.isEmpty()) {
0924 
0925             childView->openUrl(url, originalURL, req.nameFilter, req.tempFile, requestedUrl);
0926         }
0927     }
0928     //qCDebug(KONQUEROR_LOG) << "ok=" << ok << "bOthersFollowed=" << bOthersFollowed
0929     //             << "returning" << (ok || bOthersFollowed);
0930     return ok || bOthersFollowed;
0931 }
0932 
0933 static KonqView *findChildView(KParts::ReadOnlyPart *callingPart, const QString &name, KonqMainWindow *&mainWindow, KParts::ReadOnlyPart **part)
0934 {
0935     if (!KonqMainWindow::mainWindowList()) {
0936         return nullptr;
0937     }
0938 
0939     for (KonqMainWindow *window: *KonqMainWindow::mainWindowList()) {
0940         KonqView *res = window->childView(callingPart, name, part);
0941         if (res) {
0942             mainWindow = window;
0943             return res;
0944         }
0945     }
0946 
0947     return nullptr;
0948 }
0949 
0950 void KonqMainWindow::slotOpenURLRequest(const QUrl &url, KonqOpenURLRequest &req)
0951 {
0952     //qCDebug(KONQUEROR_LOG) << "frameName=" << browserArgs.frameName;
0953 
0954     QString frameName = req.browserArgs.frameName;
0955 
0956     if (!frameName.isEmpty()) {
0957         static QString _top = QStringLiteral("_top");
0958         static QString _self = QStringLiteral("_self");
0959         static QString _parent = QStringLiteral("_parent");
0960         static QString _blank = QStringLiteral("_blank");
0961 
0962         if (frameName.toLower() == _blank) {
0963             KonqMainWindow *mainWindow = (m_popupProxyWindow ? m_popupProxyWindow.data() : this);
0964             mainWindow->slotCreateNewWindow(url, req);
0965             if (m_isPopupWithProxyWindow) {
0966                 raiseWindow(mainWindow);
0967             }
0968             return;
0969         }
0970 
0971         if (frameName.toLower() != _top &&
0972                 frameName.toLower() != _self &&
0973                 frameName.toLower() != _parent) {
0974             KonqView *view = childView(req.requestingPart, frameName, nullptr);
0975             if (!view) {
0976                 KonqMainWindow *mainWindow = nullptr;
0977                 view = findChildView(req.requestingPart, frameName, mainWindow, nullptr);
0978 
0979                 if (!view || !mainWindow) {
0980                     slotCreateNewWindow(url, req);
0981                     return;
0982                 }
0983 
0984                 mainWindow->openUrl(view, url, req);
0985                 return;
0986             }
0987 
0988             openUrl(view, url, req);
0989             return;
0990         }
0991     }
0992 
0993     KonqView *view = req.browserArgs.newTab() ? nullptr : childView(req.requestingPart);
0994     openUrl(view, url, req);
0995 }
0996 
0997 //Called by slotOpenURLRequest
0998 void KonqMainWindow::openUrl(KonqView *childView, const QUrl &url, KonqOpenURLRequest &req)
0999 {
1000     //qCDebug(KONQUEROR_LOG) << "url=" << url;
1001     openUrl(childView, url, req.args.mimeType(), req, req.browserArgs.trustedSource);
1002 }
1003 
1004 QObject *KonqMainWindow::lastFrame(KonqView *view)
1005 {
1006     QObject *nextFrame, *viewFrame;
1007     nextFrame = view->frame();
1008     viewFrame = nullptr;
1009     while (nextFrame != nullptr && !::qobject_cast<QStackedWidget *>(nextFrame)) {
1010         viewFrame = nextFrame;
1011         nextFrame = nextFrame->parent();
1012     }
1013     return nextFrame ? viewFrame : nullptr;
1014 }
1015 
1016 // Linked-views feature, plus "sidebar follows URL opened in the active view" feature
1017 bool KonqMainWindow::makeViewsFollow(const QUrl &url,
1018                                      const KParts::OpenUrlArguments &args,
1019                                      const BrowserArguments &browserArgs,
1020                                      const QString &serviceType, KonqView *senderView)
1021 {
1022     if (!senderView->isLinkedView() && senderView != m_currentView) {
1023         return false;    // none of those features apply -> return
1024     }
1025 
1026     bool res = false;
1027     //qCDebug(KONQUEROR_LOG) << senderView->metaObject()->className() << "url=" << url << "serviceType=" << serviceType;
1028     KonqOpenURLRequest req;
1029     req.forceAutoEmbed = true;
1030     req.followMode = true;
1031     req.args = args;
1032     req.browserArgs = browserArgs;
1033     // We can't iterate over the map here, and openUrl for each, because the map can get modified
1034     // (e.g. by part changes). Better copy the views into a list.
1035     const QList<KonqView *> listViews = m_mapViews.values();
1036 
1037     QObject *senderFrame = lastFrame(senderView);
1038 
1039     for (KonqView *view: listViews) {
1040         if (view == senderView) {
1041             continue;
1042         }
1043         bool followed = false;
1044         // Views that should follow this URL as both views are linked
1045         if (view->isLinkedView() && senderView->isLinkedView()) {
1046             QObject *viewFrame = lastFrame(view);
1047 
1048             // Only views in the same tab of the sender will follow
1049             if (senderFrame && viewFrame && viewFrame != senderFrame) {
1050                 continue;
1051             }
1052 
1053             qCDebug(KONQUEROR_LOG) << "sending openUrl to view" << view->part()->metaObject()->className() << "url=" << url;
1054 
1055             // XXX duplicate code from ::openUrl
1056             if (view == m_currentView) {
1057                 abortLoading();
1058                 setLocationBarURL(url);
1059             } else {
1060                 view->stop();
1061             }
1062 
1063             followed = openView(serviceType, url, view, req);
1064         } else {
1065             // Make the sidebar follow the URLs opened in the active view
1066             if (view->isFollowActive() && senderView == m_currentView) {
1067                 followed = openView(serviceType, url, view, req);
1068             }
1069         }
1070 
1071         // Ignore return value if the view followed but doesn't really
1072         // show the file contents. We still want to see that
1073         // file, e.g. in a separate viewer.
1074         // This happens in views locked to a directory mode,
1075         // like sidebar and konsolepart (#52161).
1076         const bool ignore = view->isLockedViewMode() && view->showsDirectory();
1077         //qCDebug(KONQUEROR_LOG) << "View " << view->service()->name()
1078         //              << " supports dirs: " << view->showsDirectory()
1079         //              << " is locked-view-mode:" << view->isLockedViewMode()
1080         //              << " ignore=" << ignore;
1081         if (!ignore) {
1082             res = followed || res;
1083         }
1084     }
1085 
1086     return res;
1087 }
1088 
1089 void KonqMainWindow::abortLoading()
1090 {
1091     if (m_currentView) {
1092         m_currentView->stop(); // will take care of the statusbar
1093         stopAnimation();
1094     }
1095 }
1096 
1097 // Are there any indications that this window has a strong popup
1098 // nature and should therefore not be embedded into a tab?
1099 static bool isPopupWindow(const WindowArgs &windowArgs)
1100 {
1101     // ### other settings to respect?
1102     return windowArgs.x() != -1 || windowArgs.y() != -1 ||
1103            windowArgs.width() != -1 || windowArgs.height() != -1 ||
1104            !windowArgs.isMenuBarVisible() ||
1105            !windowArgs.toolBarsVisible() ||
1106            !windowArgs.isStatusBarVisible();
1107 }
1108 
1109 // This is called for the javascript window.open call.
1110 // Also called for MMB on link, target="_blank" link, MMB on folder, etc.
1111 void KonqMainWindow::slotCreateNewWindow(const QUrl &url, KonqOpenURLRequest &req,
1112         const WindowArgs &windowArgs, KParts::ReadOnlyPart **part)
1113 {
1114     // NOTE: 'part' may be null
1115 
1116     qCDebug(KONQUEROR_LOG) << "url=" << url << "args.mimeType()=" << req.args.mimeType()
1117              << "browserArgs.frameName=" << req.browserArgs.frameName;
1118 
1119     // If we are a popup window, forward the request the proxy window.
1120     if (m_isPopupWithProxyWindow && m_popupProxyWindow) {
1121         m_popupProxyWindow->slotCreateNewWindow(url, req, windowArgs, part);
1122         raiseWindow(m_popupProxyWindow);
1123         return;
1124     }
1125 
1126     if (part) {
1127         *part = nullptr;    // Make sure to be initialized in case of failure...
1128     }
1129 
1130     KonqMainWindow *mainWindow = nullptr;
1131     if (!req.browserArgs.frameName.isEmpty() && req.browserArgs.frameName.toLower() != QLatin1String("_blank")) {
1132         KParts::ReadOnlyPart *ro_part = nullptr;
1133         KParts::NavigationExtension *be = ::qobject_cast<KParts::NavigationExtension *>(sender());
1134         if (be) {
1135             ro_part = ::qobject_cast<KParts::ReadOnlyPart *>(be->parent());
1136         }
1137         if (findChildView(ro_part, req.browserArgs.frameName, mainWindow, part)) {
1138             // Found a view. If url isn't empty, we should open it - but this never happens currently
1139             // findChildView put the resulting part in 'part', so we can just return now
1140             //qCDebug(KONQUEROR_LOG) << "frame=" << req.browserArgs.frameName << "-> found part=" << part << part->name();
1141             return;
1142         }
1143     }
1144 
1145     bool createTab = req.browserArgs.newTab();
1146     if (!createTab && !req.browserArgs.forcesNewWindow() /* explicit "Open in New Window" action, e.g. on frame or history item */) {
1147         if (req.args.actionRequestedByUser()) { // MMB or some RMB popupmenu action
1148             createTab = KonqSettings::mmbOpensTab();
1149         } else { // Javascript popup
1150             createTab = KonqSettings::popupsWithinTabs() &&
1151                         !isPopupWindow(windowArgs);
1152         }
1153     }
1154     qCDebug(KONQUEROR_LOG) << "createTab=" << createTab << "part=" << part;
1155 
1156     if (createTab && !m_isPopupWithProxyWindow) {
1157 
1158         bool newtabsinfront = !windowArgs.lowerWindow();
1159         if (KonqSettings::newTabsInFront()) {
1160             newtabsinfront = !newtabsinfront;
1161         }
1162         const bool aftercurrentpage = KonqSettings::openAfterCurrentPage();
1163 
1164         // Can we use the standard way (openUrl), or do we need the part pointer immediately?
1165         if (!part) {
1166             req.browserArgs.setNewTab(true);
1167             req.forceAutoEmbed = true; // testcase: MMB on link-to-PDF, when pdf setting is "show file in external browser".
1168             req.newTabInFront = newtabsinfront;
1169             req.openAfterCurrentPage = aftercurrentpage;
1170             openUrl(nullptr, url, req.args.mimeType(), req);
1171         } else {
1172             KonqView *newView = m_pViewManager->addTab(QStringLiteral("text/html"), QString(), false, aftercurrentpage);
1173             if (newView == nullptr) {
1174                 return;
1175             }
1176 
1177             if (newtabsinfront) {
1178                 m_pViewManager->showTab(newView);
1179             }
1180 
1181             openUrl(newView, url.isEmpty() ? KonqUrl::url(KonqUrl::Type::Blank) : url, QString(), req);
1182             newView->setViewName(req.browserArgs.frameName);
1183 
1184             *part = newView->part();
1185         }
1186 
1187         // Raise the current window if the request to create the tab came from a popup
1188         // window, e.g. clicking on links with target = "_blank" in popup windows.
1189         KParts::NavigationExtension *be = qobject_cast<KParts::NavigationExtension *>(sender());
1190         KonqView *view = (be ? childView(qobject_cast<KParts::ReadOnlyPart *>(be->parent())) : nullptr);
1191         KonqMainWindow *window = view ? view->mainWindow() : nullptr;
1192         if (window && window->m_isPopupWithProxyWindow && !m_isPopupWithProxyWindow) {
1193             raiseWindow(this);
1194         }
1195 
1196         return;
1197     }
1198 
1199     req.browserArgs.setNewTab(false); // we got a new window, no need for a new tab in that window
1200     req.forceAutoEmbed = true;
1201     req.serviceName = preferredService(m_currentView, req.args.mimeType());
1202 
1203     mainWindow = KonqMainWindowFactory::createEmptyWindow();
1204     mainWindow->resetAutoSaveSettings(); // Don't autosave
1205 
1206     // Do we know the mimetype? If not, go to generic openUrl which will use a KonqRun.
1207     if (req.args.mimeType().isEmpty()) {
1208         mainWindow->openUrl(nullptr, url, QString(), req);
1209     } else {
1210         if (!mainWindow->openView(req.args.mimeType(), url, mainWindow->currentView(), req)) {
1211             // we have problems. abort.
1212             delete mainWindow;
1213 
1214             if (part) {
1215                 *part = nullptr;
1216             }
1217             return;
1218         }
1219     }
1220 
1221     qCDebug(KONQUEROR_LOG) << "newWindow" << mainWindow << "currentView" << mainWindow->currentView() << "views" << mainWindow->viewMap().count();
1222 
1223     KonqView *view = nullptr;
1224     // cannot use activePart/currentView, because the activation through the partmanager
1225     // is delayed by a singleshot timer (see KonqViewManager::setActivePart)
1226     // ### TODO: not true anymore
1227     if (mainWindow->viewMap().count()) {
1228         MapViews::ConstIterator it = mainWindow->viewMap().begin();
1229         view = it.value();
1230 
1231         if (part) {
1232             *part = it.key();
1233         }
1234     }
1235 
1236     // activate the view now in order to make the menuBar() hide call work
1237     if (part && *part) {
1238         mainWindow->viewManager()->setActivePart(*part);
1239     }
1240 
1241     // WORKAROUND: Clear the window state information set by KMainWindow::restoreWindowSize
1242     // so that the size and location settings we set below always take effect.
1243 #if QT_VERSION_MAJOR < 6
1244     KWindowSystem::clearState(mainWindow->winId(), NET::Max);
1245 #else
1246     KX11Extras::clearState(mainWindow->winId(), NET::Max);
1247 #endif
1248 
1249     // process the window args
1250     const int xPos = ((windowArgs.x() == -1) ?  mainWindow->x() : windowArgs.x());
1251     const int yPos = ((windowArgs.y() == -1) ?  mainWindow->y() : windowArgs.y());
1252     const int width = ((windowArgs.width() == -1) ?  mainWindow->width() : windowArgs.width());
1253     const int height = ((windowArgs.height() == -1) ?  mainWindow->height() : windowArgs.height());
1254 
1255     mainWindow->move(xPos, yPos);
1256     mainWindow->resize(width, height);
1257 
1258     // Make the window open properties configurable. This is equivalent to
1259     // Firefox's "dom.disable_window_open_feature.*" properties. For now
1260     // only LocationBar visibility is configurable.
1261     KSharedConfig::Ptr config = KSharedConfig::openConfig();
1262     KConfigGroup cfg(config, "DisableWindowOpenFeatures");
1263 
1264     if (!windowArgs.isMenuBarVisible()) {
1265         mainWindow->menuBar()->hide();
1266         mainWindow->m_paShowMenuBar->setChecked(false);
1267     }
1268 
1269     if (!windowArgs.toolBarsVisible()) {
1270         // For security reasons the address bar is NOT hidden by default. The
1271         // user can override the default setup by adding a config option
1272         // "LocationBar=false" to the [DisableWindowOpenFeatures] section of
1273         // konquerorrc.
1274         const bool showLocationBar = cfg.readEntry("LocationBar", true);
1275         KToolBar *locationToolBar = mainWindow->toolBar(QStringLiteral("locationToolBar"));
1276 
1277         for (KToolBar *bar: mainWindow->findChildren<KToolBar *>()) {
1278             if (bar != locationToolBar || !showLocationBar) {
1279                 bar->hide();
1280             }
1281         }
1282 
1283         if (locationToolBar && showLocationBar && isPopupWindow(windowArgs)) {
1284             // Hide all the actions of the popup window
1285             KActionCollection *collection = mainWindow->actionCollection();
1286             for (int i = 0, count = collection->count(); i < count; ++i) {
1287                 collection->action(i)->setVisible(false);
1288             }
1289 
1290             // Show only those actions that are allowed in a popup window
1291             static const char *const s_allowedActions[] = {
1292                 "go_back", "go_forward", "go_up", "reload", "hard_reload",
1293                 "stop", "cut", "copy", "paste", "print", "fullscreen",
1294                 "add_bookmark", "new_window", nullptr
1295             };
1296             for (int i = 0; s_allowedActions[i]; ++i) {
1297                 if (QAction *action = collection->action(QLatin1String(s_allowedActions[i]))) {
1298                     action->setVisible(true);
1299                 }
1300             }
1301 
1302             // Make only the address widget available in the location toolbar
1303             locationToolBar->clear();
1304             QAction *action = locationToolBar->addWidget(mainWindow->m_combo);
1305             action->setVisible(true);
1306 
1307             // Make the combo box non editable and clear it of previous history
1308             QLineEdit *edit = (mainWindow->m_combo ? mainWindow->m_combo->lineEdit() : nullptr);
1309             if (edit) {
1310                 mainWindow->m_combo->clear();
1311                 mainWindow->m_combo->setCompletionMode(KCompletion::CompletionNone);
1312                 edit->setReadOnly(true);
1313             }
1314 
1315             // Store the originating window as the popup's proxy window so that
1316             // new tab requests in the popup window are forwarded to it.
1317             mainWindow->m_popupProxyWindow = this;
1318             mainWindow->m_isPopupWithProxyWindow = true;
1319         }
1320     }
1321 
1322     if (view) {
1323         if (!windowArgs.scrollBarsVisible()) {
1324             view->disableScrolling();
1325         }
1326         if (!windowArgs.isStatusBarVisible()) {
1327             view->frame()->statusbar()->hide();
1328             mainWindow->m_paShowStatusBar->setChecked(false);
1329         } else {
1330             mainWindow->m_paShowStatusBar->setChecked(true);
1331         }
1332     }
1333 
1334     if (!windowArgs.isResizable())
1335         // ### this doesn't seem to work :-(
1336     {
1337         mainWindow->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed));
1338     }
1339 
1340 // Trying to show the window initially behind the current window is a bit tricky,
1341 // as this involves the window manager, which may see things differently.
1342 // Many WMs raise and activate new windows, which means without WM support this won't work very
1343 // well. If the WM has support for _NET_WM_USER_TIME, it will be just set to 0 (=don't focus on show),
1344 // and the WM should take care of it itself.
1345     bool wm_usertime_support = false;
1346 
1347     if (KWindowSystem::isPlatformX11()) {
1348         auto saved_last_input_time = QX11Info::appUserTime();
1349         if (windowArgs.lowerWindow()) {
1350             NETRootInfo wm_info(QX11Info::connection(), NET::Supported);
1351             wm_usertime_support = wm_info.isSupported(NET::WM2UserTime);
1352             if (wm_usertime_support) {
1353                 // *sigh*, and I thought nobody would need QWidget::dontFocusOnShow().
1354                 // Avoid Qt's support for user time by setting it to 0, and
1355                 // set the property ourselves.
1356                 QX11Info::setAppUserTime(0);
1357             }
1358             // Put below the current window before showing, in case that actually works with the WM.
1359             // First do complete lower(), then stackUnder(), because the latter may not work with many WMs.
1360             mainWindow->lower();
1361             mainWindow->stackUnder(this);
1362         }
1363 
1364         mainWindow->show();
1365 
1366         if (windowArgs.lowerWindow()) {
1367             QX11Info::setAppUserTime(saved_last_input_time);
1368             if (!wm_usertime_support) {
1369                 // No WM support. Let's try ugly tricks.
1370                 mainWindow->lower();
1371                 mainWindow->stackUnder(this);
1372                 if (this->isActiveWindow()) {
1373                     this->activateWindow();
1374                 }
1375             }
1376         }
1377     }
1378 
1379     if (windowArgs.isFullScreen()) {
1380         mainWindow->action("fullscreen")->trigger();
1381     }
1382 }
1383 
1384 void KonqMainWindow::slotNewWindow()
1385 {
1386     KonqMainWindow *mainWin = KonqMainWindowFactory::createNewWindow();
1387     mainWin->show();
1388 }
1389 
1390 void KonqMainWindow::slotDuplicateWindow()
1391 {
1392     m_pViewManager->duplicateWindow()->show();
1393 }
1394 
1395 void KonqMainWindow::slotSendURL()
1396 {
1397     const QList<QUrl> lst = currentURLs();
1398     QString body;
1399     QString fileNameList;
1400     for (QList<QUrl>::ConstIterator it = lst.constBegin(); it != lst.constEnd(); ++it) {
1401         if (!body.isEmpty()) {
1402             body += '\n';
1403         }
1404         body += (*it).toDisplayString();
1405         if (!fileNameList.isEmpty()) {
1406             fileNameList += QLatin1String(", ");
1407         }
1408         fileNameList += (*it).fileName();
1409     }
1410     QString subject;
1411     if (m_currentView && !m_currentView->showsDirectory()) {
1412         subject = m_currentView->caption();
1413     } else { // directory view
1414         subject = fileNameList;
1415     }
1416     QUrl mailtoUrl;
1417     mailtoUrl.setScheme(QStringLiteral("mailto"));
1418     QUrlQuery query;
1419     query.addQueryItem(QStringLiteral("subject"), subject);
1420     query.addQueryItem(QStringLiteral("body"), body);
1421     mailtoUrl.setQuery(query);
1422     QDesktopServices::openUrl(mailtoUrl);
1423 }
1424 
1425 void KonqMainWindow::slotSendFile()
1426 {
1427     const QList<QUrl> lst = currentURLs();
1428     QStringList urls;
1429     QString fileNameList;
1430     for (QList<QUrl>::ConstIterator it = lst.constBegin(); it != lst.constEnd(); ++it) {
1431         if (!fileNameList.isEmpty()) {
1432             fileNameList += QLatin1String(", ");
1433         }
1434         if ((*it).isLocalFile() && QFileInfo((*it).toLocalFile()).isDir()) {
1435             // Create a temp dir, so that we can put the ZIP file in it with a proper name
1436             // Problem: when to delete it?
1437             QTemporaryDir tempDir;
1438             tempDir.setAutoRemove(false);
1439             if (!tempDir.isValid()) {
1440                 qCWarning(KONQUEROR_LOG) << "Could not create temporary dir";
1441                 continue;
1442             }
1443             const QString zipFileName = tempDir.path() + '/' + (*it).fileName() + ".zip";
1444             KZip zip(zipFileName);
1445             if (!zip.open(QIODevice::WriteOnly)) {
1446                 qCWarning(KONQUEROR_LOG) << "Could not open" << zipFileName << "for writing";
1447                 continue;
1448             }
1449             zip.addLocalDirectory((*it).path(), QString());
1450             zip.close();
1451             fileNameList += (*it).fileName() + ".zip";
1452             urls.append(QUrl::fromLocalFile(zipFileName).url());
1453         } else {
1454             fileNameList += (*it).fileName();
1455             urls.append((*it).url());
1456         }
1457     }
1458     QString subject;
1459     if (m_currentView && !m_currentView->showsDirectory()) {
1460         subject = m_currentView->caption();
1461     } else {
1462         subject = fileNameList;
1463     }
1464     QUrl mailtoUrl;
1465     mailtoUrl.setScheme(QStringLiteral("mailto"));
1466     QUrlQuery query;
1467     query.addQueryItem(QStringLiteral("subject"), subject);
1468     for (const QString& url : urls) {
1469         query.addQueryItem(QStringLiteral("attachment"), url);
1470     }
1471     mailtoUrl.setQuery(query);
1472     QDesktopServices::openUrl(mailtoUrl);
1473 }
1474 
1475 void KonqMainWindow::slotOpenLocation()
1476 {
1477     focusLocationBar();
1478     QLineEdit *edit = comboEdit();
1479     if (edit) {
1480         edit->selectAll();
1481     }
1482 }
1483 
1484 void KonqMainWindow::slotOpenFile()
1485 {
1486     QUrl currentUrl;
1487     if (m_currentView && m_currentView->url().isLocalFile()) {
1488         currentUrl = m_currentView->url();
1489     } else {
1490         currentUrl = QUrl::fromLocalFile(QDir::homePath());
1491     }
1492 
1493     QUrl url = QFileDialog::getOpenFileUrl(this, i18n("Open File"), currentUrl, QString());
1494     if (!url.isEmpty()) {
1495         openFilteredUrl(url.url().trimmed());
1496     }
1497 }
1498 
1499 void KonqMainWindow::slotIconsChanged()
1500 {
1501     qCDebug(KONQUEROR_LOG);
1502     if (m_combo) {
1503         m_combo->updatePixmaps();
1504     }
1505     m_pViewManager->updatePixmaps();
1506     updateWindowIcon();
1507 }
1508 
1509 void KonqMainWindow::slotOpenWith()
1510 {
1511     if (!m_currentView) {
1512         return;
1513     }
1514 
1515     const QString serviceName = sender()->objectName();
1516     const KService::List offers = m_currentView->appServiceOffers();
1517     for (const KService::Ptr &service : offers) {
1518         if (service->desktopEntryName() == serviceName) {
1519             KIO::ApplicationLauncherJob *job = new KIO::ApplicationLauncherJob(service);
1520             //TODO KF6: check whether requestedUrl or realUrl is more suitable here
1521             job->setUrls({ m_currentView->realUrl() });
1522             job->setUiDelegate(KIO::createDefaultJobUiDelegate(KJobUiDelegate::AutoHandlingEnabled, this));
1523             job->start();
1524             return;
1525         }
1526     }
1527 }
1528 
1529 void KonqMainWindow::slotViewModeTriggered(QAction *action)
1530 {
1531     if (!m_currentView) {
1532         return;
1533     }
1534 
1535     //TODO port away from query: check that plugin id actually respect these rules
1536     // Gather data from the action, since the action will be deleted by changePart
1537     QString modeName = action->objectName();
1538     Q_ASSERT(modeName.endsWith("-viewmode"));
1539     modeName.chop(9);
1540     const QString internalViewMode = action->data().toString();
1541     m_currentView->switchEmbeddingPart(modeName, internalViewMode);
1542 }
1543 
1544 void KonqMainWindow::slotLockView()
1545 {
1546     if (!m_currentView) {
1547         return;
1548     }
1549 
1550     m_currentView->setLockedLocation(m_paLockView->isChecked());
1551 }
1552 
1553 void KonqMainWindow::slotStop()
1554 {
1555     abortLoading();
1556     if (m_currentView) {
1557         m_currentView->frame()->statusbar()->message(i18n("Canceled."));
1558     }
1559 }
1560 
1561 void KonqMainWindow::slotLinkView()
1562 {
1563     if (!m_currentView) {
1564         return;
1565     }
1566 
1567     // Can't access this action in passive mode anyway
1568     Q_ASSERT(!m_currentView->isPassiveMode());
1569     const bool mode = !m_currentView->isLinkedView();
1570 
1571     const QList<KonqView *> linkableViews = KonqLinkableViewsCollector::collect(this);
1572     if (linkableViews.count() == 2) {
1573         // Exactly two linkable views : link both
1574         linkableViews.at(0)->setLinkedView(mode);
1575         linkableViews.at(1)->setLinkedView(mode);
1576     } else { // Normal case : just this view
1577         m_currentView->setLinkedView(mode);
1578     }
1579 }
1580 
1581 void KonqMainWindow::slotReload(KonqView *reloadView, bool softReload)
1582 {
1583     if (!reloadView) {
1584         reloadView = m_currentView;
1585     }
1586 
1587     if (!reloadView || (reloadView->url().isEmpty() && reloadView->locationBarURL().isEmpty())) {
1588         return;
1589     }
1590 
1591     if (reloadView->isModified()) {
1592         if (KMessageBox::warningContinueCancel(this,
1593                                                i18n("This page contains changes that have not been submitted.\nReloading the page will discard these changes."),
1594                                                i18nc("@title:window", "Discard Changes?"), KGuiItem(i18n("&Discard Changes"), QStringLiteral("view-refresh")), KStandardGuiItem::cancel(), QStringLiteral("discardchangesreload")) != KMessageBox::Continue) {
1595             return;
1596         }
1597     }
1598 
1599     KonqOpenURLRequest req(reloadView->typedUrl());
1600     req.userRequestedReload = true;
1601     if (reloadView->prepareReload(req.args, req.browserArgs, softReload)) {
1602         reloadView->lockHistory();
1603         // Reuse current servicetype for local files, but not for remote files (it could have changed, e.g. over HTTP)
1604         QString serviceType = reloadView->url().isLocalFile() ? reloadView->serviceType() : QString();
1605         // By using locationBarURL instead of url, we preserve name filters (#54687)
1606         QUrl reloadUrl = QUrl::fromUserInput(reloadView->locationBarURL(), QString(), QUrl::AssumeLocalFile);
1607         if (reloadUrl.isEmpty()) { // e.g. initial screen
1608             reloadUrl = reloadView->url();
1609         }
1610         openUrl(reloadView, reloadUrl, serviceType, req);
1611     }
1612 }
1613 
1614 void KonqMainWindow::slotForceReload()
1615 {
1616     // A forced reload is simply a "hard" (i.e. - not soft!) reload.
1617     slotReload(nullptr /* Current view */, false /* Not softReload*/);
1618 }
1619 
1620 void KonqMainWindow::slotReloadPopup()
1621 {
1622     KonqFrameBase *tab = m_pViewManager->tabContainer()->tabAt(m_workingTab);
1623     if (tab) {
1624         slotReload(tab->activeChildView());
1625     }
1626 }
1627 
1628 void KonqMainWindow::slotHome()
1629 {
1630     const QString homeURL = m_paHomePopup->data().toString();
1631 
1632     KonqOpenURLRequest req;
1633     req.browserArgs.setNewTab(true);
1634     req.newTabInFront = KonqSettings::newTabsInFront();
1635 
1636     Qt::MouseButtons buttons = QApplication::mouseButtons();
1637     Qt::KeyboardModifiers modifiers = QApplication::keyboardModifiers();
1638 
1639     if (modifiers & Qt::ShiftModifier) {
1640         req.newTabInFront = !req.newTabInFront;
1641     }
1642 
1643     if (modifiers & Qt::ControlModifier) { // Ctrl Left/MMB
1644         openFilteredUrl(homeURL, req);
1645     } else if (buttons & Qt::MiddleButton) {
1646         if (KonqSettings::mmbOpensTab()) {
1647             openFilteredUrl(homeURL, req);
1648         } else {
1649             const QUrl finalURL = KonqMisc::konqFilteredURL(this, homeURL);
1650             KonqMainWindow *mw = KonqMainWindowFactory::createNewWindow(finalURL);
1651             mw->show();
1652         }
1653     } else {
1654         openFilteredUrl(homeURL, false);
1655     }
1656 }
1657 
1658 void KonqMainWindow::slotHomePopupActivated(QAction *action)
1659 {
1660     openUrl(nullptr, QUrl(action->data().toString()));
1661 }
1662 
1663 void KonqMainWindow::slotGoHistory()
1664 {
1665     if (!m_historyDialog) {
1666         m_historyDialog = new KonqHistoryDialog(this);
1667         m_historyDialog->setAttribute(Qt::WA_DeleteOnClose);
1668         m_historyDialog->setModal(false);
1669     }
1670     m_historyDialog->show();
1671 }
1672 
1673 void KonqMainWindow::slotConfigureExtensions()
1674 {
1675     KonqExtensionManager extensionManager(this, this, m_currentView ? m_currentView->part() : nullptr);
1676     extensionManager.exec();
1677 }
1678 
1679 void KonqMainWindow::slotConfigure()
1680 {
1681     emit aboutToConfigure();
1682 
1683     if (!m_configureDialog) {
1684         m_configureDialog = new Konq::ConfigDialog(this);
1685     }
1686 
1687     m_configureDialog->show();
1688 }
1689 
1690 void KonqMainWindow::slotConfigure(Konq::ConfigDialog::Module module)
1691 {
1692     slotConfigure();
1693     if (m_configureDialog) {
1694         m_configureDialog->setCurrentPage(module);
1695     }
1696 }
1697 
1698 
1699 void KonqMainWindow::slotConfigureDone()
1700 {
1701     // Cleanup the dialog so other instances can use it..
1702     if (m_configureDialog) {
1703         m_configureDialog->deleteLater();
1704         m_configureDialog = nullptr;
1705     }
1706 }
1707 
1708 void KonqMainWindow::slotConfigureSpellChecking()
1709 {
1710     Sonnet::ConfigDialog dialog(this);
1711     dialog.setWindowIcon(QIcon::fromTheme("konqueror"));
1712     if (dialog.exec() == QDialog::Accepted) {
1713         updateSpellCheckConfiguration();
1714     }
1715 }
1716 
1717 void KonqMainWindow::updateSpellCheckConfiguration()
1718 {
1719     //HACK: since Sonnet doesn't allow to find out whether the spell checker should be enabled by default
1720     //we need to open its config file and read the setting from there. We then store it in our own configuration file
1721     //so that it can be read from there
1722     KSharedConfig::Ptr cfg = KSharedConfig::openConfig("KDE/Sonnet.conf");
1723     KConfigGroup grp = cfg->group("General");
1724     bool enabled = grp.readEntry("checkerEnabledByDefault", false);
1725     cfg = KSharedConfig::openConfig();
1726     grp = cfg->group("General");
1727     grp.writeEntry("SpellCheckingEnabled", enabled);
1728     cfg->sync();
1729     emit KonqSpellCheckingConfigurationDispatcher::self()->spellCheckingConfigurationChanged(enabled);
1730 }
1731 
1732 void KonqMainWindow::slotConfigureToolbars()
1733 {
1734     slotForceSaveMainWindowSettings();
1735     KEditToolBar dlg(factory(), this);
1736     connect(&dlg, &KEditToolBar::newToolBarConfig, this, &KonqMainWindow::slotNewToolbarConfig);
1737     connect(&dlg, &KEditToolBar::newToolBarConfig, this, &KonqMainWindow::initBookmarkBar);
1738     dlg.exec();
1739     checkDisableClearButton();
1740 }
1741 
1742 void KonqMainWindow::slotNewToolbarConfig() // This is called when OK or Apply is clicked
1743 {
1744     if (m_toggleViewGUIClient) {
1745         plugActionList(QStringLiteral("toggleview"), m_toggleViewGUIClient->actions());
1746     }
1747     if (m_currentView && m_currentView->appServiceOffers().count() > 0) {
1748         plugActionList(QStringLiteral("openwith"), m_openWithActions);
1749     }
1750 
1751     plugViewModeActions();
1752 
1753     KConfigGroup cg = KSharedConfig::openConfig()->group("KonqMainWindow");
1754     applyMainWindowSettings(cg);
1755 }
1756 
1757 void KonqMainWindow::slotUndoAvailable(bool avail)
1758 {
1759     m_paUndo->setEnabled(avail);
1760 }
1761 
1762 void KonqMainWindow::slotPartChanged(KonqView *childView, KParts::ReadOnlyPart *oldPart, KParts::ReadOnlyPart *newPart)
1763 {
1764     m_mapViews.remove(oldPart);
1765     m_mapViews.insert(newPart, childView);
1766 
1767     // Remove the old part, and add the new part to the manager
1768     const bool wasActive = m_pViewManager->activePart() == oldPart;
1769 
1770     m_pViewManager->replacePart(oldPart, newPart, false);
1771 
1772     // Set active immediately - but only if the old part was the active one (#67956)
1773     if (wasActive) {
1774         // Note: this makes the new part active... so it calls slotPartActivated
1775         m_pViewManager->setActivePart(newPart);
1776     }
1777 
1778     viewsChanged();
1779 }
1780 
1781 void KonqMainWindow::applyKonqMainWindowSettings()
1782 {
1783     const QStringList toggableViewsShown = KonqSettings::toggableViewsShown();
1784     QStringList::ConstIterator togIt = toggableViewsShown.begin();
1785     QStringList::ConstIterator togEnd = toggableViewsShown.end();
1786     for (; togIt != togEnd; ++togIt) {
1787         // Find the action by name
1788         //    QAction * act = m_toggleViewGUIClient->actionCollection()->action( (*togIt).toLatin1() );
1789         QAction *act = m_toggleViewGUIClient->action(*togIt);
1790         if (act) {
1791             act->trigger();
1792         } else {
1793             qCWarning(KONQUEROR_LOG) << "Unknown toggable view in ToggableViewsShown " << *togIt;
1794         }
1795     }
1796 }
1797 
1798 void KonqMainWindow::slotSetStatusBarText(const QString &)
1799 {
1800     // Reimplemented to disable KParts::MainWindow default behaviour
1801     // Does nothing here, see KonqFrame
1802 }
1803 
1804 void KonqMainWindow::slotViewCompleted(KonqView *view)
1805 {
1806     Q_ASSERT(view);
1807 
1808     // Need to update the current working directory
1809     // of the completion object every time the user
1810     // changes the directory!! (DA)
1811     if (m_pURLCompletion) {
1812         m_pURLCompletion->setDir(QUrl::fromUserInput(view->locationBarURL()));
1813     }
1814 }
1815 
1816 void KonqMainWindow::slotPartActivated(KParts::Part *part)
1817 {
1818     qCDebug(KONQUEROR_LOG) << part << (part ? part->metaData().pluginId() : QString());
1819     KonqView *newView = nullptr;
1820     KonqView *oldView = m_currentView;
1821 
1822     //Exit full screen when a new part is activated
1823     if (m_fullScreenData.currentState == FullScreenState::CompleteFullScreen) {
1824         if (oldView && oldView->part()) {
1825             QMetaObject::invokeMethod(oldView->part(), "exitFullScreen");
1826         } else { //This should never happen
1827             toggleCompleteFullScreen(false);
1828         }
1829     }
1830 
1831     if (part) {
1832         newView = m_mapViews.value(static_cast<KParts::ReadOnlyPart *>(part));
1833         Q_ASSERT(newView);
1834         if (newView->isPassiveMode()) {
1835             // Passive view. Don't connect anything, don't change m_currentView
1836             // Another view will become the current view very soon
1837             //qCDebug(KONQUEROR_LOG) << "Passive mode - return";
1838             return;
1839         }
1840     }
1841 
1842     KParts::NavigationExtension *ext = nullptr;
1843 
1844     if (oldView) {
1845         ext = oldView->browserExtension();
1846         if (ext) {
1847             //qCDebug(KONQUEROR_LOG) << "Disconnecting extension for view" << oldView;
1848             disconnectExtension(ext);
1849         }
1850     }
1851 
1852     qCDebug(KONQUEROR_LOG) << "New current view" << newView;
1853     m_currentView = newView;
1854     if (newView) {
1855         m_paShowStatusBar->setChecked(newView->frame()->statusbar()->isVisible());
1856     }
1857 
1858     if (!part) {
1859         //qCDebug(KONQUEROR_LOG) << "No part activated - returning";
1860         unplugViewModeActions();
1861         createGUI(nullptr);
1862         KParts::MainWindow::setCaption(QString());
1863         return;
1864     }
1865 
1866     ext = m_currentView->browserExtension();
1867 
1868     if (ext) {
1869         connectExtension(ext);
1870     } else {
1871 
1872         qCDebug(KONQUEROR_LOG) << "No Browser Extension for the new part";
1873         // Disable all browser-extension actions
1874 
1875 #if QT_VERSION_MAJOR < 6
1876         KParts::NavigationExtension::ActionSlotMap *actionSlotMap = KParts::NavigationExtension::actionSlotMapPtr();
1877 #else
1878         KParts::NavigationExtension::ActionSlotMap *actionSlotMap = KParts::NavigationExtension::actionSlotMap();
1879 #endif
1880         KParts::NavigationExtension::ActionSlotMap::ConstIterator it = actionSlotMap->constBegin();
1881         const KParts::NavigationExtension::ActionSlotMap::ConstIterator itEnd = actionSlotMap->constEnd();
1882         for (; it != itEnd; ++it) {
1883             QAction *act = actionCollection()->action(QString::fromLatin1(it.key()));
1884             Q_ASSERT(act);
1885             if (act) {
1886                 act->setEnabled(false);
1887             }
1888         }
1889 
1890         if (m_paCopyFiles) {
1891             m_paCopyFiles->setEnabled(false);
1892         }
1893         if (m_paMoveFiles) {
1894             m_paMoveFiles->setEnabled(false);
1895         }
1896     }
1897 
1898     m_paShowDeveloperTools->setEnabled(m_currentView && m_currentView->isWebEngineView());
1899 
1900     createGUI(part);
1901 
1902     // View-dependent GUI
1903 
1904     KParts::MainWindow::setCaption(KStringHandler::csqueeze(m_currentView->caption(), 128));
1905     // This line causes #170470 when removing the current tab, because QTabBar
1906     // emits currentChanged before calling tabRemoved, so KTabWidget gets confused.
1907     // I don't see a need for it anyway...
1908     //m_currentView->frame()->setTitle(m_currentView->caption(), 0);
1909 
1910     updateOpenWithActions();
1911     updateViewActions(); // undo, lock, link and other view-dependent actions
1912     updateViewModeActions();
1913 
1914     bool viewShowsDir = m_currentView->showsDirectory();
1915     bool buttonShowsFolder = m_paHomePopup->text() == i18n("Home Folder");
1916     if (m_paHomePopup->text() == i18n("Home") || viewShowsDir != buttonShowsFolder) {
1917         QAction *actHomeFolder = new QAction(this);
1918         QAction *actHomePage = new QAction(this);
1919 
1920         actHomeFolder->setIcon(QIcon::fromTheme(QStringLiteral("user-home")));
1921         actHomeFolder->setText(i18n("Home Folder"));
1922         actHomeFolder->setStatusTip(i18n("Navigate to your 'Home Folder'"));
1923         actHomeFolder->setWhatsThis(i18n("Navigate to your local 'Home Folder'"));
1924         actHomeFolder->setData(QUrl::fromLocalFile(QDir::homePath()));
1925         actHomePage->setIcon(QIcon::fromTheme(QStringLiteral("go-home")));
1926         actHomePage->setText(i18n("Home Page"));
1927 
1928         actHomePage->setStatusTip(i18n("Navigate to your 'Home Page'"));
1929         actHomePage->setWhatsThis(i18n("<html>Navigate to your 'Home Page'<br /><br />"
1930                                        "You can configure the location where this button takes you "
1931                                        "under <b>Settings -> Configure Konqueror -> General</b>.</html>"));
1932         actHomePage->setData(KonqSettings::homeURL());
1933 
1934         m_paHome->setIcon(viewShowsDir ? actHomeFolder->icon() : actHomePage->icon());
1935         m_paHome->setText(viewShowsDir ? actHomeFolder->text() : actHomePage->text());
1936         m_paHome->setStatusTip(viewShowsDir ? actHomeFolder->statusTip() : actHomePage->statusTip());
1937         m_paHome->setWhatsThis(viewShowsDir ? actHomeFolder->whatsThis() : actHomePage->whatsThis());
1938         m_paHomePopup->setIcon(viewShowsDir ? actHomeFolder->icon() : actHomePage->icon());
1939         m_paHomePopup->setText(viewShowsDir ? actHomeFolder->text() : actHomePage->text());
1940         m_paHomePopup->setStatusTip(viewShowsDir ? actHomeFolder->statusTip() : actHomePage->statusTip());
1941         m_paHomePopup->setWhatsThis(viewShowsDir ? actHomeFolder->whatsThis() : actHomePage->whatsThis());
1942         m_paHomePopup->setData(viewShowsDir ? actHomeFolder->data() : actHomePage->data());
1943         m_paHomePopup->popupMenu()->clear();
1944         if (viewShowsDir) {
1945             m_paHomePopup->popupMenu()->addAction(actHomePage);
1946             delete actHomeFolder;
1947         } else {
1948             m_paHomePopup->popupMenu()->addAction(actHomeFolder);
1949             delete actHomePage;
1950         }
1951     }
1952 
1953     m_currentView->frame()->statusbar()->updateActiveStatus();
1954 
1955     if (oldView && oldView->frame()) {
1956         oldView->frame()->statusbar()->updateActiveStatus();
1957     }
1958 
1959     //qCDebug(KONQUEROR_LOG) << "setting location bar url to"
1960     //         << m_currentView->locationBarURL() << "m_currentView=" << m_currentView;
1961 
1962     // Make sure the location bar gets updated when the view(tab) is changed.
1963     if (oldView != newView && m_combo) {
1964         m_combo->lineEdit()->setModified(false);
1965     }
1966     m_currentView->setLocationBarURL(m_currentView->locationBarURL());
1967 
1968     updateToolBarActions();
1969 }
1970 
1971 void KonqMainWindow::insertChildView(KonqView *childView)
1972 {
1973     //qCDebug(KONQUEROR_LOG) << childView;
1974     m_mapViews.insert(childView->part(), childView);
1975 
1976     connect(childView, SIGNAL(viewCompleted(KonqView*)),
1977             this, SLOT(slotViewCompleted(KonqView*)));
1978 
1979     emit viewAdded(childView);
1980 }
1981 
1982 // Called by KonqViewManager, internal
1983 void KonqMainWindow::removeChildView(KonqView *childView)
1984 {
1985     //qCDebug(KONQUEROR_LOG) << childView;
1986 
1987     disconnect(childView, SIGNAL(viewCompleted(KonqView*)),
1988                this, SLOT(slotViewCompleted(KonqView*)));
1989 
1990 #ifndef NDEBUG
1991     //dumpViewList();
1992 #endif
1993 
1994     MapViews::Iterator it = m_mapViews.begin();
1995     const MapViews::Iterator end = m_mapViews.end();
1996 
1997     // find it in the map - can't use the key since childView->part() might be 0
1998 
1999     //qCDebug(KONQUEROR_LOG) << "Searching map";
2000 
2001     while (it != end && it.value() != childView) {
2002         ++it;
2003     }
2004 
2005     //qCDebug(KONQUEROR_LOG) << "Verifying search results";
2006 
2007     if (it == m_mapViews.end()) {
2008         qCWarning(KONQUEROR_LOG) << "KonqMainWindow::removeChildView childView " << childView << " not in map !";
2009         return;
2010     }
2011 
2012     //qCDebug(KONQUEROR_LOG) << "Removing view" << childView;
2013 
2014     m_mapViews.erase(it);
2015 
2016     emit viewRemoved(childView);
2017 
2018 #ifndef NDEBUG
2019     //dumpViewList();
2020 #endif
2021 
2022     // KonqViewManager takes care of m_currentView
2023 }
2024 
2025 void KonqMainWindow::linkableViewCountChanged()
2026 {
2027     const QList<KonqView *> linkableViews = KonqLinkableViewsCollector::collect(this);
2028     const int lvc = linkableViews.count();
2029     m_paLinkView->setEnabled(lvc > 1);
2030     // Only one view -> unlink it
2031     if (lvc == 1) {
2032         linkableViews.at(0)->setLinkedView(false);
2033     }
2034     m_pViewManager->viewCountChanged();
2035 }
2036 
2037 void KonqMainWindow::viewCountChanged()
2038 {
2039     // This is called (by the view manager) when the number of views changes.
2040     linkableViewCountChanged();
2041     viewsChanged();
2042 }
2043 
2044 void KonqMainWindow::viewsChanged()
2045 {
2046     // This is called when the number of views changes OR when
2047     // the type of some view changes.
2048 
2049     updateViewActions(); // undo, lock, link and other view-dependent actions
2050 }
2051 
2052 KonqView *KonqMainWindow::childView(KParts::ReadOnlyPart *view)
2053 {
2054     return m_mapViews.value(view);
2055 }
2056 
2057 KonqView *KonqMainWindow::childView(KParts::ReadOnlyPart *callingPart, const QString &name, KParts::ReadOnlyPart **part)
2058 {
2059     //qCDebug(KONQUEROR_LOG) << "this=" << this << "looking for" << name;
2060     QList<KonqView *> views = m_mapViews.values();
2061     KonqView *callingView = m_mapViews.value(callingPart);
2062     if (callingView) {
2063         // Move the callingView in front of the list, in case of duplicate frame names (#133967)
2064         if (views.removeAll(callingView)) {
2065             views.prepend(callingView);
2066         }
2067     }
2068 
2069     for (KonqView *view : qAsConst(views)) {
2070         QString viewName = view->viewName();
2071         //qCDebug(KONQUEROR_LOG) << "       - viewName=" << viewName
2072         //          << "frame names:" << view->frameNames();
2073 
2074         if (!viewName.isEmpty() && viewName == name) {
2075             qCDebug(KONQUEROR_LOG) << "found existing view by name:" << view;
2076             if (part) {
2077                 *part = view->part();
2078             }
2079             return view;
2080         }
2081     }
2082 
2083     return nullptr;
2084 }
2085 
2086 int KonqMainWindow::activeViewsNotLockedCount() const
2087 {
2088     int res = 0;
2089     MapViews::ConstIterator end = m_mapViews.constEnd();
2090     for (MapViews::ConstIterator it = m_mapViews.constBegin(); it != end; ++it) {
2091         if (!it.value()->isPassiveMode() && !it.value()->isLockedLocation()) {
2092             ++res;
2093         }
2094     }
2095 
2096     return res;
2097 }
2098 
2099 int KonqMainWindow::linkableViewsCount() const
2100 {
2101     return KonqLinkableViewsCollector::collect(const_cast<KonqMainWindow *>(this)).count();
2102 }
2103 
2104 int KonqMainWindow::mainViewsCount() const
2105 {
2106     int res = 0;
2107     MapViews::ConstIterator it = m_mapViews.constBegin();
2108     const MapViews::ConstIterator end = m_mapViews.constEnd();
2109     for (; it != end; ++it) {
2110         if (!it.value()->isPassiveMode() && !it.value()->isToggleView()) {
2111             //qCDebug(KONQUEROR_LOG) << res << it.value() << it.value()->part()->widget();
2112             ++res;
2113         }
2114     }
2115 
2116     return res;
2117 }
2118 
2119 void KonqMainWindow::slotURLEntered(const QString &text, Qt::KeyboardModifiers modifiers)
2120 {
2121     if (m_bURLEnterLock || text.isEmpty()) {
2122         return;
2123     }
2124 
2125     m_bURLEnterLock = true;
2126 
2127     if ((modifiers & Qt::ControlModifier) || (modifiers & Qt::AltModifier)) {
2128         m_combo->setURL(m_currentView ? m_currentView->url().toDisplayString() : QString());
2129         const bool inNewTab = !m_isPopupWithProxyWindow; // do not open a new tab in popup window.
2130         openFilteredUrl(text.trimmed(), inNewTab);
2131     } else {
2132         openFilteredUrl(text.trimmed());
2133     }
2134 
2135     m_bURLEnterLock = false;
2136 }
2137 
2138 void KonqMainWindow::splitCurrentView(Qt::Orientation orientation)
2139 {
2140     if (!m_currentView) {
2141         return;
2142     }
2143     KonqView *oldView = m_currentView;
2144     KonqView *newView = m_pViewManager->splitView(m_currentView, orientation);
2145     if (newView == nullptr) {
2146         return;
2147     }
2148     KonqOpenURLRequest req;
2149     req.forceAutoEmbed = true;
2150 
2151     QString mime = oldView->serviceType();
2152     QUrl url = oldView->url();
2153     KSharedConfig::Ptr cfg = KSharedConfig::openConfig("konquerorrc");
2154     const bool alwaysDuplicateView = cfg->group("UserSettings").readEntry("AlwaysDuplicatePageWhenSplittingView", true);
2155     //TODO KF6: check whether this works correctly
2156     if (alwaysDuplicateView || url.isLocalFile()) {
2157         newView->duplicateView(oldView);
2158         return;
2159     }
2160     url = QUrl(KonqSettings::startURL());
2161     openView(QStringLiteral("text/html"), url, newView, req);
2162 }
2163 
2164 void KonqMainWindow::slotSplitViewHorizontal()
2165 {
2166     splitCurrentView(Qt::Horizontal);
2167 }
2168 
2169 void KonqMainWindow::slotSplitViewVertical()
2170 {
2171     splitCurrentView(Qt::Vertical);
2172 }
2173 
2174 void KonqMainWindow::slotAddTab()
2175 {
2176     // we can hardcode text/html because this is what konq:blank will use anyway
2177     KonqView *newView = m_pViewManager->addTab(QStringLiteral("text/html"),
2178                         QString(),
2179                         false,
2180                         KonqSettings::openAfterCurrentPage());
2181     if (!newView) {
2182         return;
2183     }
2184 
2185     openUrl(newView, KonqUrl::url(KonqUrl::Type::Blank), QString());
2186 
2187     //HACK!! QTabBar likes to steal focus when changing widgets.  This can result
2188     //in a flicker since we don't want it to get focus we want the combo to get
2189     //or keep focus...
2190     // TODO: retest, and replace with the smaller hack from KTabWidget::moveTab
2191     QWidget *widget = newView->frame() && newView->frame()->part() ?
2192                       newView->frame()->part()->widget() : nullptr;
2193     QWidget *origFocusProxy = widget ? widget->focusProxy() : nullptr;
2194     if (widget) {
2195         widget->setFocusProxy(m_combo);
2196     }
2197 
2198     m_pViewManager->showTab(newView);
2199 
2200     if (widget) {
2201         widget->setFocusProxy(origFocusProxy);
2202     }
2203 
2204     m_workingTab = 0;
2205 }
2206 
2207 void KonqMainWindow::slotDuplicateTab()
2208 {
2209     m_pViewManager->duplicateTab(m_pViewManager->tabContainer()->currentIndex(), KonqSettings::openAfterCurrentPage());
2210 }
2211 
2212 void KonqMainWindow::slotDuplicateTabPopup()
2213 {
2214     m_pViewManager->duplicateTab(m_workingTab, KonqSettings::openAfterCurrentPage());
2215 }
2216 
2217 void KonqMainWindow::slotBreakOffTab()
2218 {
2219     breakOffTab(m_pViewManager->tabContainer()->currentIndex());
2220 }
2221 
2222 void KonqMainWindow::slotBreakOffTabPopup()
2223 {
2224     // Delay the call since it might delete the tabbar
2225     QMetaObject::invokeMethod(this, "breakOffTab", Qt::QueuedConnection, Q_ARG(int, m_workingTab));
2226 }
2227 
2228 void KonqMainWindow::breakOffTab(int tabIndex)
2229 {
2230     KonqFrameBase *tab = m_pViewManager->tabContainer()->tabAt(tabIndex);
2231     if (!tab) {
2232         return;
2233     }
2234     const int originalTabIndex = m_pViewManager->tabContainer()->currentIndex();
2235     // TODO: Why do we warn about breaking off a modified tab, since it seems to show the unsubmitted form data just fine?
2236     if (!KonqModifiedViewsCollector::collect(tab).isEmpty()) {
2237         m_pViewManager->showTab(tabIndex);
2238         if (KMessageBox::warningContinueCancel(
2239                     this,
2240                     i18n("This tab contains changes that have not been submitted.\nDetaching the tab will discard these changes."),
2241                     i18nc("@title:window", "Discard Changes?"), KGuiItem(i18n("&Discard Changes"), QStringLiteral("tab-detach")), KStandardGuiItem::cancel(), QStringLiteral("discardchangesdetach")) != KMessageBox::Continue) {
2242             m_pViewManager->showTab(originalTabIndex);
2243             return;
2244         }
2245     }
2246     m_pViewManager->showTab(originalTabIndex);
2247     m_pViewManager->breakOffTab(tabIndex, size());
2248     updateViewActions();
2249 }
2250 
2251 void KonqMainWindow::slotPopupNewWindow()
2252 {
2253     KFileItemList::const_iterator it = m_popupItems.constBegin();
2254     const KFileItemList::const_iterator end = m_popupItems.constEnd();
2255     KonqOpenURLRequest req;
2256     req.args = m_popupUrlArgs;
2257     req.browserArgs = m_popupUrlBrowserArgs;
2258     for (; it != end; ++it) {
2259         KonqMainWindow *mw = KonqMainWindowFactory::createNewWindow((*it).targetUrl(), req);
2260         mw->show();
2261     }
2262 }
2263 
2264 void KonqMainWindow::slotPopupThisWindow()
2265 {
2266     openUrl(nullptr, m_popupItems.first().url());
2267 }
2268 
2269 void KonqMainWindow::slotPopupNewTab()
2270 {
2271     if (m_isPopupWithProxyWindow && !m_popupProxyWindow) {
2272         slotPopupNewWindow();
2273         return;
2274     }
2275     bool openAfterCurrentPage = KonqSettings::openAfterCurrentPage();
2276     bool newTabsInFront = KonqSettings::newTabsInFront();
2277 
2278     if (QApplication::keyboardModifiers() & Qt::ShiftModifier) {
2279         newTabsInFront = !newTabsInFront;
2280     }
2281 
2282     popupNewTab(newTabsInFront, openAfterCurrentPage);
2283 }
2284 
2285 void KonqMainWindow::popupNewTab(bool infront, bool openAfterCurrentPage)
2286 {
2287     KonqOpenURLRequest req;
2288     req.newTabInFront = false;
2289     req.forceAutoEmbed = true;
2290     req.openAfterCurrentPage = openAfterCurrentPage;
2291     req.args = m_popupUrlArgs;
2292     req.browserArgs = m_popupUrlBrowserArgs;
2293     req.browserArgs.setNewTab(true);
2294 
2295     KonqMainWindow *mainWindow = (m_popupProxyWindow ? m_popupProxyWindow.data() : this);
2296 
2297     for (int i = 0; i < m_popupItems.count(); ++i) {
2298         if (infront && i == m_popupItems.count() - 1) {
2299             req.newTabInFront = true;
2300         }
2301         mainWindow->openUrl(nullptr, m_popupItems[i].targetUrl(), QString(), req);
2302     }
2303 
2304     // Raise this window if the request to create the tab came from a popup window.
2305     if (m_isPopupWithProxyWindow) {
2306         raiseWindow(mainWindow);
2307     }
2308 }
2309 
2310 void KonqMainWindow::openMultiURL(const QList<QUrl> &url)
2311 {
2312     QList<QUrl>::ConstIterator it = url.constBegin();
2313     const QList<QUrl>::ConstIterator end = url.constEnd();
2314     for (; it != end; ++it) {
2315         KonqView *newView = m_pViewManager->addTab(QStringLiteral("text/html"));
2316         Q_ASSERT(newView);
2317         if (newView == nullptr) {
2318             continue;
2319         }
2320         openUrl(newView, *it, QString());
2321         m_pViewManager->showTab(newView);
2322     }
2323 }
2324 
2325 void KonqMainWindow::slotRemoveView()
2326 {
2327     if (!m_currentView) {
2328         return;
2329     }
2330 
2331     if (m_currentView->isModified()) {
2332         if (KMessageBox::warningContinueCancel(this,
2333                                                i18n("This view contains changes that have not been submitted.\nClosing the view will discard these changes."),
2334                                                i18nc("@title:window", "Discard Changes?"), KGuiItem(i18n("&Discard Changes"), QStringLiteral("view-close")), KStandardGuiItem::cancel(), QStringLiteral("discardchangesclose")) != KMessageBox::Continue) {
2335             return;
2336         }
2337     }
2338 
2339     // takes care of choosing the new active view
2340     m_pViewManager->removeView(m_currentView);
2341 }
2342 
2343 void KonqMainWindow::slotRemoveTab()
2344 {
2345     removeTab(m_pViewManager->tabContainer()->currentIndex());
2346 }
2347 
2348 void KonqMainWindow::slotRemoveTabPopup()
2349 {
2350     // Can't do immediately - may kill the tabbar, and we're in an event path down from it
2351     QMetaObject::invokeMethod(this, "removeTab", Qt::QueuedConnection, Q_ARG(int, m_workingTab));
2352 }
2353 
2354 void KonqMainWindow::removeTab(int tabIndex)
2355 {
2356     KonqFrameBase *tab = m_pViewManager->tabContainer()->tabAt(tabIndex);
2357     if (!tab) {
2358         return;
2359     }
2360     const int originalTabIndex = m_pViewManager->tabContainer()->currentIndex();
2361     if (!KonqModifiedViewsCollector::collect(tab).isEmpty()) {
2362         m_pViewManager->showTab(tabIndex);
2363         if (KMessageBox::warningContinueCancel(
2364                     this,
2365                     i18n("This tab contains changes that have not been submitted.\nClosing the tab will discard these changes."),
2366                     i18nc("@title:window", "Discard Changes?"), KGuiItem(i18n("&Discard Changes"), QStringLiteral("tab-close")), KStandardGuiItem::cancel(), QStringLiteral("discardchangesclose")) != KMessageBox::Continue) {
2367             m_pViewManager->showTab(originalTabIndex);
2368             return;
2369         }
2370     }
2371     m_pViewManager->showTab(originalTabIndex);
2372     m_pViewManager->removeTab(tab);
2373     updateViewActions();
2374 }
2375 
2376 void KonqMainWindow::slotRemoveOtherTabs()
2377 {
2378     removeOtherTabs(m_pViewManager->tabContainer()->currentIndex());
2379 }
2380 
2381 void KonqMainWindow::slotRemoveOtherTabsPopup()
2382 {
2383     // Can't do immediately - kills the tabbar, and we're in an event path down from it
2384     QMetaObject::invokeMethod(this, "removeOtherTabs", Qt::QueuedConnection, Q_ARG(int, m_workingTab));
2385 }
2386 
2387 void KonqMainWindow::removeOtherTabs(int tabToKeep)
2388 {
2389     if (KMessageBox::warningContinueCancel(
2390                 this,
2391                 i18n("Do you really want to close all other tabs?"),
2392                 i18nc("@title:window", "Close Other Tabs Confirmation"), KGuiItem(i18n("Close &Other Tabs"), QStringLiteral("tab-close-other")),
2393                 KStandardGuiItem::cancel(), QStringLiteral("CloseOtherTabConfirm")) != KMessageBox::Continue) {
2394         return;
2395     }
2396 
2397     KonqFrameTabs *tabContainer = m_pViewManager->tabContainer();
2398     const int originalTabIndex = tabContainer->currentIndex();
2399     for (int tabIndex = 0; tabIndex < tabContainer->count(); ++tabIndex) {
2400         if (tabIndex == tabToKeep) {
2401             continue;
2402         }
2403         KonqFrameBase *tab = tabContainer->tabAt(tabIndex);
2404         if (!KonqModifiedViewsCollector::collect(tab).isEmpty()) {
2405             m_pViewManager->showTab(tabIndex);
2406             if (KMessageBox::warningContinueCancel(
2407                         this,
2408                         i18n("This tab contains changes that have not been submitted.\nClosing other tabs will discard these changes."),
2409                         i18nc("@title:window", "Discard Changes?"), KGuiItem(i18n("&Discard Changes"), QStringLiteral("tab-close")),
2410                         KStandardGuiItem::cancel(), QStringLiteral("discardchangescloseother")) != KMessageBox::Continue) {
2411                 m_pViewManager->showTab(originalTabIndex);
2412                 return;
2413             }
2414         }
2415     }
2416     m_pViewManager->showTab(originalTabIndex);
2417     m_pViewManager->removeOtherTabs(tabToKeep);
2418     updateViewActions();
2419 }
2420 
2421 void KonqMainWindow::slotReloadAllTabs()
2422 {
2423     KonqFrameTabs *tabContainer = m_pViewManager->tabContainer();
2424     const int originalTabIndex = tabContainer->currentIndex();
2425     for (int tabIndex = 0; tabIndex < tabContainer->count(); ++tabIndex) {
2426         KonqFrameBase *tab = tabContainer->tabAt(tabIndex);
2427         if (!KonqModifiedViewsCollector::collect(tab).isEmpty()) {
2428             m_pViewManager->showTab(tabIndex);
2429             if (KMessageBox::warningContinueCancel(this,
2430                                                    i18n("This tab contains changes that have not been submitted.\nReloading all tabs will discard these changes."),
2431                                                    i18nc("@title:window", "Discard Changes?"),
2432                                                    KGuiItem(i18n("&Discard Changes"), QStringLiteral("view-refresh")),
2433                                                    KStandardGuiItem::cancel(), QStringLiteral("discardchangesreload")) != KMessageBox::Continue) {
2434                 m_pViewManager->showTab(originalTabIndex);
2435                 return;
2436             }
2437         }
2438     }
2439     m_pViewManager->showTab(originalTabIndex);
2440     m_pViewManager->reloadAllTabs();
2441     updateViewActions();
2442 }
2443 
2444 int KonqMainWindow::tabsCount() const
2445 {
2446     return m_pViewManager->tabsCount();
2447 }
2448 
2449 int KonqMainWindow::currentTabIndex() const
2450 {
2451     return m_pViewManager->currentTabIndex();
2452 }
2453 
2454 void KonqMainWindow::activateTab(int index)
2455 {
2456     m_pViewManager->activateTab(index);
2457 }
2458 
2459 void KonqMainWindow::slotActivateNextTab()
2460 {
2461     m_pViewManager->activateNextTab();
2462 }
2463 
2464 void KonqMainWindow::slotActivatePrevTab()
2465 {
2466     m_pViewManager->activatePrevTab();
2467 }
2468 
2469 void KonqMainWindow::slotActivateTab()
2470 {
2471     m_pViewManager->activateTab(QStringView{sender()->objectName()}.right(2).toInt() - 1);
2472 }
2473 
2474 void KonqMainWindow::slotDumpDebugInfo()
2475 {
2476 #ifndef NDEBUG
2477     dumpViewList();
2478     m_pViewManager->printFullHierarchy();
2479 #endif
2480 }
2481 
2482 bool KonqMainWindow::askForTarget(const KLocalizedString &text, QUrl &url)
2483 {
2484     const QUrl initialUrl = (viewCount() == 2) ? otherView(m_currentView)->url() : m_currentView->url();
2485     QString label = text.subs(m_currentView->url().toDisplayString(QUrl::PreferLocalFile)).toString();
2486     KUrlRequesterDialog dlg(initialUrl, label, this);
2487     dlg.setWindowTitle(i18nc("@title:window", "Enter Target"));
2488     dlg.urlRequester()->setMode(KFile::File | KFile::ExistingOnly | KFile::Directory);
2489     if (dlg.exec()) {
2490         url = dlg.selectedUrl();
2491         if (url.isValid()) {
2492             return true;
2493         } else {
2494             KMessageBox::error(this, i18n("<qt><b>%1</b> is not valid</qt>", url.url()));
2495             return false;
2496         }
2497     }
2498     return false;
2499 }
2500 
2501 void KonqMainWindow::slotCopyFiles()
2502 {
2503     QUrl dest;
2504     if (!askForTarget(ki18n("Copy selected files from %1 to:"), dest)) {
2505         return;
2506     }
2507 
2508     KIO::CopyJob *job = KIO::copy(currentURLs(), dest);
2509     KIO::FileUndoManager::self()->recordCopyJob(job);
2510     KJobWidgets::setWindow(job, this);
2511     job->uiDelegate()->setAutoErrorHandlingEnabled(true);
2512 }
2513 
2514 void KonqMainWindow::slotMoveFiles()
2515 {
2516     QUrl dest;
2517     if (!askForTarget(ki18n("Move selected files from %1 to:"), dest)) {
2518         return;
2519     }
2520 
2521     KIO::CopyJob *job = KIO::move(currentURLs(), dest);
2522     KIO::FileUndoManager::self()->recordCopyJob(job);
2523     KJobWidgets::setWindow(job, this);
2524     job->uiDelegate()->setAutoErrorHandlingEnabled(true);
2525 }
2526 
2527 QList<QUrl> KonqMainWindow::currentURLs() const
2528 {
2529     QList<QUrl> urls;
2530     if (m_currentView) {
2531         //TODO KF6: check whether requestedUrl or realUrl is more suitable here
2532         urls.append(m_currentView->url());
2533         if (!m_currentView->selectedItems().isEmpty()) { // Return list of selected items only if we have a selection
2534             urls = m_currentView->selectedItems().urlList();
2535         }
2536     }
2537     return urls;
2538 }
2539 
2540 // Only valid if there are one or two views
2541 KonqView *KonqMainWindow::otherView(KonqView *view) const
2542 {
2543     Q_ASSERT(viewCount() <= 2);
2544     MapViews::ConstIterator it = m_mapViews.constBegin();
2545     if ((*it) == view) {
2546         ++it;
2547     }
2548     if (it != m_mapViews.constEnd()) {
2549         return (*it);
2550     }
2551     return nullptr;
2552 }
2553 
2554 void KonqMainWindow::slotUpAboutToShow()
2555 {
2556     if (!m_currentView) {
2557         return;
2558     }
2559 
2560     QMenu *popup = m_paUp->popupMenu();
2561     popup->clear();
2562 
2563     int i = 0;
2564 
2565     // Use the location bar URL, because in case we display a index.html
2566     // we want to go up from the dir, not from the index.html
2567     QUrl u(QUrl::fromUserInput(m_currentView->locationBarURL()));
2568     u = KIO::upUrl(u);
2569     while (!u.path().isEmpty()) {
2570         QAction *action = new QAction(QIcon::fromTheme(KonqPixmapProvider::self()->iconNameFor(u)),
2571                                       u.toDisplayString(QUrl::PreferLocalFile),
2572                                       popup);
2573         action->setData(u);
2574         popup->addAction(action);
2575 
2576         if (u.path() == QLatin1String("/") || ++i > 10) {
2577             break;
2578         }
2579 
2580         u = KIO::upUrl(u);
2581     }
2582 }
2583 
2584 void KonqMainWindow::slotUp()
2585 {
2586     if (!m_currentView) {
2587         return;
2588     }
2589 
2590     Qt::MouseButtons goMouseState = QApplication::mouseButtons();
2591     Qt::KeyboardModifiers goKeyboardState = QApplication::keyboardModifiers();
2592 
2593     KonqOpenURLRequest req;
2594     req.browserArgs.setNewTab(true);
2595     req.forceAutoEmbed = true;
2596 
2597     req.openAfterCurrentPage = KonqSettings::openAfterCurrentPage();
2598     req.newTabInFront = KonqSettings::newTabsInFront();
2599 
2600     if (goKeyboardState & Qt::ShiftModifier) {
2601         req.newTabInFront = !req.newTabInFront;
2602     }
2603 
2604     const QUrl &url = m_currentView->upUrl();
2605     if (goKeyboardState & Qt::ControlModifier) {
2606         openFilteredUrl(url.url(), req);
2607     } else if (goMouseState & Qt::MiddleButton) {
2608         if (KonqSettings::mmbOpensTab()) {
2609             openFilteredUrl(url.url(), req);
2610         } else {
2611             KonqMainWindow *mw = KonqMainWindowFactory::createNewWindow(url);
2612             mw->show();
2613         }
2614     } else {
2615         openFilteredUrl(url.url(), false);
2616     }
2617 }
2618 
2619 void KonqMainWindow::slotUpActivated(QAction *action)
2620 {
2621     openUrl(nullptr, action->data().value<QUrl>());
2622 }
2623 
2624 void KonqMainWindow::slotGoHistoryActivated(int steps)
2625 {
2626     if (!m_goBuffer) {
2627         // Only start 1 timer.
2628         m_goBuffer = steps;
2629         m_goMouseState = QApplication::mouseButtons();
2630         m_goKeyboardState = QApplication::keyboardModifiers();
2631         QTimer::singleShot(0, this, SLOT(slotGoHistoryDelayed()));
2632     }
2633 }
2634 
2635 void KonqMainWindow::slotGoHistoryDelayed()
2636 {
2637     if (!m_currentView) {
2638         return;
2639     }
2640 
2641     bool openAfterCurrentPage = KonqSettings::openAfterCurrentPage();
2642     bool mmbOpensTab = KonqSettings::mmbOpensTab();
2643     bool inFront = KonqSettings::newTabsInFront();
2644     if (m_goKeyboardState & Qt::ShiftModifier) {
2645         inFront = !inFront;
2646     }
2647 
2648     if (m_goKeyboardState & Qt::ControlModifier) {
2649         KonqView *newView = m_pViewManager->addTabFromHistory(m_currentView, m_goBuffer, openAfterCurrentPage);
2650         if (newView && inFront) {
2651             m_pViewManager->showTab(newView);
2652         }
2653     } else if (m_goMouseState & Qt::MiddleButton) {
2654         if (mmbOpensTab) {
2655             KonqView *newView = m_pViewManager->addTabFromHistory(m_currentView, m_goBuffer, openAfterCurrentPage);
2656             if (newView && inFront) {
2657                 m_pViewManager->showTab(newView);
2658             }
2659         } else {
2660             KonqMisc::newWindowFromHistory(this->currentView(), m_goBuffer);
2661         }
2662     } else {
2663         m_currentView->go(m_goBuffer);
2664         makeViewsFollow(m_currentView->url(),
2665                         KParts::OpenUrlArguments(),
2666                         BrowserArguments(),
2667                         m_currentView->serviceType(),
2668                         m_currentView);
2669     }
2670 
2671     m_goBuffer = 0;
2672     m_goMouseState = Qt::LeftButton;
2673     m_goKeyboardState = Qt::NoModifier;
2674 }
2675 
2676 void KonqMainWindow::slotBackAboutToShow()
2677 {
2678     m_paBack->popupMenu()->clear();
2679     if (m_currentView) {
2680         KonqActions::fillHistoryPopup(m_currentView->history(), m_currentView->historyIndex(), m_paBack->popupMenu(), true, false);
2681     }
2682 }
2683 
2684 /**
2685  * Fill the closed tabs action menu before it's shown
2686  */
2687 void KonqMainWindow::slotClosedItemsListAboutToShow()
2688 {
2689     QMenu *popup = m_paClosedItems->popupMenu();
2690     // Clear the menu and fill it with a maximum of s_closedItemsListLength number of urls
2691     popup->clear();
2692     QAction *clearAction = popup->addAction(i18nc("This menu entry empties the closed items history", "Empty Closed Items History"));
2693     connect(clearAction, &QAction::triggered, m_pUndoManager, &KonqUndoManager::clearClosedItemsList);
2694     popup->insertSeparator(static_cast<QAction *>(nullptr));
2695 
2696     QList<KonqClosedItem *>::ConstIterator it = m_pUndoManager->closedItemsList().constBegin();
2697     const QList<KonqClosedItem *>::ConstIterator end = m_pUndoManager->closedItemsList().constEnd();
2698     for (int i = 0; it != end && i < s_closedItemsListLength; ++it, ++i) {
2699         const QString text = QString::number(i) + ' ' + (*it)->title();
2700         QAction *action = popup->addAction((*it)->icon(), text);
2701         action->setActionGroup(m_closedItemsGroup);
2702         action->setData(i);
2703     }
2704     KAcceleratorManager::manage(popup);
2705 }
2706 
2707 /**
2708  */
2709 void KonqMainWindow::slotSessionsListAboutToShow()
2710 {
2711     QMenu *popup = m_paSessions->menu();
2712     // Clear the menu and fill it with a maximum of s_closedItemsListLength number of urls
2713     popup->clear();
2714     QAction *saveSessionAction = popup->addAction(QIcon::fromTheme(QStringLiteral("document-save")), i18n("Save As..."));
2715     connect(saveSessionAction, &QAction::triggered, this, &KonqMainWindow::saveCurrentSession);
2716     QAction *manageSessionsAction = popup->addAction(QIcon::fromTheme(QStringLiteral("view-choose")), i18n("Manage..."));
2717     connect(manageSessionsAction, &QAction::triggered, this, &KonqMainWindow::manageSessions);
2718     popup->addSeparator();
2719 
2720     QString dir = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + QLatin1Char('/') + "sessions/";
2721     QDirIterator it(dir, QDir::Readable | QDir::NoDotAndDotDot | QDir::Dirs);
2722 
2723     while (it.hasNext()) {
2724         QFileInfo fileInfo(it.next());
2725 
2726         QAction *action = popup->addAction(KIO::decodeFileName(fileInfo.baseName()));
2727         action->setActionGroup(m_sessionsGroup);
2728         action->setData(fileInfo.filePath());
2729     }
2730     KAcceleratorManager::manage(popup);
2731 }
2732 
2733 void KonqMainWindow::saveCurrentSession()
2734 {
2735     KonqNewSessionDlg dlg(this, this);
2736     dlg.exec();
2737 }
2738 
2739 void KonqMainWindow::manageSessions()
2740 {
2741     KonqSessionDlg dlg(m_pViewManager, this);
2742     dlg.exec();
2743 }
2744 
2745 void KonqMainWindow::slotSessionActivated(QAction *action)
2746 {
2747     QString dirpath = action->data().toString();
2748     KonqSessionManager::self()->restoreSessions(dirpath);
2749 }
2750 
2751 void KonqMainWindow::updateClosedItemsAction()
2752 {
2753     bool available = m_pUndoManager->undoAvailable();
2754     m_paClosedItems->setEnabled(available);
2755     m_paUndo->setText(m_pUndoManager->undoText());
2756 }
2757 
2758 void KonqMainWindow::slotBack()
2759 {
2760     slotGoHistoryActivated(-1);
2761 }
2762 
2763 void KonqMainWindow::slotBackActivated(QAction *action)
2764 {
2765     slotGoHistoryActivated(action->data().toInt());
2766 }
2767 
2768 void KonqMainWindow::slotForwardAboutToShow()
2769 {
2770     m_paForward->popupMenu()->clear();
2771     if (m_currentView) {
2772         KonqActions::fillHistoryPopup(m_currentView->history(), m_currentView->historyIndex(), m_paForward->popupMenu(), false, true);
2773     }
2774 }
2775 
2776 void KonqMainWindow::slotForward()
2777 {
2778     slotGoHistoryActivated(1);
2779 }
2780 
2781 void KonqMainWindow::slotForwardActivated(QAction *action)
2782 {
2783     slotGoHistoryActivated(action->data().toInt());
2784 }
2785 
2786 void KonqMainWindow::checkDisableClearButton()
2787 {
2788     // if the location toolbar already has the clear_location action,
2789     // disable the combobox's embedded clear icon.
2790     KToolBar *ltb = toolBar(QStringLiteral("locationToolBar"));
2791     QAction *clearAction = action("clear_location");
2792     bool enable = true;
2793     const auto toolbuttons = ltb->findChildren<QToolButton *>();
2794     for (QToolButton *atb : toolbuttons) {
2795         if (atb->defaultAction() == clearAction) {
2796             enable = false;
2797             break;
2798         }
2799     }
2800     QLineEdit *lineEdit = comboEdit();
2801     if (lineEdit) {
2802         lineEdit->setClearButtonEnabled(enable);
2803     }
2804 }
2805 
2806 void KonqMainWindow::initCombo()
2807 {
2808     m_combo = new KonqCombo(nullptr);
2809 
2810     m_combo->init(s_pCompletion);
2811 
2812     connect(m_combo, SIGNAL(activated(QString,Qt::KeyboardModifiers)),
2813             this, SLOT(slotURLEntered(QString,Qt::KeyboardModifiers)));
2814     connect(m_combo, SIGNAL(showPageSecurity()),
2815             this, SLOT(showPageSecurity()));
2816 
2817     m_pURLCompletion = new KUrlCompletion();
2818     m_pURLCompletion->setCompletionMode(s_pCompletion->completionMode());
2819 
2820     // This only turns completion off. ~ is still there in the result
2821     // We do want completion of user names, right?
2822     //m_pURLCompletion->setReplaceHome( false );  // Leave ~ alone! Will be taken care of by filters!!
2823 
2824     connect(m_combo, SIGNAL(completionModeChanged(KCompletion::CompletionMode)),
2825             SLOT(slotCompletionModeChanged(KCompletion::CompletionMode)));
2826     connect(m_combo, SIGNAL(completion(QString)),
2827             SLOT(slotMakeCompletion(QString)));
2828     connect(m_combo, SIGNAL(substringCompletion(QString)),
2829             SLOT(slotSubstringcompletion(QString)));
2830     connect(m_combo, SIGNAL(textRotation(KCompletionBase::KeyBindingType)),
2831             SLOT(slotRotation(KCompletionBase::KeyBindingType)));
2832     connect(m_combo, SIGNAL(cleared()),
2833             SLOT(slotClearHistory()));
2834     connect(m_pURLCompletion, SIGNAL(match(QString)),
2835             SLOT(slotMatch(QString)));
2836 
2837     m_combo->installEventFilter(this);
2838 
2839     static bool bookmarkCompletionInitialized = false;
2840     if (!bookmarkCompletionInitialized) {
2841         bookmarkCompletionInitialized = true;
2842         DelayedInitializer *initializer = new DelayedInitializer(QEvent::KeyPress, m_combo);
2843         connect(initializer, &DelayedInitializer::initialize, this, &KonqMainWindow::bookmarksIntoCompletion);
2844     }
2845 }
2846 
2847 void KonqMainWindow::bookmarksIntoCompletion()
2848 {
2849     // add all bookmarks to the completion list for easy access
2850     addBookmarksIntoCompletion(s_bookmarkManager->root());
2851 }
2852 
2853 // the user changed the completion mode in the combo
2854 void KonqMainWindow::slotCompletionModeChanged(KCompletion::CompletionMode m)
2855 {
2856     s_pCompletion->setCompletionMode(m);
2857 
2858     KonqSettings::setSettingsCompletionMode(int(m_combo->completionMode()));
2859     KonqSettings::self()->save();
2860 
2861     // tell the other windows too (only this instance currently)
2862     for (KonqMainWindow *window: *s_lstMainWindows) {
2863         if (window && window->m_combo) {
2864             window->m_combo->setCompletionMode(m);
2865             window->m_pURLCompletion->setCompletionMode(m);
2866         }
2867     }
2868 }
2869 
2870 // at first, try to find a completion in the current view, then use the global
2871 // completion (history)
2872 void KonqMainWindow::slotMakeCompletion(const QString &text)
2873 {
2874     if (m_pURLCompletion) {
2875         m_urlCompletionStarted = true; // flag for slotMatch()
2876 
2877         // qCDebug(KONQUEROR_LOG) << "Local Completion object found!";
2878         QString completion = m_pURLCompletion->makeCompletion(text);
2879         m_currentDir.clear();
2880 
2881         if (completion.isNull() && !m_pURLCompletion->isRunning()) {
2882             // No match() signal will come from m_pURLCompletion
2883             // ask the global one
2884             // tell the static completion object about the current completion mode
2885             completion = s_pCompletion->makeCompletion(text);
2886 
2887             // some special handling necessary for CompletionPopup
2888             if (m_combo->completionMode() == KCompletion::CompletionPopup ||
2889                     m_combo->completionMode() == KCompletion::CompletionPopupAuto) {
2890                 m_combo->setCompletedItems(historyPopupCompletionItems(text));
2891             }
2892 
2893             else if (!completion.isNull()) {
2894                 m_combo->setCompletedText(completion);
2895             }
2896         } else {
2897             // To be continued in slotMatch()...
2898             if (!m_pURLCompletion->dir().isEmpty()) {
2899                 m_currentDir = m_pURLCompletion->dir();
2900             }
2901         }
2902     }
2903     // qCDebug(KONQUEROR_LOG) << "Current dir:" << m_currentDir << "Current text:" << text;
2904 }
2905 
2906 void KonqMainWindow::slotSubstringcompletion(const QString &text)
2907 {
2908     if (!m_currentView) {
2909         return;
2910     }
2911 
2912     QString currentURL = m_currentView->url().toDisplayString();
2913     bool filesFirst = currentURL.startsWith('/') ||
2914                       currentURL.startsWith(QLatin1String("file:/"));
2915     QStringList items;
2916     if (filesFirst && m_pURLCompletion) {
2917         items = m_pURLCompletion->substringCompletion(text);
2918     }
2919 
2920     items += s_pCompletion->substringCompletion(text);
2921     if (!filesFirst && m_pURLCompletion) {
2922         items += m_pURLCompletion->substringCompletion(text);
2923     }
2924 
2925     m_combo->setCompletedItems(items);
2926 }
2927 
2928 void KonqMainWindow::slotRotation(KCompletionBase::KeyBindingType type)
2929 {
2930     // Tell slotMatch() to do nothing
2931     m_urlCompletionStarted = false;
2932 
2933     bool prev = (type == KCompletionBase::PrevCompletionMatch);
2934     if (prev || type == KCompletionBase::NextCompletionMatch) {
2935         QString completion = prev ? m_pURLCompletion->previousMatch() :
2936                              m_pURLCompletion->nextMatch();
2937 
2938         if (completion.isNull()) {  // try the history KCompletion object
2939             completion = prev ? s_pCompletion->previousMatch() :
2940                          s_pCompletion->nextMatch();
2941         }
2942         if (completion.isEmpty() || completion == m_combo->currentText()) {
2943             return;
2944         }
2945 
2946         m_combo->setCompletedText(completion);
2947     }
2948 }
2949 
2950 // Handle match() from m_pURLCompletion
2951 void KonqMainWindow::slotMatch(const QString &match)
2952 {
2953     if (match.isEmpty() || !m_combo) {
2954         return;
2955     }
2956 
2957     // Check flag to avoid match() raised by rotation
2958     if (m_urlCompletionStarted) {
2959         m_urlCompletionStarted = false;
2960 
2961         // some special handling necessary for CompletionPopup
2962         if (m_combo->completionMode() == KCompletion::CompletionPopup ||
2963                 m_combo->completionMode() == KCompletion::CompletionPopupAuto) {
2964             QStringList items = m_pURLCompletion->allMatches();
2965             items += historyPopupCompletionItems(m_combo->currentText());
2966             items.removeDuplicates();  // when items from completion are also in history
2967             // items.sort(); // should we?
2968             m_combo->setCompletedItems(items);
2969         } else if (!match.isNull()) {
2970             m_combo->setCompletedText(match);
2971         }
2972     }
2973 }
2974 
2975 void KonqMainWindow::slotCtrlTabPressed()
2976 {
2977     KonqView *view = m_pViewManager->chooseNextView(m_currentView);
2978     //qCDebug(KONQUEROR_LOG) << m_currentView->url() << "->" << view->url();
2979     if (view) {
2980         m_pViewManager->setActivePart(view->part());
2981         KonqFrameTabs *tabs = m_pViewManager->tabContainer();
2982         m_pViewManager->showTab(tabs->tabIndexContaining(view->frame()));
2983     }
2984 }
2985 
2986 void KonqMainWindow::slotClearHistory()
2987 {
2988     KonqHistoryManager::kself()->emitClear();
2989 }
2990 
2991 void KonqMainWindow::slotClearComboHistory()
2992 {
2993     if (m_combo && m_combo->count()) {
2994         m_combo->clearHistory();
2995     }
2996 }
2997 
2998 bool KonqMainWindow::eventFilter(QObject *obj, QEvent *ev)
2999 {
3000     if ((ev->type() == QEvent::FocusIn || ev->type() == QEvent::FocusOut) &&
3001             m_combo && m_combo->lineEdit() && m_combo == obj) {
3002         //qCDebug(KONQUEROR_LOG) << obj << obj->metaObject()->className() << obj->name();
3003 
3004         QFocusEvent *focusEv = static_cast<QFocusEvent *>(ev);
3005         if (focusEv->reason() == Qt::PopupFocusReason) {
3006             return KParts::MainWindow::eventFilter(obj, ev);
3007         }
3008 
3009         KParts::NavigationExtension *ext = nullptr;
3010         if (m_currentView) {
3011             ext = m_currentView->browserExtension();
3012         }
3013 
3014         if (ev->type() == QEvent::FocusIn) {
3015             //qCDebug(KONQUEROR_LOG) << "ComboBox got the focus...";
3016             if (m_bLocationBarConnected) {
3017                 //qCDebug(KONQUEROR_LOG) << "Was already connected...";
3018                 return KParts::MainWindow::eventFilter(obj, ev);
3019             }
3020             m_bLocationBarConnected = true;
3021 
3022             // Workaround for Qt issue: usually, QLineEdit reacts on Ctrl-D,
3023             // but the duplicatecurrenttab action also has Ctrl-D as accel and
3024             // prevents the lineedit from getting this event. IMHO the accel
3025             // should be disabled in favor of the focus-widget.
3026             // TODO: decide if the delete-character behaviour of QLineEdit
3027             // really is useful enough to warrant this workaround
3028             QAction *duplicate = actionCollection()->action(QStringLiteral("duplicatecurrenttab"));
3029             if (duplicate->shortcuts().contains(QKeySequence(Qt::CTRL | Qt::Key_D))) {
3030                 duplicate->setEnabled(false);
3031             }
3032 
3033             connect(m_paCut, SIGNAL(triggered()), m_combo->lineEdit(), SLOT(cut()));
3034             connect(m_paCopy, SIGNAL(triggered()), m_combo->lineEdit(), SLOT(copy()));
3035             connect(m_paPaste, SIGNAL(triggered()), m_combo->lineEdit(), SLOT(paste()));
3036             connect(QApplication::clipboard(), SIGNAL(dataChanged()), this, SLOT(slotClipboardDataChanged()));
3037             connect(m_combo->lineEdit(), SIGNAL(textChanged(QString)), this, SLOT(slotCheckComboSelection()));
3038             connect(m_combo->lineEdit(), SIGNAL(selectionChanged()), this, SLOT(slotCheckComboSelection()));
3039 
3040             slotClipboardDataChanged();
3041         } else if (ev->type() == QEvent::FocusOut) {
3042             //qCDebug(KONQUEROR_LOG) << "ComboBox lost focus...";
3043             if (!m_bLocationBarConnected) {
3044                 //qCDebug(KONQUEROR_LOG) << "Was already disconnected...";
3045                 return KParts::MainWindow::eventFilter(obj, ev);
3046             }
3047             m_bLocationBarConnected = false;
3048 
3049             // see above in FocusIn for explanation
3050             // action is reenabled if a view exists
3051             QAction *duplicate = actionCollection()->action(QStringLiteral("duplicatecurrenttab"));
3052             if (duplicate->shortcuts().contains(QKeySequence(Qt::CTRL | Qt::Key_D))) {
3053                 duplicate->setEnabled(currentView() && currentView()->frame());
3054             }
3055 
3056             disconnect(m_paCut, SIGNAL(triggered()), m_combo->lineEdit(), SLOT(cut()));
3057             disconnect(m_paCopy, SIGNAL(triggered()), m_combo->lineEdit(), SLOT(copy()));
3058             disconnect(m_paPaste, SIGNAL(triggered()), m_combo->lineEdit(), SLOT(paste()));
3059             disconnect(QApplication::clipboard(), SIGNAL(dataChanged()), this, SLOT(slotClipboardDataChanged()));
3060             disconnect(m_combo->lineEdit(), SIGNAL(textChanged(QString)), this, SLOT(slotCheckComboSelection()));
3061             disconnect(m_combo->lineEdit(), SIGNAL(selectionChanged()), this, SLOT(slotCheckComboSelection()));
3062 
3063             if (ext) {
3064                 m_paCut->setEnabled(ext->isActionEnabled("cut"));
3065                 m_paCopy->setEnabled(ext->isActionEnabled("copy"));
3066                 m_paPaste->setEnabled(ext->isActionEnabled("paste"));
3067             } else {
3068                 m_paCut->setEnabled(false);
3069                 m_paCopy->setEnabled(false);
3070                 m_paPaste->setEnabled(false);
3071             }
3072         }
3073     } else if (ev->type() == QEvent::KeyPress) {
3074         QKeyEvent *keyEv = static_cast<QKeyEvent *>(ev);
3075         if ((keyEv->key() == Qt::Key_Tab) && (keyEv->modifiers() == Qt::ControlModifier)) {
3076             slotCtrlTabPressed();
3077             return true; // don't let QTabWidget see the event
3078         } else if (obj == m_combo && m_currentView && keyEv->key() == Qt::Key_Escape) {
3079             // reset url to current view's actual url on ESC
3080             m_combo->setURL(m_currentView->url().QUrl::toDisplayString(QUrl::PreferLocalFile));
3081             m_combo->lineEdit()->setModified(false);
3082             return true;
3083         }
3084     }
3085     return KParts::MainWindow::eventFilter(obj, ev);
3086 }
3087 
3088 // Only called when m_bLocationBarConnected, i.e. when the combobox has focus.
3089 // The rest of the time, the part handles the cut/copy/paste actions.
3090 void KonqMainWindow::slotClipboardDataChanged()
3091 {
3092     const QMimeData *data = QApplication::clipboard()->mimeData();
3093     if (data) {
3094         m_paPaste->setEnabled(data->hasText());
3095         slotCheckComboSelection();
3096     }
3097 }
3098 
3099 void KonqMainWindow::slotCheckComboSelection()
3100 {
3101     QLineEdit *edit = comboEdit();
3102     if (edit) {
3103         const bool hasSelection = edit->hasSelectedText();
3104         //qCDebug(KONQUEROR_LOG) << "m_combo->lineEdit()->hasMarkedText():" << hasSelection;
3105         m_paCopy->setEnabled(hasSelection);
3106         m_paCut->setEnabled(hasSelection);
3107     }
3108 }
3109 
3110 void KonqMainWindow::slotClearLocationBar()
3111 {
3112     slotStop();
3113     if (m_combo) {
3114         m_combo->clearTemporary();
3115     }
3116     focusLocationBar();
3117 }
3118 
3119 void KonqMainWindow::slotForceSaveMainWindowSettings()
3120 {
3121     if (autoSaveSettings()) {   // don't do it on e.g. JS window.open windows with no toolbars!
3122         KConfigGroup config = KSharedConfig::openConfig()->group("MainWindow");
3123         saveMainWindowSettings(config);
3124     }
3125 }
3126 
3127 void KonqMainWindow::slotShowMenuBar()
3128 {
3129     menuBar()->setVisible(!menuBar()->isVisible());
3130     slotForceSaveMainWindowSettings();
3131 }
3132 
3133 void KonqMainWindow::slotShowStatusBar()
3134 {
3135     if (m_currentView) {
3136         m_currentView->frame()->statusbar()->setVisible(m_paShowStatusBar->isChecked());
3137     }
3138 
3139     // An alternative: this will change simultaneously all of the status bars on
3140     // all of the current views.
3141     //MapViews::const_iterator end = m_mapViews.constEnd();
3142     //for (MapViews::const_iterator it = m_mapViews.constBegin(); it != end; ++it) {
3143     //  KonqView* view = it.value();
3144     //  view->frame()->statusbar()->setVisible(on);
3145     //}
3146 
3147     slotForceSaveMainWindowSettings();
3148 }
3149 
3150 void KonqMainWindow::slotUpdateFullScreen(bool set)
3151 {
3152     if (m_fullScreenData.currentState == FullScreenState::CompleteFullScreen) {
3153         if (m_currentView && m_currentView->part()) {
3154             QMetaObject::invokeMethod(m_currentView->part(), "exitFullScreen");
3155         }
3156         return;
3157     }
3158 
3159     KToggleFullScreenAction::setFullScreen(this, set);
3160     if (set) {
3161         // Create toolbar button for exiting from full-screen mode
3162         // ...but only if there isn't one already...
3163 
3164         bool haveFullScreenButton = false;
3165 
3166         //Walk over the toolbars and check whether there is a show fullscreen button in any of them
3167         for (KToolBar *bar: findChildren<KToolBar *>()) {
3168             //Are we plugged here, in a visible toolbar?
3169             if (bar->isVisible() &&
3170                     action("fullscreen")->associatedWidgets().contains(bar)) {
3171                 haveFullScreenButton = true;
3172                 break;
3173             }
3174         }
3175 
3176         if (!haveFullScreenButton) {
3177             QList<QAction *> lst;
3178             lst.append(m_ptaFullScreen);
3179             plugActionList(QStringLiteral("fullscreen"), lst);
3180         }
3181 
3182         m_fullScreenData.wasMenuBarVisible = menuBar()->isVisible();
3183         menuBar()->hide();
3184         m_paShowMenuBar->setChecked(false);
3185     } else {
3186         unplugActionList(QStringLiteral("fullscreen"));
3187 
3188         if (m_fullScreenData.wasMenuBarVisible) {
3189             menuBar()->show();
3190             m_paShowMenuBar->setChecked(true);
3191         }
3192     }
3193     m_fullScreenData.switchToState(set ? FullScreenState::OrdinaryFullScreen : FullScreenState::NoFullScreen);
3194 }
3195 
3196 void KonqMainWindow::setLocationBarURL(const QUrl &url)
3197 {
3198     setLocationBarURL(url.toString());
3199 }
3200 
3201 void KonqMainWindow::setLocationBarURL(const QString &url)
3202 {
3203     // Don't set the location bar URL if it hasn't changed
3204     // or if the user had time to edit the url since the last call to openUrl (#64868)
3205     QLineEdit *edit = comboEdit();
3206     if (edit && url != edit->text() && !edit->isModified()) {
3207         //qCDebug(KONQUEROR_LOG) << "url=" << url;
3208         m_combo->setURL(url);
3209         updateWindowIcon();
3210     }
3211 }
3212 
3213 void KonqMainWindow::setPageSecurity(PageSecurity pageSecurity)
3214 {
3215     if (m_combo) {
3216         m_combo->setPageSecurity(pageSecurity);
3217     }
3218 }
3219 
3220 void KonqMainWindow::showPageSecurity()
3221 {
3222     if (m_currentView && m_currentView->part()) {
3223         QAction *act = m_currentView->part()->action("security");
3224         if (act) {
3225             act->trigger();
3226         }
3227     }
3228 }
3229 
3230 // Called via DBUS from KonquerorApplication
3231 void KonqMainWindow::comboAction(int action, const QString &url, const QString &senderId)
3232 {
3233     if (!s_lstMainWindows) { // this happens in "konqueror --silent"
3234         return;
3235     }
3236 
3237     KonqCombo *combo = nullptr;
3238     for (KonqMainWindow *window: *s_lstMainWindows) {
3239         if (window && window->m_combo) {
3240             combo = window->m_combo;
3241 
3242             switch (action) {
3243             case ComboAdd:
3244                 combo->insertPermanent(url);
3245                 break;
3246             case ComboClear:
3247                 combo->clearHistory();
3248                 break;
3249             case ComboRemove:
3250                 combo->removeURL(url);
3251                 break;
3252             default:
3253                 break;
3254             }
3255         }
3256     }
3257 
3258     // only one instance should save...
3259     if (combo && senderId == QDBusConnection::sessionBus().baseService()) {
3260         combo->saveItems();
3261     }
3262 }
3263 
3264 QString KonqMainWindow::locationBarURL() const
3265 {
3266     return (m_combo ? m_combo->currentText() : QString());
3267 }
3268 
3269 void KonqMainWindow::focusLocationBar()
3270 {
3271     if (m_combo && (m_combo->isVisible() || !isVisible())) {
3272         m_combo->setFocus();
3273     }
3274 }
3275 
3276 void KonqMainWindow::startAnimation()
3277 {
3278     m_paAnimatedLogo->start();
3279     m_paStop->setEnabled(true);
3280 }
3281 
3282 void KonqMainWindow::stopAnimation()
3283 {
3284     m_paAnimatedLogo->stop();
3285     m_paStop->setEnabled(false);
3286 }
3287 
3288 void KonqMainWindow::setUpEnabled(const QUrl &url)
3289 {
3290     bool bHasUpURL = ((!url.path().isEmpty() && url.path() != QLatin1String("/") && url.path()[0] == '/')
3291                       || !url.query().isEmpty() /*e.g. lists.kde.org*/);
3292 
3293     m_paUp->setEnabled(bHasUpURL);
3294 }
3295 
3296 void KonqMainWindow::initActions()
3297 {
3298     // Note about this method : don't call setEnabled() on any of the actions.
3299     // They are all disabled then re-enabled with enableAllActions
3300     // If any one needs to be initially disabled, put that code in enableAllActions
3301 
3302     // For the popup menu only.
3303     m_pMenuNew = new KNewFileMenu(this);
3304 
3305     // File menu
3306 
3307     QAction *action = actionCollection()->addAction(QStringLiteral("new_window"));
3308     action->setIcon(QIcon::fromTheme(QStringLiteral("window-new")));
3309     action->setText(i18n("New &Window"));
3310     connect(action, &QAction::triggered, this, &KonqMainWindow::slotNewWindow);
3311     actionCollection()->setDefaultShortcuts(action, KStandardShortcut::shortcut(KStandardShortcut::New));
3312     action = actionCollection()->addAction(QStringLiteral("duplicate_window"));
3313     action->setIcon(QIcon::fromTheme(QStringLiteral("window-duplicate")));
3314     action->setText(i18n("&Duplicate Window"));
3315     connect(action, &QAction::triggered, this, &KonqMainWindow::slotDuplicateWindow);
3316     actionCollection()->setDefaultShortcut(action, Qt::CTRL | Qt::SHIFT | Qt::Key_D);
3317     action = actionCollection()->addAction(QStringLiteral("sendURL"));
3318     action->setIcon(QIcon::fromTheme(QStringLiteral("mail-message-new")));
3319     action->setText(i18n("Send &Link Address..."));
3320     connect(action, &QAction::triggered, this, &KonqMainWindow::slotSendURL);
3321     action = actionCollection()->addAction(QStringLiteral("sendPage"));
3322     action->setIcon(QIcon::fromTheme(QStringLiteral("mail-message-new")));
3323     action->setText(i18n("S&end File..."));
3324     connect(action, &QAction::triggered, this, &KonqMainWindow::slotSendFile);
3325     action = actionCollection()->addAction(QStringLiteral("open_location"));
3326     action->setIcon(QIcon::fromTheme(QStringLiteral("document-open-remote")));
3327     action->setText(i18n("&Open Location"));
3328     actionCollection()->setDefaultShortcut(action, Qt::ALT | Qt::Key_O);
3329     connect(action, &QAction::triggered, this, &KonqMainWindow::slotOpenLocation);
3330 
3331     action = actionCollection()->addAction(QStringLiteral("open_file"));
3332     action->setIcon(QIcon::fromTheme(QStringLiteral("document-open")));
3333     action->setText(i18n("&Open File..."));
3334     connect(action, &QAction::triggered, this, &KonqMainWindow::slotOpenFile);
3335     actionCollection()->setDefaultShortcuts(action, KStandardShortcut::shortcut(KStandardShortcut::Open));
3336 
3337 #if 0
3338     m_paFindFiles = new KToggleAction(QIcon::fromTheme("edit-find"), i18n("&Find File..."), this);
3339     actionCollection()->addAction("findfile", m_paFindFiles);
3340     connect(m_paFindFiles, &KToggleAction::triggered, this, &KonqMainWindow::slotToolFind);
3341     actionCollection()->setDefaultShortcuts(m_paFindFiles, KStandardShortcut::shortcut(KStandardShortcut::Find));
3342 #endif
3343 
3344     m_paPrint = actionCollection()->addAction(KStandardAction::Print, QStringLiteral("print"), nullptr, nullptr);
3345     actionCollection()->addAction(KStandardAction::Quit, QStringLiteral("quit"), this, SLOT(close()));
3346 
3347     m_paLockView = new KToggleAction(i18n("Lock to Current Location"), this);
3348     actionCollection()->addAction(QStringLiteral("lock"), m_paLockView);
3349     connect(m_paLockView, &KToggleAction::triggered, this, &KonqMainWindow::slotLockView);
3350     m_paLinkView = new KToggleAction(i18nc("This option links konqueror views", "Lin&k View"), this);
3351     actionCollection()->addAction(QStringLiteral("link"), m_paLinkView);
3352     connect(m_paLinkView, &KToggleAction::triggered, this, &KonqMainWindow::slotLinkView);
3353 
3354     // Go menu
3355     m_paUp = new KToolBarPopupAction(QIcon::fromTheme(QStringLiteral("go-up")), i18n("&Up"), this);
3356     actionCollection()->addAction(QStringLiteral("go_up"), m_paUp);
3357     actionCollection()->setDefaultShortcuts(m_paUp, KStandardShortcut::shortcut(KStandardShortcut::Up));
3358     connect(m_paUp, &QAction::triggered, this, &KonqMainWindow::slotUp);
3359     connect(m_paUp->popupMenu(), &QMenu::aboutToShow, this, &KonqMainWindow::slotUpAboutToShow);
3360     connect(m_paUp->popupMenu(), &QMenu::triggered, this, &KonqMainWindow::slotUpActivated);
3361 
3362     QPair< KGuiItem, KGuiItem > backForward = KStandardGuiItem::backAndForward();
3363 
3364     // Trash bin of closed tabs
3365     m_paClosedItems = new KToolBarPopupAction(QIcon::fromTheme(QStringLiteral("edit-undo-closed-tabs")),  i18n("Closed Items"), this);
3366     actionCollection()->addAction(QStringLiteral("closeditems"), m_paClosedItems);
3367     m_closedItemsGroup = new QActionGroup(m_paClosedItems->popupMenu());
3368 
3369     // set the closed tabs list shown
3370     connect(m_paClosedItems, &KToolBarPopupAction::triggered, m_pUndoManager, &KonqUndoManager::undoLastClosedItem);
3371     connect(m_paClosedItems->popupMenu(), &QMenu::aboutToShow, this, &KonqMainWindow::slotClosedItemsListAboutToShow);
3372     connect(m_closedItemsGroup, &QActionGroup::triggered, m_pUndoManager, &KonqUndoManager::slotClosedItemsActivated);
3373     connect(m_pViewManager, &KonqViewManager::aboutToRemoveTab, this, &KonqMainWindow::slotAddClosedUrl);
3374     connect(m_pUndoManager, &KonqUndoManager::openClosedTab, m_pViewManager, &KonqViewManager::openClosedTab);
3375     connect(m_pUndoManager, &KonqUndoManager::openClosedWindow, m_pViewManager, &KonqViewManager::openClosedWindow);
3376     connect(m_pUndoManager, &KonqUndoManager::closedItemsListChanged, this, &KonqMainWindow::updateClosedItemsAction);
3377 
3378     m_paSessions = new KActionMenu(i18n("Sessions"), this);
3379     actionCollection()->addAction(QStringLiteral("sessions"), m_paSessions);
3380     m_sessionsGroup = new QActionGroup(m_paSessions->menu());
3381     connect(m_paSessions->menu(), &QMenu::aboutToShow, this, &KonqMainWindow::slotSessionsListAboutToShow);
3382     connect(m_sessionsGroup, &QActionGroup::triggered, this, &KonqMainWindow::slotSessionActivated);
3383 
3384     m_paBack = new KToolBarPopupAction(QIcon::fromTheme(backForward.first.iconName()), backForward.first.text(), this);
3385     actionCollection()->addAction(QStringLiteral("go_back"), m_paBack);
3386     actionCollection()->setDefaultShortcuts(m_paBack, KStandardShortcut::shortcut(KStandardShortcut::Back));
3387     connect(m_paBack, &QAction::triggered, this, &KonqMainWindow::slotBack);
3388     connect(m_paBack->popupMenu(), &QMenu::aboutToShow, this, &KonqMainWindow::slotBackAboutToShow);
3389     connect(m_paBack->popupMenu(), &QMenu::triggered, this, &KonqMainWindow::slotBackActivated);
3390 
3391     m_paForward = new KToolBarPopupAction(QIcon::fromTheme(backForward.second.iconName()), backForward.second.text(), this);
3392     actionCollection()->addAction(QStringLiteral("go_forward"), m_paForward);
3393     actionCollection()->setDefaultShortcuts(m_paForward, KStandardShortcut::shortcut(KStandardShortcut::Forward));
3394     connect(m_paForward, &QAction::triggered, this, &KonqMainWindow::slotForward);
3395     connect(m_paForward->popupMenu(), &QMenu::aboutToShow, this, &KonqMainWindow::slotForwardAboutToShow);
3396     connect(m_paForward->popupMenu(), &QMenu::triggered, this, &KonqMainWindow::slotForwardActivated);
3397 
3398     m_paHome = actionCollection()->addAction(KStandardAction::Home);
3399     connect(m_paHome, &QAction::triggered, this, &KonqMainWindow::slotHome);
3400     m_paHomePopup = new KToolBarPopupAction (QIcon::fromTheme(QStringLiteral("go-home")), i18n("Home"), this);
3401     actionCollection()->addAction(QStringLiteral("go_home_popup"), m_paHomePopup);
3402     connect(m_paHomePopup, &QAction::triggered, this, &KonqMainWindow::slotHome);
3403     connect(m_paHomePopup->popupMenu(), &QMenu::triggered, this, &KonqMainWindow::slotHomePopupActivated);
3404 
3405     KonqMostOftenURLSAction *mostOften = new KonqMostOftenURLSAction(i18nc("@action:inmenu Go", "Most Often Visited"), this);
3406     actionCollection()->addAction(QStringLiteral("go_most_often"), mostOften);
3407     connect(mostOften, &KonqMostOftenURLSAction::activated, this, &KonqMainWindow::slotOpenURL);
3408 
3409     KonqHistoryAction *historyAction = new KonqHistoryAction(i18nc("@action:inmenu Go", "Recently Visited"), this);
3410     actionCollection()->addAction(QStringLiteral("history"), historyAction);
3411     connect(historyAction, &KonqHistoryAction::activated, this, &KonqMainWindow::slotOpenURL);
3412 
3413     action = actionCollection()->addAction(QStringLiteral("go_history"));
3414     action->setIcon(QIcon::fromTheme(QStringLiteral("view-history")));
3415     // Ctrl+Shift+H, shortcut from firefox
3416     // TODO: and Ctrl+H should open the sidebar history module
3417     actionCollection()->setDefaultShortcut(action, Qt::CTRL | Qt::SHIFT | Qt::Key_H);
3418     action->setText(i18nc("@action:inmenu Go", "Show History"));
3419     connect(action, &QAction::triggered, this, &KonqMainWindow::slotGoHistory);
3420 
3421     // Settings menu
3422     actionCollection()->addAction(KStandardAction::Preferences, QStringLiteral("options_configure"), this, QOverload<>::of(&KonqMainWindow::slotConfigure));
3423 
3424     KStandardAction::keyBindings(guiFactory(), &KXMLGUIFactory::showConfigureShortcutsDialog, actionCollection());
3425 
3426     actionCollection()->addAction(KStandardAction::ConfigureToolbars, this, SLOT(slotConfigureToolbars()));
3427 
3428     m_paConfigureExtensions = actionCollection()->addAction(QStringLiteral("options_configure_extensions"));
3429     m_paConfigureExtensions->setIcon(QIcon::fromTheme(QStringLiteral("plugins")));
3430     m_paConfigureExtensions->setText(i18n("Configure Extensions..."));
3431     connect(m_paConfigureExtensions, &QAction::triggered, this, &KonqMainWindow::slotConfigureExtensions);
3432     m_paConfigureSpellChecking = actionCollection()->addAction(QStringLiteral("configurespellcheck"));
3433     m_paConfigureSpellChecking->setIcon(QIcon::fromTheme(QStringLiteral("tools-check-spelling")));
3434     m_paConfigureSpellChecking->setText(i18n("Configure Spell Checking..."));
3435     connect(m_paConfigureSpellChecking, &QAction::triggered, this, &KonqMainWindow::slotConfigureSpellChecking);
3436 
3437     // Window menu
3438     m_paSplitViewHor = actionCollection()->addAction(QStringLiteral("splitviewh"));
3439     m_paSplitViewHor->setIcon(QIcon::fromTheme(QStringLiteral("view-split-left-right")));
3440     m_paSplitViewHor->setText(i18n("Split View &Left/Right"));
3441     connect(m_paSplitViewHor, &QAction::triggered, this, &KonqMainWindow::slotSplitViewHorizontal);
3442     actionCollection()->setDefaultShortcut(m_paSplitViewHor, Qt::CTRL | Qt::SHIFT | Qt::Key_L);
3443     m_paSplitViewVer = actionCollection()->addAction(QStringLiteral("splitviewv"));
3444     m_paSplitViewVer->setIcon(QIcon::fromTheme(QStringLiteral("view-split-top-bottom")));
3445     m_paSplitViewVer->setText(i18n("Split View &Top/Bottom"));
3446     connect(m_paSplitViewVer, &QAction::triggered, this, &KonqMainWindow::slotSplitViewVertical);
3447     actionCollection()->setDefaultShortcut(m_paSplitViewVer, Qt::CTRL | Qt::SHIFT | Qt::Key_T);
3448     m_paAddTab = actionCollection()->addAction(QStringLiteral("newtab"));
3449     m_paAddTab->setIcon(QIcon::fromTheme(QStringLiteral("tab-new")));
3450     m_paAddTab->setText(i18n("&New Tab"));
3451     connect(m_paAddTab, &QAction::triggered, this, &KonqMainWindow::slotAddTab);
3452     QList<QKeySequence> addTabShortcuts;
3453     addTabShortcuts.append(QKeySequence(Qt::CTRL | Qt::Key_T));
3454     addTabShortcuts.append(QKeySequence(Qt::CTRL | Qt::SHIFT | Qt::Key_N));
3455     actionCollection()->setDefaultShortcuts(m_paAddTab, addTabShortcuts);
3456 
3457     m_paDuplicateTab = actionCollection()->addAction(QStringLiteral("duplicatecurrenttab"));
3458     m_paDuplicateTab->setIcon(QIcon::fromTheme(QStringLiteral("tab-duplicate")));
3459     m_paDuplicateTab->setText(i18n("&Duplicate Current Tab"));
3460     connect(m_paDuplicateTab, &QAction::triggered, this, &KonqMainWindow::slotDuplicateTab);
3461     actionCollection()->setDefaultShortcut(m_paDuplicateTab, Qt::CTRL | Qt::Key_D);
3462     m_paBreakOffTab = actionCollection()->addAction(QStringLiteral("breakoffcurrenttab"));
3463     m_paBreakOffTab->setIcon(QIcon::fromTheme(QStringLiteral("tab-detach")));
3464     m_paBreakOffTab->setText(i18n("Detach Current Tab"));
3465     connect(m_paBreakOffTab, &QAction::triggered, this, &KonqMainWindow::slotBreakOffTab);
3466     actionCollection()->setDefaultShortcut(m_paBreakOffTab, Qt::CTRL | Qt::SHIFT | Qt::Key_B);
3467     m_paRemoveView = actionCollection()->addAction(QStringLiteral("removeview"));
3468     m_paRemoveView->setIcon(QIcon::fromTheme(QStringLiteral("view-close")));
3469     m_paRemoveView->setText(i18n("&Close Active View"));
3470     connect(m_paRemoveView, &QAction::triggered, this, &KonqMainWindow::slotRemoveView);
3471     actionCollection()->setDefaultShortcut(m_paRemoveView, Qt::CTRL | Qt::SHIFT | Qt::Key_W);
3472     m_paRemoveTab = actionCollection()->addAction(QStringLiteral("removecurrenttab"));
3473     m_paRemoveTab->setIcon(QIcon::fromTheme(QStringLiteral("tab-close")));
3474     m_paRemoveTab->setText(i18n("Close Current Tab"));
3475     connect(m_paRemoveTab, &QAction::triggered, this, &KonqMainWindow::slotRemoveTab, Qt::QueuedConnection /* exit Ctrl | W handler before deleting */);
3476     actionCollection()->setDefaultShortcut(m_paRemoveTab, Qt::CTRL | Qt::Key_W);
3477     m_paRemoveTab->setAutoRepeat(false);
3478     m_paRemoveOtherTabs = actionCollection()->addAction(QStringLiteral("removeothertabs"));
3479     m_paRemoveOtherTabs->setIcon(QIcon::fromTheme(QStringLiteral("tab-close-other")));
3480     m_paRemoveOtherTabs->setText(i18n("Close &Other Tabs"));
3481     connect(m_paRemoveOtherTabs, &QAction::triggered, this, &KonqMainWindow::slotRemoveOtherTabs);
3482 
3483     m_paActivateNextTab = actionCollection()->addAction(QStringLiteral("activatenexttab"));
3484     m_paActivateNextTab->setText(i18n("Activate Next Tab"));
3485     connect(m_paActivateNextTab, &QAction::triggered, this, &KonqMainWindow::slotActivateNextTab);
3486     actionCollection()->setDefaultShortcuts(m_paActivateNextTab, QApplication::isRightToLeft() ? KStandardShortcut::tabPrev() : KStandardShortcut::tabNext());
3487     m_paActivatePrevTab = actionCollection()->addAction(QStringLiteral("activateprevtab"));
3488     m_paActivatePrevTab->setText(i18n("Activate Previous Tab"));
3489     connect(m_paActivatePrevTab, &QAction::triggered, this, &KonqMainWindow::slotActivatePrevTab);
3490     actionCollection()->setDefaultShortcuts(m_paActivatePrevTab, QApplication::isRightToLeft() ? KStandardShortcut::tabNext() : KStandardShortcut::tabPrev());
3491 
3492     for (int i = 1; i < 13; i++) {
3493         const QString actionname = QString::asprintf("activate_tab_%02d", i);
3494         QAction *action = actionCollection()->addAction(actionname);
3495         action->setText(i18n("Activate Tab %1", i));
3496         connect(action, &QAction::triggered, this, &KonqMainWindow::slotActivateTab);
3497     }
3498 
3499     m_paMoveTabLeft = actionCollection()->addAction(QStringLiteral("tab_move_left"));
3500     m_paMoveTabLeft->setText(i18n("Move Tab Left"));
3501     m_paMoveTabLeft->setIcon(QIcon::fromTheme(QStringLiteral("arrow-left")));
3502     connect(m_paMoveTabLeft, &QAction::triggered, this, &KonqMainWindow::slotMoveTabLeft);
3503     actionCollection()->setDefaultShortcut(m_paMoveTabLeft, Qt::CTRL | Qt::SHIFT | Qt::Key_Left);
3504     m_paMoveTabRight = actionCollection()->addAction(QStringLiteral("tab_move_right"));
3505     m_paMoveTabRight->setText(i18n("Move Tab Right"));
3506     m_paMoveTabRight->setIcon(QIcon::fromTheme(QStringLiteral("arrow-right")));
3507     connect(m_paMoveTabRight, &QAction::triggered, this, &KonqMainWindow::slotMoveTabRight);
3508     actionCollection()->setDefaultShortcut(m_paMoveTabRight, Qt::CTRL | Qt::SHIFT | Qt::Key_Right);
3509 
3510 #ifndef NDEBUG
3511     action = actionCollection()->addAction(QStringLiteral("dumpdebuginfo"));
3512     action->setIcon(QIcon::fromTheme(QStringLiteral("view-dump-debug-info")));
3513     action->setText(i18n("Dump Debug Info"));
3514     connect(action, &QAction::triggered, this, &KonqMainWindow::slotDumpDebugInfo);
3515 #endif
3516 
3517     m_ptaFullScreen = KStandardAction::fullScreen(nullptr, nullptr, this, this);
3518     actionCollection()->addAction(m_ptaFullScreen->objectName(), m_ptaFullScreen);
3519     QList<QKeySequence> fullScreenShortcut = m_ptaFullScreen->shortcuts();
3520     fullScreenShortcut.append(Qt::Key_F11);
3521     actionCollection()->setDefaultShortcuts(m_ptaFullScreen, fullScreenShortcut);
3522     connect(m_ptaFullScreen, &KToggleFullScreenAction::toggled, this, &KonqMainWindow::slotUpdateFullScreen);
3523 
3524     QList<QKeySequence> reloadShortcut = KStandardShortcut::shortcut(KStandardShortcut::Reload);
3525     QKeySequence reloadAlternate(Qt::CTRL | Qt::Key_R);
3526     if (!reloadShortcut.contains(reloadAlternate)) {
3527         reloadShortcut.append(reloadAlternate);
3528     }
3529     m_paReload = actionCollection()->addAction(QStringLiteral("reload"));
3530     m_paReload->setIcon(QIcon::fromTheme(QStringLiteral("view-refresh")));
3531     m_paReload->setText(i18n("&Reload"));
3532     connect(m_paReload, SIGNAL(triggered()), SLOT(slotReload()));
3533     actionCollection()->setDefaultShortcuts(m_paReload, reloadShortcut);
3534     m_paReloadAllTabs = actionCollection()->addAction(QStringLiteral("reload_all_tabs"));
3535     m_paReloadAllTabs->setIcon(QIcon::fromTheme(QStringLiteral("view-refresh-all")));
3536     m_paReloadAllTabs->setText(i18n("&Reload All Tabs"));
3537     connect(m_paReloadAllTabs, &QAction::triggered, this, &KonqMainWindow::slotReloadAllTabs);
3538     actionCollection()->setDefaultShortcut(m_paReloadAllTabs, Qt::SHIFT | Qt::Key_F5);
3539     // "Forced"/ "Hard" reload action - re-downloads all e.g. images even if a cached
3540     // version already exists.
3541     m_paForceReload = actionCollection()->addAction(QStringLiteral("hard_reload"));
3542     // TODO - request new icon? (view-refresh will do for the time being)
3543     m_paForceReload->setIcon(QIcon::fromTheme(QStringLiteral("view-refresh")));
3544     m_paForceReload->setText(i18n("&Force Reload"));
3545     connect(m_paForceReload, &QAction::triggered, this, &KonqMainWindow::slotForceReload);
3546     QList<QKeySequence> forceReloadShortcuts;
3547     forceReloadShortcuts.append(QKeySequence(Qt::CTRL | Qt::Key_F5));
3548     forceReloadShortcuts.append(QKeySequence(Qt::CTRL | Qt::SHIFT | Qt::Key_R));
3549     actionCollection()->setDefaultShortcuts(m_paForceReload, forceReloadShortcuts);
3550 
3551     m_paUndo = KStandardAction::undo(m_pUndoManager, SLOT(undo()), this);
3552     actionCollection()->addAction(QStringLiteral("undo"), m_paUndo);
3553     connect(m_pUndoManager, SIGNAL(undoTextChanged(QString)),
3554             this, SLOT(slotUndoTextChanged(QString)));
3555 
3556     // Those are connected to the browserextension directly
3557     m_paCut = KStandardAction::cut(nullptr, nullptr, this);
3558     actionCollection()->addAction(QStringLiteral("cut"), m_paCut);
3559 
3560     QList<QKeySequence> cutShortcuts(m_paCut->shortcuts());
3561     cutShortcuts.removeAll(QKeySequence(Qt::SHIFT | Qt::Key_Delete)); // used for deleting files
3562     actionCollection()->setDefaultShortcuts(m_paCut, cutShortcuts);
3563 
3564     m_paCopy = KStandardAction::copy(nullptr, nullptr, this);
3565     actionCollection()->addAction(QStringLiteral("copy"), m_paCopy);
3566     m_paPaste = KStandardAction::paste(nullptr, nullptr, this);
3567     actionCollection()->addAction(QStringLiteral("paste"), m_paPaste);
3568     m_paStop = actionCollection()->addAction(QStringLiteral("stop"));
3569     m_paStop->setIcon(QIcon::fromTheme(QStringLiteral("process-stop")));
3570     m_paStop->setText(i18n("&Stop"));
3571     connect(m_paStop, &QAction::triggered, this, &KonqMainWindow::slotStop);
3572     actionCollection()->setDefaultShortcut(m_paStop, Qt::Key_Escape);
3573 
3574     m_paAnimatedLogo = new KonqAnimatedLogo;
3575     QWidgetAction *logoAction = new QWidgetAction(this);
3576     actionCollection()->addAction(QStringLiteral("konq_logo"), logoAction);
3577     logoAction->setDefaultWidget(m_paAnimatedLogo);
3578     // Set icon and text so that it's easier to figure out what the action is in the toolbar editor
3579     logoAction->setText(i18n("Throbber"));
3580     logoAction->setIcon(QIcon::fromTheme(QStringLiteral("kde")));
3581 
3582     // Location bar
3583     m_locationLabel = new KonqDraggableLabel(this, i18n("L&ocation: "));
3584     QWidgetAction *locationAction = new QWidgetAction(this);
3585     actionCollection()->addAction(QStringLiteral("location_label"), locationAction);
3586     locationAction->setText(i18n("L&ocation: "));
3587     connect(locationAction, &QWidgetAction::triggered, this, &KonqMainWindow::slotLocationLabelActivated);
3588     locationAction->setDefaultWidget(m_locationLabel);
3589     m_locationLabel->setBuddy(m_combo);
3590 
3591     QWidgetAction *comboAction = new QWidgetAction(this);
3592     actionCollection()->addAction(QStringLiteral("toolbar_url_combo"), comboAction);
3593     comboAction->setText(i18n("Location Bar"));
3594     actionCollection()->setDefaultShortcut(comboAction, Qt::Key_F6);
3595     connect(comboAction, &QWidgetAction::triggered, this, &KonqMainWindow::slotLocationLabelActivated);
3596     comboAction->setDefaultWidget(m_combo);
3597     actionCollection()->setShortcutsConfigurable(comboAction, false);
3598 
3599     m_combo->setWhatsThis(i18n("<html>Location Bar<br /><br />Enter a web address or search term.</html>"));
3600 
3601     QAction *clearLocation = actionCollection()->addAction(QStringLiteral("clear_location"));
3602     clearLocation->setIcon(QIcon::fromTheme(QApplication::isRightToLeft() ? "edit-clear-locationbar-rtl" : "edit-clear-locationbar-ltr"));
3603     clearLocation->setText(i18n("Clear Location Bar"));
3604     actionCollection()->setDefaultShortcut(clearLocation, Qt::CTRL | Qt::Key_L);
3605     connect(clearLocation, SIGNAL(triggered()),
3606             SLOT(slotClearLocationBar()));
3607     clearLocation->setWhatsThis(i18n("<html>Clear Location bar<br /><br />"
3608                                      "Clears the contents of the location bar.</html>"));
3609 
3610     // Bookmarks menu
3611     m_pamBookmarks = new KBookmarkActionMenu(s_bookmarkManager->root(),
3612             i18n("&Bookmarks"), this);
3613     actionCollection()->addAction(QStringLiteral("bookmarks"), m_pamBookmarks);
3614     m_pamBookmarks->setPopupMode(QToolButton::InstantPopup);
3615 
3616     // The actual menu needs a different action collection, so that the bookmarks
3617     // don't appear in kedittoolbar
3618     m_bookmarksActionCollection = new KActionCollection(static_cast<QWidget *>(this));
3619 
3620     m_pBookmarkMenu = new Konqueror::KonqBookmarkMenu(s_bookmarkManager, m_pBookmarksOwner, m_pamBookmarks, m_bookmarksActionCollection);
3621 
3622     QAction *addBookmark = m_bookmarksActionCollection->action(QStringLiteral("add_bookmark"));
3623     if (addBookmark) {
3624         // Keep the "Add bookmark" action visible though (#153835)
3625         // -> We should think of a way to mark actions as "not configurable in toolbars" and
3626         // "should not appear in shortcut dialog (!= isShortcutConfigurable)" instead, and use
3627         // a single actionCollection.
3628         actionCollection()->addAction(QStringLiteral("add_bookmark"), m_bookmarksActionCollection->takeAction(addBookmark));
3629     } else {
3630         qCDebug(KONQUEROR_LOG) << "Action add_bookmark not found!";
3631     }
3632 
3633     m_paShowMenuBar = KStandardAction::showMenubar(this, SLOT(slotShowMenuBar()), this);
3634     actionCollection()->addAction(KStandardAction::name(KStandardAction::ShowMenubar), m_paShowMenuBar);
3635 
3636     m_paShowStatusBar = KStandardAction::showStatusbar(this, SLOT(slotShowStatusBar()), this);
3637     actionCollection()->addAction(KStandardAction::name(KStandardAction::ShowStatusbar), m_paShowStatusBar);
3638 
3639     action = actionCollection()->addAction(QStringLiteral("konqintro"));
3640     action->setText(i18n("Kon&queror Introduction"));
3641     connect(action, &QAction::triggered, this, &KonqMainWindow::slotIntro);
3642 
3643     QAction *goUrl = actionCollection()->addAction(QStringLiteral("go_url"));
3644     goUrl->setIcon(QIcon::fromTheme(QStringLiteral("go-jump-locationbar")));
3645     goUrl->setText(i18n("Go"));
3646     connect(goUrl, &QAction::triggered, this, &KonqMainWindow::goURL);
3647     goUrl->setWhatsThis(i18n("<html>Go<br /><br />"
3648                              "Goes to the page that has been entered into the location bar.</html>"));
3649 
3650     KStandardAction::switchApplicationLanguage(nullptr, nullptr, this);
3651 
3652     enableAllActions(false);
3653 
3654     // help stuff
3655     m_paUp->setWhatsThis(i18n("<html>Enter the parent folder<br /><br />"
3656                               "For instance, if the current location is file:/home/%1 clicking this "
3657                               "button will take you to file:/home.</html>",  KUser().loginName()));
3658     m_paUp->setStatusTip(i18n("Enter the parent folder"));
3659 
3660     m_paBack->setWhatsThis(i18n("Move backwards one step in the browsing history"));
3661     m_paBack->setStatusTip(i18n("Move backwards one step in the browsing history"));
3662 
3663     m_paForward->setWhatsThis(i18n("Move forward one step in the browsing history"));
3664     m_paForward->setStatusTip(i18n("Move forward one step in the browsing history"));
3665 
3666     m_paClosedItems->setWhatsThis(i18n("Move backwards one step in the closed tabs history"));
3667     m_paClosedItems->setStatusTip(i18n("Move backwards one step in the closed tabs history"));
3668 
3669     m_paReload->setWhatsThis(i18n("<html>Reload the currently displayed document<br /><br />"
3670                                   "This may, for example, be needed to refresh web pages that have been "
3671                                   "modified since they were loaded, in order to make the changes visible.</html>"));
3672     m_paReload->setStatusTip(i18n("Reload the currently displayed document"));
3673 
3674     m_paReloadAllTabs->setWhatsThis(i18n("<html>Reload all currently displayed documents in tabs<br /><br />"
3675                                          "This may, for example, be needed to refresh web pages that have been "
3676                                          "modified since they were loaded, in order to make the changes visible.</html>"));
3677     m_paReloadAllTabs->setStatusTip(i18n("Reload all currently displayed document in tabs"));
3678 
3679     m_paStop->setWhatsThis(i18n("<html>Stop loading the document<br /><br />"
3680                                 "All network transfers will be stopped and Konqueror will display the content "
3681                                 "that has been received so far.</html>"));
3682 
3683     m_paForceReload->setWhatsThis(i18n("<html>Reload the currently displayed document<br /><br />"
3684                                        "This may, for example, be needed to refresh web pages that have been "
3685                                        "modified since they were loaded, in order to make the changes visible. Any images on the page are downloaded again, even if cached copies exist.</html>"));
3686 
3687     m_paForceReload->setStatusTip(i18n("Force a reload of the currently displayed document and any contained images"));
3688 
3689     m_paStop->setStatusTip(i18n("Stop loading the document"));
3690 
3691     m_paCut->setWhatsThis(i18n("<html>Cut the currently selected text or item(s) and move it "
3692                                "to the system clipboard<br /><br />"
3693                                "This makes it available to the <b>Paste</b> command in Konqueror "
3694                                "and other KDE applications.</html>"));
3695     m_paCut->setStatusTip(i18n("Move the selected text or item(s) to the clipboard"));
3696 
3697     m_paCopy->setWhatsThis(i18n("<html>Copy the currently selected text or item(s) to the "
3698                                 "system clipboard<br /><br />"
3699                                 "This makes it available to the <b>Paste</b> command in Konqueror "
3700                                 "and other KDE applications.</html>"));
3701     m_paCopy->setStatusTip(i18n("Copy the selected text or item(s) to the clipboard"));
3702 
3703     m_paPaste->setWhatsThis(i18n("<html>Paste the previously cut or copied clipboard "
3704                                  "contents<br /><br />"
3705                                  "This also works for text copied or cut from other KDE applications.</html>"));
3706     m_paPaste->setStatusTip(i18n("Paste the clipboard contents"));
3707 
3708     m_paPrint->setWhatsThis(i18n("<html>Print the currently displayed document<br /><br />"
3709                                  "You will be presented with a dialog where you can set various "
3710                                  "options, such as the number of copies to print and which printer "
3711                                  "to use.<br /><br />"
3712                                  "This dialog also provides access to special KDE printing "
3713                                  "services such as creating a PDF file from the current document.</html>"));
3714     m_paPrint->setStatusTip(i18n("Print the current document"));
3715 
3716     m_paLockView->setStatusTip(i18n("A locked view cannot change folders. Use in combination with 'link view' to explore many files from one folder"));
3717     m_paLinkView->setStatusTip(i18n("Sets the view as 'linked'. A linked view follows folder changes made in other linked views."));
3718 
3719     m_paShowDeveloperTools = actionCollection()->addAction("inspect_page", this, &KonqMainWindow::inspectCurrentPage);
3720     actionCollection()->setDefaultShortcut(m_paShowDeveloperTools, QKeySequence("Ctrl | Shift | I"));
3721     m_paShowDeveloperTools->setText(i18n("&Inspect Current Page"));
3722     m_paShowDeveloperTools->setWhatsThis(i18n("<html>Shows the developer tools for the current page<br/><br/>The current view is split in two and the developer tools are displayed in the second half"));
3723     m_paShowDeveloperTools->setStatusTip(i18n("Shows the developer tools for the current page"));
3724 }
3725 
3726 void KonqExtendedBookmarkOwner::openBookmark(const KBookmark &bm, Qt::MouseButtons mb, Qt::KeyboardModifiers km)
3727 {
3728     qCDebug(KONQUEROR_LOG) << bm.url() << km << mb;
3729 
3730     const QString url = bm.url().url();
3731 
3732     KonqOpenURLRequest req;
3733     req.browserArgs.setNewTab(true);
3734     req.newTabInFront = KonqSettings::newTabsInFront();
3735     req.forceAutoEmbed = true;
3736 
3737     if (km & Qt::ShiftModifier) {
3738         req.newTabInFront = !req.newTabInFront;
3739     }
3740 
3741     if (km & Qt::ControlModifier) {  // Ctrl Left/MMB
3742         m_pKonqMainWindow->openFilteredUrl(url, req);
3743     } else if (mb & Qt::MiddleButton) {
3744         if (KonqSettings::mmbOpensTab()) {
3745             m_pKonqMainWindow->openFilteredUrl(url, req);
3746         } else {
3747             const QUrl finalURL = KonqMisc::konqFilteredURL(m_pKonqMainWindow, url);
3748             KonqMainWindow *mw = KonqMainWindowFactory::createNewWindow(finalURL);
3749             mw->show();
3750         }
3751     } else {
3752         m_pKonqMainWindow->openFilteredUrl(url, false);
3753     }
3754 }
3755 
3756 void KonqMainWindow::slotMoveTabLeft()
3757 {
3758     if (QApplication::isRightToLeft()) {
3759         m_pViewManager->moveTabForward();
3760     } else {
3761         m_pViewManager->moveTabBackward();
3762     }
3763 
3764     updateViewActions();
3765 }
3766 
3767 void KonqMainWindow::slotMoveTabRight()
3768 {
3769     if (QApplication::isRightToLeft()) {
3770         m_pViewManager->moveTabBackward();
3771     } else {
3772         m_pViewManager->moveTabForward();
3773     }
3774 
3775     updateViewActions();
3776 }
3777 
3778 void KonqMainWindow::updateHistoryActions()
3779 {
3780     if (m_currentView) {
3781         m_paBack->setEnabled(m_currentView->canGoBack());
3782         m_paForward->setEnabled(m_currentView->canGoForward());
3783     }
3784 }
3785 
3786 bool KonqMainWindow::isPreloaded() const
3787 {
3788     return !isVisible() && m_mapViews.count() == 1 && m_currentView && KonqUrl::isKonqBlank(m_currentView->url().toString());
3789 }
3790 
3791 void KonqMainWindow::updateToolBarActions(bool pendingAction /*=false*/)
3792 {
3793     if (!m_currentView) {
3794         return;
3795     }
3796 
3797     // Enables/disables actions that depend on the current view & url (mostly toolbar)
3798     // Up, back, forward, the edit extension, stop button, wheel
3799     setUpEnabled(m_currentView->url());
3800     m_paBack->setEnabled(m_currentView->canGoBack());
3801     m_paForward->setEnabled(m_currentView->canGoForward());
3802 
3803     if (m_currentView->isLoading()) {
3804         startAnimation(); // takes care of m_paStop
3805     } else {
3806         m_paAnimatedLogo->stop();
3807         m_paStop->setEnabled(pendingAction);    //enable/disable based on any pending actions...
3808     }
3809 }
3810 
3811 void KonqMainWindow::updateViewActions()
3812 {
3813     // Update actions that depend on the current view and its mode, or on the number of views etc.
3814 
3815     // Don't do things in this method that depend on m_currentView->url().
3816     // When going 'back' in history this will be called before opening the url.
3817     // Use updateToolBarActions instead.
3818 
3819     bool enable = false;
3820 
3821     if (m_currentView && m_currentView->part()) {
3822         // Avoid qWarning from QObject::property if it doesn't exist
3823         if (m_currentView->part()->metaObject()->indexOfProperty("supportsUndo") != -1) {
3824             QVariant prop = m_currentView->part()->property("supportsUndo");
3825             if (prop.isValid() && prop.toBool()) {
3826                 enable = true;
3827             }
3828         }
3829     }
3830 
3831     m_pUndoManager->updateSupportsFileUndo(enable);
3832 
3833 //   slotUndoAvailable( m_pUndoManager->undoAvailable() );
3834 
3835     m_paLockView->setEnabled(true);
3836     m_paLockView->setChecked(m_currentView && m_currentView->isLockedLocation());
3837 
3838     // Can remove view if we'll still have a main view after that
3839     m_paRemoveView->setEnabled(mainViewsCount() > 1 ||
3840                                (m_currentView && m_currentView->isToggleView()));
3841 
3842     if (!currentView() || !currentView()->frame()) {
3843         m_paAddTab->setEnabled(false);
3844         m_paDuplicateTab->setEnabled(false);
3845         m_paRemoveOtherTabs->setEnabled(false);
3846         m_paBreakOffTab->setEnabled(false);
3847         m_paActivateNextTab->setEnabled(false);
3848         m_paActivatePrevTab->setEnabled(false);
3849         m_paMoveTabLeft->setEnabled(false);
3850         m_paMoveTabRight->setEnabled(false);
3851     } else {
3852         m_paAddTab->setEnabled(true);
3853         m_paDuplicateTab->setEnabled(true);
3854         KonqFrameTabs *tabContainer = m_pViewManager->tabContainer();
3855         bool state = (tabContainer->count() > 1);
3856         m_paRemoveOtherTabs->setEnabled(state);
3857         m_paBreakOffTab->setEnabled(state);
3858         m_paActivateNextTab->setEnabled(state);
3859         m_paActivatePrevTab->setEnabled(state);
3860 
3861         QList<KonqFrameBase *> childFrameList = tabContainer->childFrameList();
3862         Q_ASSERT(!childFrameList.isEmpty());
3863         m_paMoveTabLeft->setEnabled(currentView() ? currentView()->frame() !=
3864                                     (QApplication::isRightToLeft() ? childFrameList.last() : childFrameList.first()) : false);
3865         m_paMoveTabRight->setEnabled(currentView() ? currentView()->frame() !=
3866                                      (QApplication::isRightToLeft() ? childFrameList.first() : childFrameList.last()) : false);
3867     }
3868 
3869     // Can split a view if it's not a toggle view (because a toggle view can be here only once)
3870     bool isNotToggle = m_currentView && !m_currentView->isToggleView();
3871     m_paSplitViewHor->setEnabled(isNotToggle);
3872     m_paSplitViewVer->setEnabled(isNotToggle);
3873 
3874     m_paLinkView->setChecked(m_currentView && m_currentView->isLinkedView());
3875 
3876 #if 0
3877     if (m_currentView && m_currentView->part() &&
3878             ::qobject_cast<KonqDirPart *>(m_currentView->part())) {
3879         KonqDirPart *dirPart = static_cast<KonqDirPart *>(m_currentView->part());
3880         m_paFindFiles->setEnabled(dirPart->findPart() == 0);
3881 
3882         // Create the copy/move options if not already done
3883         // TODO: move that stuff to dolphin(part)
3884         if (!m_paCopyFiles) {
3885             // F5 is the default key binding for Reload.... a la Windows.
3886             // mc users want F5 for Copy and F6 for move, but I can't make that default.
3887 
3888             m_paCopyFiles = actionCollection()->addAction("copyfiles");
3889             m_paCopyFiles->setText(i18n("Copy &Files..."));
3890             connect(m_paCopyFiles, &QAction::triggered, this, &KonqMainWindow::slotCopyFiles);
3891             m_paCopyFiles->setShortcut(Qt::Key_F7);
3892             m_paMoveFiles = actionCollection()->addAction("movefiles");
3893             m_paMoveFiles->setText(i18n("M&ove Files..."));
3894             connect(m_paMoveFiles, &QAction::triggered, this, &KonqMainWindow::slotMoveFiles);
3895             m_paMoveFiles->setShortcut(Qt::Key_F8);
3896 
3897             QList<QAction *> lst;
3898             lst.append(m_paCopyFiles);
3899             lst.append(m_paMoveFiles);
3900             m_paCopyFiles->setEnabled(false);
3901             m_paMoveFiles->setEnabled(false);
3902             plugActionList("operations", lst);
3903         }
3904     } else {
3905         m_paFindFiles->setEnabled(false);
3906 
3907         if (m_paCopyFiles) {
3908             unplugActionList("operations");
3909             delete m_paCopyFiles;
3910             m_paCopyFiles = 0;
3911             delete m_paMoveFiles;
3912             m_paMoveFiles = 0;
3913         }
3914     }
3915 #endif
3916 }
3917 
3918 QString KonqMainWindow::findIndexFile(const QString &dir)
3919 {
3920     QDir d(dir);
3921 
3922     QString f = d.filePath(QStringLiteral("index.html"));
3923     if (QFile::exists(f)) {
3924         return f;
3925     }
3926 
3927     f = d.filePath(QStringLiteral("index.htm"));
3928     if (QFile::exists(f)) {
3929         return f;
3930     }
3931 
3932     f = d.filePath(QStringLiteral("index.HTML"));
3933     if (QFile::exists(f)) {
3934         return f;
3935     }
3936 
3937     return QString();
3938 }
3939 
3940 void KonqMainWindow::connectExtension(KParts::NavigationExtension *ext)
3941 {
3942 #if QT_VERSION_MAJOR < 6
3943     KParts::NavigationExtension::ActionSlotMap *actionSlotMap = KParts::NavigationExtension::actionSlotMapPtr();
3944 #else
3945     KParts::NavigationExtension::ActionSlotMap *actionSlotMap = KParts::NavigationExtension::actionSlotMap();
3946 #endif
3947     KParts::NavigationExtension::ActionSlotMap::ConstIterator it = actionSlotMap->constBegin();
3948     KParts::NavigationExtension::ActionSlotMap::ConstIterator itEnd = actionSlotMap->constEnd();
3949 
3950     for (; it != itEnd; ++it) {
3951         QAction *act = actionCollection()->action(it.key().data());
3952         //qCDebug(KONQUEROR_LOG) << it.key();
3953         if (act) {
3954             // Does the extension have a slot with the name of this action ?
3955             if (ext->metaObject()->indexOfSlot(QByteArray(it.key() + "()").constData()) != -1) {
3956                 //Can't use modern connect syntax as the slot name is stored inside the map
3957 #if QT_VERSION_MAJOR < 6
3958                 connect(act, SIGNAL(triggered()), ext, it.value().constData() /* SLOT(slot name) */);
3959 #else
3960                 connect(act, SIGNAL(triggered()), ext, it.value().constData() /* SLOT(slot name) */);
3961 #endif
3962                 act->setEnabled(ext->isActionEnabled(it.key().constData()));
3963                 const QString text = ext->actionText(it.key().constData());
3964                 if (!text.isEmpty()) {
3965                     act->setText(text);
3966                 }
3967                 // TODO how to re-set the original action text, when switching to a part that didn't call setAction?
3968                 // Can't test with Paste...
3969             } else {
3970                 act->setEnabled(false);
3971             }
3972 
3973         } else {
3974             qCWarning(KONQUEROR_LOG) << "Error in NavigationExtension::actionSlotMap(), unknown action : " << it.key();
3975         }
3976     }
3977 
3978 }
3979 
3980 void KonqMainWindow::disconnectExtension(KParts::NavigationExtension *ext)
3981 {
3982 #if QT_VERSION_MAJOR < 6
3983     KParts::NavigationExtension::ActionSlotMap *actionSlotMap = KParts::NavigationExtension::actionSlotMapPtr();
3984 #else
3985     KParts::NavigationExtension::ActionSlotMap *actionSlotMap = KParts::NavigationExtension::actionSlotMap();
3986 #endif
3987     KParts::NavigationExtension::ActionSlotMap::ConstIterator it = actionSlotMap->constBegin();
3988     KParts::NavigationExtension::ActionSlotMap::ConstIterator itEnd = actionSlotMap->constEnd();
3989 
3990     for (; it != itEnd; ++it) {
3991         QAction *act = actionCollection()->action(it.key().data());
3992         //qCDebug(KONQUEROR_LOG) << it.key();
3993         if (act && ext->metaObject()->indexOfSlot(QByteArray(it.key() + "()").constData()) != -1) {
3994             //qCDebug(KONQUEROR_LOG) << act << act->name();
3995             act->disconnect(ext);
3996         }
3997     }
3998 }
3999 
4000 void KonqMainWindow::enableAction(const char *name, bool enabled)
4001 {
4002     QAction *act = actionCollection()->action(name);
4003     if (!act) {
4004         qCWarning(KONQUEROR_LOG) << "Unknown action " << name << " - can't enable";
4005     } else {
4006         if (m_bLocationBarConnected && (
4007                     act == m_paCopy || act == m_paCut || act == m_paPaste))
4008             // Don't change action state while the location bar has focus.
4009         {
4010             return;
4011         }
4012         //qCDebug(KONQUEROR_LOG) << name << enabled;
4013         act->setEnabled(enabled);
4014     }
4015 
4016     // Update "copy files" and "move files" accordingly
4017     if (m_paCopyFiles && !strcmp(name, "copy")) {
4018         m_paCopyFiles->setEnabled(enabled);
4019     } else if (m_paMoveFiles && !strcmp(name, "cut")) {
4020         m_paMoveFiles->setEnabled(enabled);
4021     }
4022 }
4023 
4024 void KonqMainWindow::setActionText(const char *name, const QString &text)
4025 {
4026     QAction *act = actionCollection()->action(name);
4027     if (!act) {
4028         qCWarning(KONQUEROR_LOG) << "Unknown action " << name << "- can't enable";
4029     } else {
4030         //qCDebug(KONQUEROR_LOG) << name << " text=" << text;
4031         act->setText(text);
4032     }
4033 }
4034 
4035 void KonqMainWindow::enableAllActions(bool enable)
4036 {
4037     //qCDebug(KONQUEROR_LOG) << enable;
4038 #if QT_VERSION_MAJOR < 6
4039     KParts::NavigationExtension::ActionSlotMap *actionSlotMap = KParts::NavigationExtension::actionSlotMapPtr();
4040 #else
4041     KParts::NavigationExtension::ActionSlotMap *actionSlotMap = KParts::NavigationExtension::actionSlotMap();
4042 #endif
4043 
4044     const QList<QAction *> actions = actionCollection()->actions();
4045     QList<QAction *>::ConstIterator it = actions.constBegin();
4046     QList<QAction *>::ConstIterator end = actions.constEnd();
4047     for (; it != end; ++it) {
4048         QAction *act = *it;
4049         if (!act->objectName().startsWith(QLatin1String("options_configure"))  /* do not touch the configureblah actions */
4050                 && (!enable || !actionSlotMap->contains(act->objectName().toLatin1()))) {    /* don't enable BE actions */
4051             act->setEnabled(enable);
4052         }
4053     }
4054     // This method is called with enable=false on startup, and
4055     // then only once with enable=true when the first view is setup.
4056     // So the code below is where actions that should initially be disabled are disabled.
4057     if (enable) {
4058         setUpEnabled(m_currentView ? m_currentView->url() : QUrl());
4059         // we surely don't have any history buffers at this time
4060         m_paBack->setEnabled(false);
4061         m_paForward->setEnabled(false);
4062 
4063         updateViewActions(); // undo, lock, link and other view-dependent actions
4064         updateClosedItemsAction();
4065 
4066         m_paStop->setEnabled(m_currentView && m_currentView->isLoading());
4067 
4068         if (m_toggleViewGUIClient) {
4069             QList<QAction *> actions = m_toggleViewGUIClient->actions();
4070             for (int i = 0; i < actions.size(); ++i) {
4071                 actions.at(i)->setEnabled(true);
4072             }
4073         }
4074 
4075     }
4076     actionCollection()->action(QStringLiteral("quit"))->setEnabled(true);
4077     actionCollection()->action(QStringLiteral("link"))->setEnabled(false);
4078 }
4079 
4080 void KonqMainWindow::disableActionsNoView()
4081 {
4082     // No view -> there are some things we can't do
4083     m_paUp->setEnabled(false);
4084     m_paReload->setEnabled(false);
4085     m_paReloadAllTabs->setEnabled(false);
4086     m_paBack->setEnabled(false);
4087     m_paForward->setEnabled(false);
4088     m_paLockView->setEnabled(false);
4089     m_paLockView->setChecked(false);
4090     m_paSplitViewVer->setEnabled(false);
4091     m_paSplitViewHor->setEnabled(false);
4092     m_paRemoveView->setEnabled(false);
4093     m_paLinkView->setEnabled(false);
4094     if (m_toggleViewGUIClient) {
4095         QList<QAction *> actions = m_toggleViewGUIClient->actions();
4096         for (int i = 0; i < actions.size(); ++i) {
4097             actions.at(i)->setEnabled(false);
4098         }
4099     }
4100     // There are things we can do, though : bookmarks, view profile, location bar, new window,
4101     // settings, etc.
4102     static const char *const s_enActions[] = { "new_window", "duplicate_window", "open_location",
4103                                                "toolbar_url_combo", "clear_location", "animated_logo",
4104                                                "konqintro", "go_most_often", "go_applications",
4105                                                "go_trash", "go_settings", "go_network_folders", "go_autostart",
4106                                                "go_url", "go_media", "go_history", "options_configure_extensions", nullptr
4107                                              };
4108     for (int i = 0; s_enActions[i]; ++i) {
4109         QAction *act = action(s_enActions[i]);
4110         if (act) {
4111             act->setEnabled(true);
4112         }
4113     }
4114     m_combo->clearTemporary();
4115 }
4116 
4117 void KonqMainWindow::setCaption(const QString &caption)
4118 {
4119     // KParts sends us empty captions when activating a brand new part
4120     // We can't change it there (in case of apps removing all parts altogether)
4121     // but here we never do that.
4122     if (!caption.isEmpty() && m_currentView) {
4123         //qCDebug(KONQUEROR_LOG) << caption;
4124 
4125         // Keep an unmodified copy of the caption (before squeezing and KComponentData::makeStdCaption are applied)
4126         m_currentView->setCaption(caption);
4127         KParts::MainWindow::setCaption(KStringHandler::csqueeze(m_currentView->caption(), 128));
4128     }
4129 }
4130 
4131 void KonqMainWindow::showEvent(QShowEvent *event)
4132 {
4133     //qCDebug(KONQUEROR_LOG) << QTime::currentTime();
4134     // We need to check if our toolbars are shown/hidden here, and set
4135     // our menu items accordingly. We can't do it in the constructor because
4136     // view profiles store toolbar info, and that info is read after
4137     // construct time.
4138     m_paShowMenuBar->setChecked(!menuBar()->isHidden());
4139     if (m_currentView) {
4140         m_paShowStatusBar->setChecked(m_currentView->frame()->statusbar()->isVisible());
4141     }
4142     updateBookmarkBar(); // hide if empty
4143 
4144     // Call parent method
4145     KParts::MainWindow::showEvent(event);
4146 }
4147 
4148 QUrl KonqExtendedBookmarkOwner::currentUrl() const
4149 {
4150     const KonqView *view = m_pKonqMainWindow->currentView();
4151     return view ? view->url() : QUrl();
4152 }
4153 
4154 QString KonqMainWindow::currentURL() const
4155 {
4156     if (!m_currentView) {
4157         return QString();
4158     }
4159 
4160 //TODO KF6: check whether requestedUrl or realUrl is more suitable here
4161     QString url = m_currentView->url().toDisplayString();
4162 
4163 #if 0 // do we want this?
4164     // Add the name filter (*.txt) at the end of the URL again
4165     if (m_currentView->part()) {
4166         const QString nameFilter = m_currentView->nameFilter();
4167         if (!nameFilter.isEmpty()) {
4168             if (!url.endsWith('/')) {
4169                 url += '/';
4170             }
4171             url += nameFilter;
4172         }
4173     }
4174 #endif
4175     return url;
4176 }
4177 
4178 bool KonqExtendedBookmarkOwner::supportsTabs() const
4179 {
4180     return true;
4181 }
4182 
4183 QList<KBookmarkOwner::FutureBookmark> KonqExtendedBookmarkOwner::currentBookmarkList() const
4184 {
4185     QList<KBookmarkOwner::FutureBookmark> list;
4186     KonqFrameTabs *tabContainer = m_pKonqMainWindow->viewManager()->tabContainer();
4187 
4188     for (KonqFrameBase *frame: tabContainer->childFrameList()) {
4189         if (!frame || !frame->activeChildView()) {
4190             continue;
4191         }
4192         KonqView *view = frame->activeChildView();
4193         if (view->locationBarURL().isEmpty()) {
4194             continue;
4195         }
4196         list << KBookmarkOwner::FutureBookmark(view->caption(), view->url(), KIO::iconNameForUrl(view->url()));
4197     }
4198     return list;
4199 }
4200 
4201 QString KonqExtendedBookmarkOwner::currentTitle() const
4202 {
4203     return m_pKonqMainWindow->currentTitle();
4204 }
4205 
4206 void KonqExtendedBookmarkOwner::openInNewTab(const KBookmark &bm)
4207 {
4208     bool newTabsInFront = KonqSettings::newTabsInFront();
4209     if (QApplication::keyboardModifiers() & Qt::ShiftModifier) {
4210         newTabsInFront = !newTabsInFront;
4211     }
4212 
4213     KonqOpenURLRequest req;
4214     req.browserArgs.setNewTab(true);
4215     req.newTabInFront = newTabsInFront;
4216     req.openAfterCurrentPage = false;
4217     req.forceAutoEmbed = true;
4218 
4219     m_pKonqMainWindow->openFilteredUrl(bm.url().url(), req);
4220 }
4221 
4222 void KonqExtendedBookmarkOwner::openFolderinTabs(const KBookmarkGroup &grp)
4223 {
4224     bool newTabsInFront = KonqSettings::newTabsInFront();
4225     if (QApplication::keyboardModifiers() & Qt::ShiftModifier) {
4226         newTabsInFront = !newTabsInFront;
4227     }
4228     KonqOpenURLRequest req;
4229     req.browserArgs.setNewTab(true);
4230     req.newTabInFront = false;
4231     req.openAfterCurrentPage = false;
4232     req.forceAutoEmbed = true;
4233 
4234     const QList<QUrl> list = grp.groupUrlList();
4235     if (list.isEmpty()) {
4236         return;
4237     }
4238 
4239     if (list.size() > 20) {
4240         if (KMessageBox::questionTwoActions(m_pKonqMainWindow,
4241                                        i18n("You have requested to open more than 20 bookmarks in tabs. "
4242                                             "This might take a while. Continue?"),
4243                                        i18nc("@title:window", "Open bookmarks folder in new tabs"),
4244                                        KGuiItem(i18nc("@action:button", "Open"), QStringLiteral("tab-new")),
4245                                        KStandardGuiItem::cancel()) != KMessageBox::PrimaryAction) {
4246             return;
4247         }
4248     }
4249 
4250     QList<QUrl>::ConstIterator it = list.constBegin();
4251     QList<QUrl>::ConstIterator end = list.constEnd();
4252     --end;
4253     for (; it != end; ++it) {
4254         m_pKonqMainWindow->openFilteredUrl((*it).toString(), req);
4255     }
4256     if (newTabsInFront) {
4257         req.newTabInFront = true;
4258     }
4259     m_pKonqMainWindow->openFilteredUrl((*end).toString(), req);
4260 }
4261 
4262 void KonqExtendedBookmarkOwner::openInNewWindow(const KBookmark &bm)
4263 {
4264     const QUrl finalURL(KonqMisc::konqFilteredURL(m_pKonqMainWindow, bm.url().url()));
4265     KonqMainWindow *mw = KonqMainWindowFactory::createNewWindow(finalURL);
4266     mw->show();
4267 }
4268 
4269 QString KonqMainWindow::currentTitle() const
4270 {
4271     return m_currentView ? m_currentView->caption() : QString();
4272 }
4273 
4274 // Convert between deprecated string-based KParts::NavigationExtension::ActionGroupMap
4275 // to newer enum-based KonqPopupMenu::ActionGroupMap
4276 static KonqPopupMenu::ActionGroupMap convertActionGroups(const KParts::NavigationExtension::ActionGroupMap &input)
4277 {
4278     KonqPopupMenu::ActionGroupMap agm;
4279     agm.insert(KonqPopupMenu::TopActions, input.value(QStringLiteral("topactions")));
4280     agm.insert(KonqPopupMenu::TabHandlingActions, input.value(QStringLiteral("tabhandling")));
4281     agm.insert(KonqPopupMenu::EditActions, input.value(QStringLiteral("editactions")));
4282     agm.insert(KonqPopupMenu::PreviewActions, input.value(QStringLiteral("preview")));
4283     agm.insert(KonqPopupMenu::CustomActions, input.value(QStringLiteral("partactions")));
4284     agm.insert(KonqPopupMenu::LinkActions, input.value(QStringLiteral("linkactions")));
4285     return agm;
4286 }
4287 
4288 void KonqMainWindow::slotPopupMenu(const QPoint &global, const QUrl &url, mode_t mode, const KParts::OpenUrlArguments &args, const BrowserArguments &browserArgs, KParts::NavigationExtension::PopupFlags flags, const KParts::NavigationExtension::ActionGroupMap &actionGroups
4289 #if QT_VERSION_MAJOR < 6
4290                      )
4291 #else
4292 , KonqView *currentView)
4293 #endif
4294 {
4295     KFileItem item(url, args.mimeType(), mode);
4296     KFileItemList items;
4297     items.append(item);
4298 #if QT_VERSION_MAJOR < 6
4299     slotPopupMenu(global, items, args, browserArgs, flags, actionGroups);
4300 #else
4301     slotPopupMenu(global, items, args, browserArgs, flags, actionGroups, currentView);
4302 #endif
4303 }
4304 
4305 void KonqMainWindow::slotPopupMenu(const QPoint &global, const KFileItemList &items, const KParts::OpenUrlArguments &args, const BrowserArguments &browserArgs, KParts::NavigationExtension::PopupFlags itemFlags, const KParts::NavigationExtension::ActionGroupMap &actionGroups
4306 #if QT_VERSION_MAJOR < 6
4307                      )
4308 #else
4309 , KonqView *currentView)
4310 #endif
4311 {
4312     KonqView *m_oldView = m_currentView;
4313 #if QT_VERSION_MAJOR < 6
4314     KonqView *currentView = childView(static_cast<KParts::ReadOnlyPart *>(sender()->parent()));
4315 #endif
4316 
4317     //qCDebug(KONQUEROR_LOG) << "m_oldView=" << m_oldView << "new currentView=" << currentView << "passive:" << currentView->isPassiveMode();
4318 
4319     if ((m_oldView != currentView) && currentView->isPassiveMode()) {
4320         // Make this view active only temporarily (because it's passive)
4321         m_currentView = currentView;
4322 
4323         if (m_oldView && m_oldView->browserExtension()) {
4324             disconnectExtension(m_oldView->browserExtension());
4325         }
4326         if (m_currentView->browserExtension()) {
4327             connectExtension(m_currentView->browserExtension());
4328         }
4329     }
4330     // Note that if m_oldView!=currentView and currentView isn't passive,
4331     // then the KParts mechanism has already noticed the click in it,
4332     // but KonqViewManager delays the GUI-rebuilding with a single-shot timer.
4333     // Right after the popup shows up, currentView _will_ be m_currentView.
4334 
4335     //qCDebug(KONQUEROR_LOG) << "current view=" << m_currentView << m_currentView->part()->metaObject()->className();
4336 
4337     // This action collection is used to pass actions to KonqPopupMenu.
4338     // It has to be a KActionCollection instead of a QList<QAction *> because we need
4339     // the actionStatusText signal...
4340     KActionCollection popupMenuCollection(static_cast<QWidget *>(nullptr));
4341 
4342     popupMenuCollection.addAction(QStringLiteral("closeditems"), m_paClosedItems);
4343 
4344 #if 0
4345     popupMenuCollection.addAction("find", m_paFindFiles);
4346 #endif
4347 
4348     popupMenuCollection.addAction(QStringLiteral("undo"), m_paUndo);
4349     popupMenuCollection.addAction(QStringLiteral("cut"), m_paCut);
4350     popupMenuCollection.addAction(QStringLiteral("copy"), m_paCopy);
4351     popupMenuCollection.addAction(QStringLiteral("paste"), m_paPaste);
4352 
4353     // The pasteto action is used when clicking on a dir, to paste into it.
4354     QAction *actPaste = KStandardAction::paste(this, SLOT(slotPopupPasteTo()), this);
4355     actPaste->setEnabled(m_paPaste->isEnabled());
4356     popupMenuCollection.addAction(QStringLiteral("pasteto"), actPaste);
4357 
4358     prepareForPopupMenu(items, args, browserArgs);
4359 
4360     bool sReading = false;
4361     if (!m_popupUrl.isEmpty()) {
4362         sReading = KProtocolManager::supportsReading(m_popupUrl);
4363     }
4364 
4365     QUrl viewURL = currentView->url();
4366     qCDebug(KONQUEROR_LOG) << "viewURL=" << viewURL;
4367 
4368     bool openedForViewURL = false;
4369     //bool dirsSelected = false;
4370     bool devicesFile = false;
4371 
4372     if (items.count() == 1) {
4373         const QUrl firstURL = items.first().url();
4374         if (!viewURL.isEmpty()) {
4375             //firstURL.cleanPath();
4376             openedForViewURL = firstURL.matches(viewURL, QUrl::StripTrailingSlash);
4377         }
4378         devicesFile = firstURL.scheme().indexOf(QLatin1String("device"), 0, Qt::CaseInsensitive) == 0;
4379         //dirsSelected = S_ISDIR( items.first()->mode() );
4380     }
4381     //qCDebug(KONQUEROR_LOG) << "viewURL=" << viewURL;
4382 
4383     QUrl url = viewURL;
4384     bool isIntoTrash = url.scheme() == QLatin1String("trash") || url.url().startsWith(QLatin1String("system:/trash"));
4385     const bool doTabHandling = !openedForViewURL && !isIntoTrash && sReading;
4386     const bool showEmbeddingServices = items.count() == 1 && !m_popupMimeType.isEmpty() &&
4387                                        !isIntoTrash && !devicesFile &&
4388                                        (itemFlags & KParts::NavigationExtension::ShowTextSelectionItems) == 0;
4389 
4390     QVector<KPluginMetaData> embeddingServices;
4391     if (showEmbeddingServices) {
4392         const QString currentServiceName = currentView->service().pluginId();
4393 
4394         // List of services for the "Preview In" submenu.
4395         QVector<KPluginMetaData> allEmbeddingServices = KParts::PartLoader::partsForMimeType(m_popupMimeType);
4396         auto filter = [currentServiceName](const KPluginMetaData &md) {
4397             return !md.value(QLatin1String("X-KDE-BrowserView-HideFromMenus"),false) && md.pluginId() != currentServiceName;
4398         };
4399         std::copy_if(allEmbeddingServices.begin(), allEmbeddingServices.end(), std::back_inserter(embeddingServices), filter);
4400     }
4401 
4402     // TODO: get rid of KParts::NavigationExtension::PopupFlags
4403     KonqPopupMenu::Flags popupFlags = static_cast<KonqPopupMenu::Flags>(static_cast<int>(itemFlags));
4404 
4405     KonqPopupMenu::ActionGroupMap popupActionGroups = convertActionGroups(actionGroups);
4406 
4407     PopupMenuGUIClient *konqyMenuClient = new PopupMenuGUIClient(embeddingServices,
4408             popupActionGroups,
4409             !menuBar()->isVisible() ? m_paShowMenuBar : nullptr,
4410             fullScreenMode() ? m_ptaFullScreen : nullptr
4411                                                                 );
4412     connect(konqyMenuClient, &PopupMenuGUIClient::openEmbedded, this, &KonqMainWindow::slotOpenEmbedded, Qt::QueuedConnection);
4413 
4414     // Those actions go into the PopupMenuGUIClient, since that's the one defining them.
4415     QList<QAction *> tabHandlingActions;
4416     if (doTabHandling) {
4417         if (browserArgs.forcesNewWindow()) {
4418             QAction *act = konqyMenuClient->actionCollection()->addAction(QStringLiteral("sameview"));
4419             act->setText(i18n("Open in T&his Window"));
4420             act->setStatusTip(i18n("Open the document in current window"));
4421             connect(act, &QAction::triggered, this, &KonqMainWindow::slotPopupThisWindow);
4422             tabHandlingActions.append(act);
4423         }
4424         QAction *actNewWindow = konqyMenuClient->actionCollection()->addAction(QStringLiteral("newview"));
4425         actNewWindow->setIcon(QIcon::fromTheme(QStringLiteral("window-new")));
4426         actNewWindow->setText(i18n("Open in New &Window"));
4427         actNewWindow->setStatusTip(i18n("Open the document in a new window"));
4428         connect(actNewWindow, &QAction::triggered, this, &KonqMainWindow::slotPopupNewWindow);
4429         tabHandlingActions.append(actNewWindow);
4430 
4431         QAction *actNewTab = konqyMenuClient->actionCollection()->addAction(QStringLiteral("openintab"));
4432         actNewTab->setIcon(QIcon::fromTheme(QStringLiteral("tab-new")));
4433         actNewTab->setText(i18n("Open in &New Tab"));
4434         connect(actNewTab, &QAction::triggered, this, &KonqMainWindow::slotPopupNewTab);
4435         actNewTab->setStatusTip(i18n("Open the document in a new tab"));
4436         tabHandlingActions.append(actNewTab);
4437 
4438         QAction *separator = new QAction(konqyMenuClient->actionCollection());
4439         separator->setSeparator(true);
4440         tabHandlingActions.append(separator);
4441     }
4442 
4443     if (doTabHandling) {
4444         popupActionGroups.insert(KonqPopupMenu::TabHandlingActions, tabHandlingActions);
4445     }
4446 
4447     QPointer<KonqPopupMenu> pPopupMenu = new KonqPopupMenu(
4448         items,
4449         viewURL,
4450         popupMenuCollection,
4451         popupFlags,
4452         // This parent ensures that if the part destroys itself (e.g. KHTML redirection),
4453         // it will close the popupmenu
4454         currentView->part()->widget());
4455     pPopupMenu->setNewFileMenu(m_pMenuNew);
4456     pPopupMenu->setBookmarkManager(s_bookmarkManager);
4457     pPopupMenu->setActionGroups(popupActionGroups);
4458 
4459     if (openedForViewURL && !viewURL.isLocalFile()) {
4460         pPopupMenu->setURLTitle(currentView->caption());
4461     }
4462 
4463     QPointer<KParts::NavigationExtension> be = ::qobject_cast<KParts::NavigationExtension *>(sender());
4464 
4465     if (be) {
4466         QObject::connect(this, &KonqMainWindow::popupItemsDisturbed, pPopupMenu.data(), &KonqPopupMenu::close);
4467         QObject::connect(be, SIGNAL(itemsRemoved(KFileItemList)),
4468                          this, SLOT(slotItemsRemoved(KFileItemList)));
4469     }
4470 
4471     QPointer<QObject> guard(this);   // #149736, window could be deleted inside popupmenu event loop
4472     pPopupMenu->exec(global);
4473 
4474     delete pPopupMenu;
4475 
4476     // We're sort of misusing KActionCollection here, but we need it for the actionStatusText signal...
4477     // Anyway. If the action belonged to the view, and the view got deleted, we don't want ~KActionCollection
4478     // to iterate over those deleted actions
4479     /*KActionPtrList lst = popupMenuCollection.actions();
4480     KActionPtrList::iterator it = lst.begin();
4481     for ( ; it != lst.end() ; ++it )
4482         popupMenuCollection.take( *it );*/
4483 
4484     if (guard.isNull()) { // the placement of this test is very important, double-check #149736 if moving stuff around
4485         return;
4486     }
4487 
4488     if (be) {
4489         QObject::disconnect(be, SIGNAL(itemsRemoved(KFileItemList)),
4490                             this, SLOT(slotItemsRemoved(KFileItemList)));
4491     }
4492 
4493     delete konqyMenuClient;
4494     m_popupItems.clear();
4495 
4496     // Deleted by konqyMenuClient's actioncollection
4497     //delete actNewTab;
4498     //delete actNewWindow;
4499 
4500     delete actPaste;
4501 
4502     // Restore current view if current is passive
4503     if ((m_oldView != currentView) && (currentView == m_currentView) && currentView->isPassiveMode()) {
4504         //qCDebug(KONQUEROR_LOG) << "restoring active view" << m_oldView;
4505         if (m_currentView->browserExtension()) {
4506             disconnectExtension(m_currentView->browserExtension());
4507         }
4508         if (m_oldView) {
4509             if (m_oldView->browserExtension()) {
4510                 connectExtension(m_oldView->browserExtension());
4511                 m_currentView = m_oldView;
4512             }
4513             // Special case: RMB + renaming in sidebar; setFocus would abort editing.
4514             QWidget *fw = focusWidget();
4515             if (!fw || !::qobject_cast<QLineEdit *>(fw)) {
4516                 m_oldView->part()->widget()->setFocus();
4517                 m_pViewManager->setActivePart(m_oldView->part());
4518             }
4519         }
4520     }
4521 }
4522 
4523 void KonqMainWindow::prepareForPopupMenu(const KFileItemList &items, const KParts::OpenUrlArguments &args, const BrowserArguments &browserArgs)
4524 {
4525     if (!items.isEmpty()) {
4526         m_popupUrl = items.first().url();
4527         m_popupMimeType = items.first().mimetype();
4528     } else {
4529         m_popupUrl = QUrl();
4530         m_popupMimeType.clear();
4531     }
4532     // We will need these if we call the newTab slot
4533     m_popupItems = items;
4534     m_popupUrlArgs = args;
4535     m_popupUrlArgs.setMimeType(QString());   // Reset so that Open in New Window/Tab does mimetype detection
4536     m_popupUrlBrowserArgs = browserArgs;
4537 }
4538 
4539 void KonqMainWindow::slotItemsRemoved(const KFileItemList &items)
4540 {
4541     QListIterator<KFileItem> it(items);
4542     while (it.hasNext()) {
4543         if (m_popupItems.contains(it.next())) {
4544             emit popupItemsDisturbed();
4545             return;
4546         }
4547     }
4548 }
4549 
4550 void KonqMainWindow::slotOpenEmbedded(const KPluginMetaData &part)
4551 {
4552     if (!m_currentView) {
4553         return;
4554     }
4555 
4556     m_currentView->stop();
4557     m_currentView->setLocationBarURL(m_popupUrl);
4558     m_currentView->setTypedURL(QString());
4559     if (m_currentView->changePart(m_popupMimeType,
4560                                   part.pluginId(), true)) {
4561         m_currentView->openUrl(m_popupUrl, m_popupUrl.toDisplayString(QUrl::PreferLocalFile));
4562     }
4563 }
4564 
4565 void KonqMainWindow::slotPopupPasteTo()
4566 {
4567     if (!m_currentView || m_popupUrl.isEmpty()) {
4568         return;
4569     }
4570     m_currentView->callExtensionURLMethod("pasteTo", m_popupUrl);
4571 }
4572 
4573 void KonqMainWindow::slotReconfigure()
4574 {
4575     reparseConfiguration();
4576 }
4577 
4578 void KonqMainWindow::reparseConfiguration()
4579 {
4580     qCDebug(KONQUEROR_LOG);
4581 
4582     KonqSettings::self()->load();
4583     m_pViewManager->applyConfiguration();
4584     KonqMouseEventFilter::self()->reparseConfiguration();
4585     m_pViewManager->reparseConfiguration();
4586 
4587     MapViews::ConstIterator it = m_mapViews.constBegin();
4588     MapViews::ConstIterator end = m_mapViews.constEnd();
4589     for (; it != end; ++it) {
4590         (*it)->reparseConfiguration();
4591     }
4592 }
4593 
4594 void KonqMainWindow::saveProperties(KConfigGroup &config)
4595 {
4596     // Ensure no crash if the sessionmanager timer fires before the ctor is done
4597     // This can happen via ToggleViewGUIClient -> KServiceTypeTrader::query
4598     // -> KSycoca running kbuildsycoca -> nested event loop.
4599     if (!m_fullyConstructed) {
4600         return;
4601     }
4602     KonqFrameBase::Options flags = KonqFrameBase::SaveHistoryItems;
4603     m_pViewManager->saveViewConfigToGroup(config, flags);
4604     config.writeEntry("Uuid", m_uuid);
4605     config.writeEntry("Activities", activities());
4606 }
4607 
4608 void KonqMainWindow::readProperties(const KConfigGroup &configGroup)
4609 {
4610     QString uuid = configGroup.readEntry("Uuid");
4611     if (!uuid.isEmpty()) {
4612         m_uuid = uuid;
4613     }
4614     m_pViewManager->loadViewConfigFromGroup(configGroup, QString() /*no profile name*/);
4615     // read window settings
4616     applyMainWindowSettings(configGroup);
4617 }
4618 
4619 void KonqMainWindow::applyMainWindowSettings(const KConfigGroup &config)
4620 {
4621     KParts::MainWindow::applyMainWindowSettings(config);
4622     if (m_currentView) {
4623         /// @Note status bar isn't direct child to main window
4624         QString entry = config.readEntry("StatusBar", "Enabled");
4625         m_currentView->frame()->statusbar()->setVisible(entry != QLatin1String("Disabled"));
4626     }
4627     setOnActivities(config.readEntry(QStringLiteral("Activities"), QStringList{KonquerorApplication::currentActivity()}));
4628 }
4629 
4630 void KonqMainWindow::saveMainWindowSettings(KConfigGroup &config)
4631 {
4632     KParts::MainWindow::saveMainWindowSettings(config);
4633     if (m_currentView) {
4634         /// @Note status bar isn't direct child to main window
4635         config.writeEntry("StatusBar", m_currentView->frame()->statusbar()->isHidden() ? "Disabled" : "Enabled");
4636         config.sync();
4637     }
4638 }
4639 
4640 void KonqMainWindow::setInitialFrameName(const QString &name)
4641 {
4642     m_initialFrameName = name;
4643 }
4644 
4645 void KonqMainWindow::updateOpenWithActions()
4646 {
4647     unplugActionList(QStringLiteral("openwithbase"));
4648     unplugActionList(QStringLiteral("openwith"));
4649 
4650     qDeleteAll(m_openWithActions);
4651     m_openWithActions.clear();
4652 
4653     delete m_openWithMenu;
4654     m_openWithMenu = nullptr;
4655 
4656     if (!KAuthorized::authorizeAction(QStringLiteral("openwith"))) {
4657         return;
4658     }
4659 
4660     m_openWithMenu = new KActionMenu(i18n("&Open With"), this);
4661 
4662     const KService::List &services = m_currentView->appServiceOffers();
4663     KService::List::ConstIterator it = services.constBegin();
4664     const KService::List::ConstIterator end = services.constEnd();
4665 
4666     const int baseOpenWithItems = qMax(KonqSettings::openWithItems(), 0);
4667 
4668     int idxService = 0;
4669     for (; it != end; ++it, ++idxService) {
4670         QAction *action;
4671 
4672         if (idxService < baseOpenWithItems) {
4673             action = new QAction(i18n("Open with %1", (*it)->name()), this);
4674         } else {
4675             action = new QAction((*it)->name(), this);
4676         }
4677         action->setIcon(QIcon::fromTheme((*it)->icon()));
4678 
4679         connect(action, SIGNAL(triggered()),
4680                 this, SLOT(slotOpenWith()));
4681 
4682         actionCollection()->addAction((*it)->desktopEntryName(), action);
4683         if (idxService < baseOpenWithItems) {
4684             m_openWithActions.append(action);
4685         } else {
4686             m_openWithMenu->addAction(action);
4687         }
4688     }
4689 
4690     if (services.count() > 0) {
4691         plugActionList(QStringLiteral("openwithbase"), m_openWithActions);
4692         QList<QAction *> openWithActionsMenu;
4693         if (idxService > baseOpenWithItems) {
4694             openWithActionsMenu.append(m_openWithMenu);
4695         }
4696         QAction *sep = new QAction(this);
4697         sep->setSeparator(true);
4698         openWithActionsMenu.append(sep);
4699         plugActionList(QStringLiteral("openwith"), openWithActionsMenu);
4700     }
4701 }
4702 
4703 void KonqMainWindow::updateViewModeActions()
4704 {
4705     unplugViewModeActions();
4706     for (QAction *action : m_viewModesGroup->actions()) {
4707         for (QWidget *w : action->associatedWidgets()) {
4708             w->removeAction(action);
4709         }
4710         delete action;
4711     }
4712 
4713     delete m_viewModeMenu;
4714     m_viewModeMenu = nullptr;
4715 
4716     const QVector<KPluginMetaData> services = m_currentView->partServiceOffers();
4717     if (services.count() <= 1) {
4718         return;
4719     }
4720 
4721     m_viewModeMenu = new KActionMenu(i18nc("@action:inmenu View", "&View Mode"), this);
4722     actionCollection()->addAction( "viewModeMenu", m_viewModeMenu );
4723 
4724     for (const KPluginMetaData & md : services) {
4725         const QString id = md.pluginId();
4726         bool isCurrentView = id == m_currentView->service().pluginId();
4727 
4728         if (!md.value("X-KDE-BrowserView-Toggable").isEmpty()) {
4729             continue;
4730         }
4731 
4732         //If a view provide several actions, its metadata contains an X-Konqueror-Actions-File entry
4733         //with the path of a .desktop file where the actions are described. The contents of this file
4734         //are the same as the action-related part of the old part .desktop file
4735         const QString actionDesktopFile = md.value("X-Konqueror-Actions-File");
4736 
4737         if (!actionDesktopFile.isEmpty()) {
4738             KDesktopFile df(QStandardPaths::AppDataLocation, actionDesktopFile);
4739             QStringList actionNames = df.readActions();
4740 
4741             for (const QString &name : actionNames) {
4742                 KConfigGroup grp = df.actionGroup(name);
4743                 QString text = grp.readEntry("Name", QString());
4744                 QString exec = grp.readEntry("Exec", QString());
4745                 if (text.isEmpty()) {
4746                     qCDebug(KONQUEROR_LOG) << "File" << df.fileName() << "doesn't contain a \"name\" entry";
4747                     continue;
4748                 }
4749                 KToggleAction *action = new KToggleAction(QIcon::fromTheme(grp.readEntry("Icon", QString())), text, this);
4750 //                 actionCollection()->addAction(id /*not unique!*/, action);
4751                 action->setObjectName(id + QLatin1String("-viewmode"));
4752                 action->setData(name);
4753                 action->setActionGroup(m_viewModesGroup);
4754                 m_viewModeMenu->menu()->addAction(action);
4755                 if (isCurrentView && m_currentView->internalViewMode() == name) {
4756                     action->setChecked(true);
4757                 }
4758             }
4759         } else {
4760             //TODO port away from query: is there a replacement for KService::genericName?
4761             QString text = md.name();
4762             KToggleAction *action = new KToggleAction(QIcon::fromTheme(md.iconName()), text, this);
4763             // NOTE: "-viewmode" is appended to id to avoid overwriting existing
4764             // action, e.g. konsolepart added through ToggleViewGUIClient in the ctor will be
4765             // overwritten by the view mode konsolepart action added here.  #266517.
4766             actionCollection()->addAction(id + QLatin1String("-viewmode"), action);
4767             action->setActionGroup(m_viewModesGroup);
4768             m_viewModeMenu->menu()->addAction(action);
4769             action->setChecked(isCurrentView);
4770         }
4771     }
4772 
4773     // No view mode for actions toggable views
4774     // (The other way would be to enforce a better servicetype for them, than Browser/View)
4775     if (!m_currentView->isToggleView()
4776             /* already tested: && services.count() > 1 */
4777             && m_viewModeMenu) {
4778         plugViewModeActions();
4779     }
4780 }
4781 
4782 void KonqMainWindow::slotInternalViewModeChanged()
4783 {
4784     KParts::ReadOnlyPart *part = static_cast<KParts::ReadOnlyPart *>(sender());
4785     KonqView *view = m_mapViews.value(part);
4786     if (view) {
4787         const QString actionName = view->service().pluginId();
4788         const QString actionData = view->internalViewMode();
4789         for (QAction *action: m_viewModesGroup->actions()) {
4790             if (action->objectName() == actionName + QLatin1String("-viewmode") &&
4791                     action->data().toString() == actionData) {
4792                 action->setChecked(true);
4793                 break;
4794             }
4795         }
4796     }
4797 }
4798 
4799 void KonqMainWindow::plugViewModeActions()
4800 {
4801     QList<QAction *> lst;
4802 
4803     if (m_viewModeMenu) {
4804         lst.append(m_viewModeMenu);
4805     }
4806 
4807     plugActionList(QStringLiteral("viewmode"), lst);
4808 }
4809 
4810 void KonqMainWindow::unplugViewModeActions()
4811 {
4812     unplugActionList(QStringLiteral("viewmode"));
4813 }
4814 
4815 void KonqMainWindow::updateBookmarkBar()
4816 {
4817     KToolBar *bar = this->findChild<KToolBar *>(QStringLiteral("bookmarkToolBar"));
4818     if (!bar) {
4819         return;
4820     }
4821     if (m_paBookmarkBar && bar->actions().isEmpty()) {
4822         bar->hide();
4823     }
4824 
4825 }
4826 
4827 void KonqMainWindow::closeEvent(QCloseEvent *e)
4828 {
4829     // This breaks session management (the window is withdrawn in kwin)
4830     // so let's do this only when closed by the user.
4831 
4832     if (!qApp->isSavingSession()) {
4833         KonqFrameTabs *tabContainer = m_pViewManager->tabContainer();
4834         if (tabContainer->count() > 1) {
4835             KSharedConfig::Ptr config = KSharedConfig::openConfig();
4836             KConfigGroup cs(config, QStringLiteral("Notification Messages"));
4837 
4838             if (!cs.hasKey("MultipleTabConfirm")) {
4839                 switch (
4840                     KMessageBox::warningTwoActionsCancel(
4841                         this,
4842                         i18n("You have multiple tabs open in this window, "
4843                              "are you sure you want to quit?"),
4844                         i18nc("@title:window", "Confirmation"),
4845                         KStandardGuiItem::closeWindow(),
4846                         KGuiItem(i18n("C&lose Current Tab"), QStringLiteral("tab-close")),
4847                         KStandardGuiItem::cancel(),
4848                         QStringLiteral("MultipleTabConfirm")
4849                     )
4850                 ) {
4851                 case KMessageBox::PrimaryAction :
4852                     break;
4853                 case KMessageBox::SecondaryAction :
4854                     e->ignore();
4855                     slotRemoveTab();
4856                     return;
4857                 case KMessageBox::Cancel :
4858                     e->ignore();
4859                     return;
4860                 default:
4861                     Q_UNREACHABLE();
4862                 }
4863             }
4864         }
4865 
4866         emit closing(this);
4867 
4868         const int originalTabIndex = tabContainer->currentIndex();
4869         for (int tabIndex = 0; tabIndex < tabContainer->count(); ++tabIndex) {
4870             KonqFrameBase *tab = tabContainer->tabAt(tabIndex);
4871             if (!KonqModifiedViewsCollector::collect(tab).isEmpty()) {
4872                 m_pViewManager->showTab(tabIndex);
4873                 const QString question = m_pViewManager->isTabBarVisible()
4874                                          ? i18n("This tab contains changes that have not been submitted.\nClosing the window will discard these changes.")
4875                                          : i18n("This page contains changes that have not been submitted.\nClosing the window will discard these changes.");
4876                 if (KMessageBox::warningContinueCancel(
4877                             this, question,
4878                             i18nc("@title:window", "Discard Changes?"), KGuiItem(i18n("&Discard Changes"), QStringLiteral("application-exit")),
4879                             KStandardGuiItem::cancel(), QStringLiteral("discardchangesclose")) != KMessageBox::Continue) {
4880                     e->ignore();
4881                     m_pViewManager->showTab(originalTabIndex);
4882                     return;
4883                 }
4884             }
4885         }
4886 
4887         if (settingsDirty() && autoSaveSettings()) {
4888             saveAutoSaveSettings();
4889         }
4890 
4891         addClosedWindowToUndoList();
4892     }
4893 
4894     emit closing(this);
4895 
4896     // We're going to close - tell the parts
4897     MapViews::ConstIterator it = m_mapViews.constBegin();
4898     MapViews::ConstIterator end = m_mapViews.constEnd();
4899     for (; it != end; ++it) {
4900         if ((*it)->part() && (*it)->part()->widget()) {
4901             QApplication::sendEvent((*it)->part()->widget(), e);
4902         }
4903     }
4904     KParts::MainWindow::closeEvent(e);
4905 }
4906 
4907 void KonqMainWindow::addClosedWindowToUndoList()
4908 {
4909     qCDebug(KONQUEROR_LOG);
4910 
4911     // 1. We get the current title
4912     int numTabs = m_pViewManager->tabContainer()->childFrameList().count();
4913     QString title(i18n("no name"));
4914 
4915     if (m_currentView) {
4916         title = m_currentView->caption();
4917     }
4918 
4919     // 2. Create the KonqClosedWindowItem and  save its config
4920     KonqClosedWindowItem *closedWindowItem = new KonqClosedWindowItem(title, KonqClosedWindowsManager::self()->memoryStore(),
4921                                                                       m_pUndoManager->newCommandSerialNumber(), numTabs);
4922     saveProperties(closedWindowItem->configGroup());
4923 
4924     // 3. Add the KonqClosedWindowItem to the undo list
4925     m_paClosedItems->setEnabled(true);
4926     m_pUndoManager->addClosedWindowItem(closedWindowItem);
4927 
4928     qCDebug(KONQUEROR_LOG) << "done";
4929 }
4930 
4931 void KonqMainWindow::updateWindowIcon()
4932 {
4933     KParts::MainWindow::setWindowIcon(KonqPixmapProvider::self()->iconForUrl(m_combo->currentText()));
4934 }
4935 
4936 void KonqMainWindow::slotIntro()
4937 {
4938     openUrl(nullptr, KonqUrl::url(KonqUrl::Type::NoPath));
4939 }
4940 
4941 void KonqMainWindow::goURL()
4942 {
4943     QLineEdit *lineEdit = comboEdit();
4944     if (!lineEdit) {
4945         return;
4946     }
4947 
4948     QKeyEvent event(QEvent::KeyPress, Qt::Key_Return, Qt::NoModifier, QChar('\n'));
4949     QApplication::sendEvent(lineEdit, &event);
4950 }
4951 
4952 /**
4953  * Adds the URL of a KonqView to the closed tabs list.
4954  * This slot gets called each time a View is closed.
4955  */
4956 void KonqMainWindow::slotAddClosedUrl(KonqFrameBase *tab)
4957 {
4958     qCDebug(KONQUEROR_LOG);
4959     QString title(i18n("no name")), url(KonqUrl::string(KonqUrl::Type::Blank));
4960 
4961     // Did the tab contain a single frame, or a splitter?
4962     KonqFrame *frame = dynamic_cast<KonqFrame *>(tab);
4963     if (!frame) {
4964         KonqFrameContainer *frameContainer = dynamic_cast<KonqFrameContainer *>(tab);
4965         if (frameContainer->activeChildView()) {
4966             frame = frameContainer->activeChildView()->frame();
4967         }
4968     }
4969 
4970     KParts::ReadOnlyPart *part = frame ? frame->part() : nullptr;
4971     if (part) {
4972         url = part->url().url();
4973     }
4974     if (frame) {
4975         title = frame->title().trimmed();
4976     }
4977     if (title.isEmpty()) {
4978         title = url;
4979     }
4980     title = KStringHandler::csqueeze(title, 50);
4981 
4982     // Now we get the position of the tab
4983     const int index =  m_pViewManager->tabContainer()->childFrameList().indexOf(tab);
4984 
4985     KonqClosedTabItem *closedTabItem = new KonqClosedTabItem(url, KonqClosedWindowsManager::self()->memoryStore(),
4986                                                              title, index, m_pUndoManager->newCommandSerialNumber());
4987 
4988     QString prefix = KonqFrameBase::frameTypeToString(tab->frameType()) + QString::number(0);
4989     closedTabItem->configGroup().writeEntry("RootItem", prefix);
4990     prefix.append(QLatin1Char('_'));
4991     KonqFrameBase::Options flags = KonqFrameBase::SaveHistoryItems;
4992     tab->saveConfig(closedTabItem->configGroup(), prefix, flags, nullptr, 0, 1);
4993 
4994     m_paClosedItems->setEnabled(true);
4995     m_pUndoManager->addClosedTabItem(closedTabItem);
4996 
4997     qCDebug(KONQUEROR_LOG) << "done";
4998 }
4999 
5000 void KonqMainWindow::slotLocationLabelActivated()
5001 {
5002     focusLocationBar();
5003     QLineEdit *edit = comboEdit();
5004     if (edit) {
5005         edit->selectAll();
5006     }
5007 }
5008 
5009 void KonqMainWindow::slotOpenURL(const QUrl &url)
5010 {
5011     openUrl(nullptr, url);
5012 }
5013 
5014 bool KonqMainWindow::sidebarVisible() const
5015 {
5016     QAction *a = m_toggleViewGUIClient->action(QStringLiteral("konq_sidebartng"));
5017     return (a && static_cast<KToggleAction *>(a)->isChecked());
5018 }
5019 
5020 bool KonqMainWindow::fullScreenMode() const
5021 {
5022     return m_ptaFullScreen->isChecked();
5023 }
5024 
5025 void KonqMainWindow::slotAddWebSideBar(const QUrl &url, const QString &name)
5026 {
5027     if (url.isEmpty() && name.isEmpty()) {
5028         return;
5029     }
5030 
5031     qCDebug(KONQUEROR_LOG) << "Requested to add URL" << url << " [" << name << "] to the sidebar!";
5032 
5033     QAction *a = m_toggleViewGUIClient->action(QStringLiteral("konq_sidebartng"));
5034     if (!a) {
5035         KMessageBox::error(nullptr, i18n("Your sidebar is not functional or unavailable. A new entry cannot be added."), i18nc("@title:window", "Web Sidebar"));
5036         return;
5037     }
5038 
5039     int rc = KMessageBox::questionTwoActions(nullptr,
5040                                         i18n("Add new web extension \"%1\" to your sidebar?",
5041                                                 name.isEmpty() ? name : url.toDisplayString()),
5042                                         i18nc("@title:window", "Web Sidebar"), KGuiItem(i18n("Add")), KGuiItem(i18n("Do Not Add")));
5043 
5044     if (rc == KMessageBox::PrimaryAction) {
5045         // Show the sidebar
5046         if (!static_cast<KToggleAction *>(a)->isChecked()) {
5047             a->trigger();
5048         }
5049 
5050         // Tell it to add a new panel
5051         MapViews::ConstIterator it;
5052         for (it = viewMap().constBegin(); it != viewMap().constEnd(); ++it) {
5053             KonqView *view = it.value();
5054             if (view) {
5055                 KPluginMetaData svc = view->service();
5056                 if (svc.pluginId() == QLatin1String("konq_sidebartng")) {
5057                     emit view->browserExtension()->addWebSideBar(url, name);
5058                     break;
5059                 }
5060             }
5061         }
5062     }
5063 }
5064 
5065 void KonqMainWindow::addBookmarksIntoCompletion(const KBookmarkGroup &group)
5066 {
5067     const QString http = QStringLiteral("http");
5068     const QString ftp = QStringLiteral("ftp");
5069 
5070     if (group.isNull()) {
5071         return;
5072     }
5073 
5074     for (KBookmark bm = group.first();
5075             !bm.isNull(); bm = group.next(bm)) {
5076         if (bm.isGroup()) {
5077             addBookmarksIntoCompletion(bm.toGroup());
5078             continue;
5079         }
5080 
5081         QUrl url = bm.url();
5082         if (!url.isValid()) {
5083             continue;
5084         }
5085 
5086         QString u = url.toDisplayString();
5087         s_pCompletion->addItem(u);
5088 
5089         if (url.isLocalFile()) {
5090             s_pCompletion->addItem(url.toLocalFile());
5091         } else if (url.scheme() == http) {
5092             s_pCompletion->addItem(u.mid(7));
5093         } else if (url.scheme() == ftp &&
5094                    url.host().startsWith(ftp)) {
5095             s_pCompletion->addItem(u.mid(6));
5096         }
5097     }
5098 }
5099 
5100 //
5101 // the smart popup completion code , <l.lunak@kde.org>
5102 //
5103 
5104 // prepend http://www. or http:// if there's no protocol in 's'
5105 // This is used only when there are no completion matches
5106 static QString hp_tryPrepend(const QString &s)
5107 {
5108     if (s.isEmpty() || s[0] == QLatin1Char('/') || s[0] == QLatin1Char('~')) {
5109         return QString();
5110     }
5111 
5112     bool containsSpace = false;
5113 
5114     for (int pos = 0;
5115             pos < s.length() - 2; // 4 = ://x
5116             ++pos) {
5117         if (s[ pos ] == ':' && s[ pos + 1 ] == '/' && s[ pos + 2 ] == '/') {
5118             return QString();
5119         }
5120         if (!s[ pos ].isLetter()) {
5121             break;
5122         }
5123         if (s[pos].isSpace()) {
5124             containsSpace = true;
5125             break;
5126         }
5127     }
5128 
5129     if (containsSpace || s.at(s.length() - 1).isSpace()) {
5130         return QString();
5131     }
5132 
5133     return (s.startsWith(QLatin1String("www.")) ? "http://" : "http://www.") + s;
5134 }
5135 
5136 static void hp_removeDupe(KCompletionMatches &l, const QString &dupe,
5137                           KCompletionMatches::Iterator it_orig)
5138 {
5139     KCompletionMatches::Iterator it = it_orig + 1;
5140     while (it != l.end()) {
5141         if ((*it).value() == dupe) {
5142             (*it_orig).first = qMax((*it_orig).first, (*it).key());
5143             it = l.erase(it);
5144             continue;
5145         }
5146         ++it;
5147     }
5148 }
5149 
5150 // remove duplicates like 'http://www.kde.org' and 'http://www.kde.org/'
5151 // (i.e. the trailing slash)
5152 // some duplicates are also created by prepending protocols
5153 static void hp_removeDuplicates(KCompletionMatches &l)
5154 {
5155     QString http = QStringLiteral("http://");
5156     QString ftp = QStringLiteral("ftp://ftp.");
5157     QString file = QStringLiteral("file:");
5158     QString file2 = QStringLiteral("file://");
5159     l.removeDuplicates();
5160     for (KCompletionMatches::Iterator it = l.begin();
5161             it != l.end();
5162             ++it) {
5163         QString str = (*it).value();
5164         if (str.startsWith(http)) {
5165             if (str.indexOf('/', 7) < 0) {    // http://something<noslash>
5166                 hp_removeDupe(l, str + '/', it);
5167                 hp_removeDupe(l, str.mid(7) + '/', it);
5168             } else if (str[ str.length() - 1 ] == '/') {
5169                 hp_removeDupe(l, str.left(str.length() - 1), it);
5170                 hp_removeDupe(l, str.left(str.length() - 1).mid(7), it);
5171             }
5172             hp_removeDupe(l, str.mid(7), it);
5173         } else if (str.startsWith(ftp)) { // ftp://ftp.
5174             hp_removeDupe(l, str.mid(6), it);    // remove dupes without ftp://
5175         } else if (str.startsWith(file2)) {
5176             hp_removeDupe(l, str.mid(7), it);    // remove dupes without file://
5177         } else if (str.startsWith(file)) {
5178             hp_removeDupe(l, str.mid(5), it);    // remove dupes without file:
5179         }
5180     }
5181 }
5182 
5183 static void hp_removeCommonPrefix(KCompletionMatches &l, const QString &prefix)
5184 {
5185     for (KCompletionMatches::Iterator it = l.begin();
5186             it != l.end();
5187         ) {
5188         if ((*it).value().startsWith(prefix)) {
5189             it = l.erase(it);
5190             continue;
5191         }
5192         ++it;
5193     }
5194 }
5195 
5196 // don't include common prefixes like 'http://', i.e. when s == 'h', include
5197 // http://hotmail.com but don't include everything just starting with 'http://'
5198 static void hp_checkCommonPrefixes(KCompletionMatches &matches, const QString &s)
5199 {
5200     static const char *const prefixes[] = {
5201         "http://",
5202         "https://",
5203         "www.",
5204         "ftp://",
5205         "http://www.",
5206         "https://www.",
5207         "ftp://ftp.",
5208         "file:",
5209         "file://",
5210         nullptr
5211     };
5212     for (const char *const *pos = prefixes;
5213             *pos != nullptr;
5214             ++pos) {
5215         QString prefix = *pos;
5216         if (prefix.startsWith(s)) {
5217             hp_removeCommonPrefix(matches, prefix);
5218         }
5219     }
5220 }
5221 
5222 QStringList KonqMainWindow::historyPopupCompletionItems(const QString &s)
5223 {
5224     const QString http = QStringLiteral("http://");
5225     const QString https = QStringLiteral("https://");
5226     const QString www = QStringLiteral("http://www.");
5227     const QString wwws = QStringLiteral("https://www.");
5228     const QString ftp = QStringLiteral("ftp://");
5229     const QString ftpftp = QStringLiteral("ftp://ftp.");
5230     const QString file = QStringLiteral("file:"); // without /, because people enter /usr etc.
5231     const QString file2 = QStringLiteral("file://");
5232     if (s.isEmpty()) {
5233         return QStringList();
5234     }
5235     KCompletionMatches matches = s_pCompletion->allWeightedMatches(s);
5236     hp_checkCommonPrefixes(matches, s);
5237     bool checkDuplicates = false;
5238     if (!s.startsWith(ftp)) {
5239         matches += s_pCompletion->allWeightedMatches(ftp + s);
5240         if (QStringLiteral("ftp.").startsWith(s)) {
5241             hp_removeCommonPrefix(matches, ftpftp);
5242         }
5243         checkDuplicates = true;
5244     }
5245     if (!s.startsWith(https)) {
5246         matches += s_pCompletion->allWeightedMatches(https + s);
5247         if (QStringLiteral("www.").startsWith(s)) {
5248             hp_removeCommonPrefix(matches, wwws);
5249         }
5250         checkDuplicates = true;
5251     }
5252     if (!s.startsWith(http)) {
5253         matches += s_pCompletion->allWeightedMatches(http + s);
5254         if (QStringLiteral("www.").startsWith(s)) {
5255             hp_removeCommonPrefix(matches, www);
5256         }
5257         checkDuplicates = true;
5258     }
5259     if (!s.startsWith(www)) {
5260         matches += s_pCompletion->allWeightedMatches(www + s);
5261         checkDuplicates = true;
5262     }
5263     if (!s.startsWith(wwws)) {
5264         matches += s_pCompletion->allWeightedMatches(wwws + s);
5265         checkDuplicates = true;
5266     }
5267     if (!s.startsWith(ftpftp)) {
5268         matches += s_pCompletion->allWeightedMatches(ftpftp + s);
5269         checkDuplicates = true;
5270     }
5271     if (!s.startsWith(file)) {
5272         matches += s_pCompletion->allWeightedMatches(file + s);
5273         checkDuplicates = true;
5274     }
5275     if (!s.startsWith(file2)) {
5276         matches += s_pCompletion->allWeightedMatches(file2 + s);
5277         checkDuplicates = true;
5278     }
5279     if (checkDuplicates) {
5280         hp_removeDuplicates(matches);
5281     }
5282     QStringList items = matches.list();
5283     if (items.count() == 0
5284             && !s.contains(':') && !s.isEmpty() && s[ 0 ] != '/') {
5285         QString pre = hp_tryPrepend(s);
5286         if (!pre.isNull()) {
5287             items += pre;
5288         }
5289     }
5290     return items;
5291 }
5292 
5293 #ifndef NDEBUG
5294 void KonqMainWindow::dumpViewList()
5295 {
5296     qCDebug(KONQUEROR_LOG) << m_mapViews.count() << "views:";
5297 
5298     MapViews::Iterator end = m_mapViews.end();
5299     for (MapViews::Iterator it = m_mapViews.begin(); it != end; ++it) {
5300         KonqView *view = it.value();
5301         qCDebug(KONQUEROR_LOG) << view << view->part();
5302     }
5303 }
5304 #endif
5305 
5306 void KonqMainWindow::insertChildFrame(KonqFrameBase *frame, int /*index*/)
5307 {
5308     m_pChildFrame = frame;
5309     m_pActiveChild = frame;
5310     frame->setParentContainer(this);
5311     if (centralWidget() && centralWidget() != frame->asQWidget()) {
5312         centralWidget()->setParent(nullptr);   // workaround Qt-4.1.2 crash (reported)
5313         setCentralWidget(nullptr);
5314     }
5315     setCentralWidget(frame->asQWidget());
5316 }
5317 
5318 void KonqMainWindow::childFrameRemoved(KonqFrameBase *frame)
5319 {
5320     Q_ASSERT(frame == m_pChildFrame);
5321     Q_UNUSED(frame)
5322     m_pChildFrame = nullptr;
5323     m_pActiveChild = nullptr;
5324 }
5325 
5326 void KonqMainWindow::saveConfig(KConfigGroup &config, const QString &prefix, const KonqFrameBase::Options &options, KonqFrameBase *docContainer, int id, int depth)
5327 {
5328     if (m_pChildFrame) {
5329         m_pChildFrame->saveConfig(config, prefix, options, docContainer, id, depth);
5330     }
5331 }
5332 
5333 void KonqMainWindow::copyHistory(KonqFrameBase *other)
5334 {
5335     if (m_pChildFrame) {
5336         m_pChildFrame->copyHistory(other);
5337     }
5338 }
5339 
5340 void KonqMainWindow::setTitle(const QString &/*title*/, QWidget * /*sender*/)
5341 {
5342 }
5343 
5344 void KonqMainWindow::setTabIcon(const QUrl &/*url*/, QWidget * /*sender*/)
5345 {
5346 }
5347 
5348 QWidget *KonqMainWindow::asQWidget()
5349 {
5350     return this;
5351 }
5352 
5353 KonqFrameBase::FrameType KonqMainWindow::frameType() const
5354 {
5355     return KonqFrameBase::MainWindow;
5356 }
5357 
5358 KonqFrameBase *KonqMainWindow::childFrame()const
5359 {
5360     return m_pChildFrame;
5361 }
5362 
5363 void KonqMainWindow::setActiveChild(KonqFrameBase * /*activeChild*/)
5364 {
5365 }
5366 
5367 void KonqMainWindow::setWorkingTab(int index)
5368 {
5369     m_workingTab = index;
5370 }
5371 
5372 bool KonqMainWindow::isMimeTypeAssociatedWithSelf(const QString &mimeType)
5373 {
5374     return isMimeTypeAssociatedWithSelf(mimeType, KApplicationTrader::preferredService(mimeType));
5375 }
5376 
5377 bool KonqMainWindow::isMimeTypeAssociatedWithSelf(const QString &/*mimeType*/, const KService::Ptr &offer)
5378 {
5379     // Prevention against user stupidity : if the associated app for this mimetype
5380     // is konqueror/kfmclient, then we'll loop forever. So we have to
5381     // 1) force embedding first, if that works we're ok
5382     // 2) check what OpenUrlJob is going to do before calling it.
5383     return (offer && (offer->desktopEntryName() == QLatin1String("konqueror") ||
5384                       offer->exec().trimmed().startsWith(QLatin1String("kfmclient"))));
5385 }
5386 
5387 bool KonqMainWindow::refuseExecutingKonqueror(const QString &mimeType)
5388 {
5389     if (activeViewsNotLockedCount() > 0) {   // if I lock the only view, then there's no error: open links in a new window
5390         KMessageBox::error(this, i18n("There appears to be a configuration error. You have associated Konqueror with %1, but it cannot handle this file type.", mimeType));
5391         return true; // we refuse indeed
5392     }
5393     return false; // no error
5394 }
5395 
5396 bool KonqMainWindow::event(QEvent *e)
5397 {
5398     if (e->type() == QEvent::ActivationChange && !isActiveWindow()) {
5399         m_lastDeactivationTime = QDateTime::currentMSecsSinceEpoch();
5400     }
5401     if (e->type() == QEvent::StatusTip) {
5402         if (m_currentView && m_currentView->frame()->statusbar()) {
5403             KonqFrameStatusBar *statusBar = m_currentView->frame()->statusbar();
5404             statusBar->message(static_cast<QStatusTipEvent *>(e)->tip());
5405         }
5406     }
5407 
5408     if (KonqFileSelectionEvent::test(e) ||
5409             KonqFileMouseOverEvent::test(e) ||
5410             KParts::PartActivateEvent::test(e)) {
5411         // Forward the event to all views
5412         MapViews::ConstIterator it = m_mapViews.constBegin();
5413         MapViews::ConstIterator end = m_mapViews.constEnd();
5414         for (; it != end; ++it) {
5415             QApplication::sendEvent((*it)->part(), e);
5416         }
5417         return true;
5418     }
5419 
5420     if (KParts::OpenUrlEvent::test(e)) {
5421         KParts::OpenUrlEvent *ev = static_cast<KParts::OpenUrlEvent *>(e);
5422 
5423         // Forward the event to all views
5424         MapViews::ConstIterator it = m_mapViews.constBegin();
5425         MapViews::ConstIterator end = m_mapViews.constEnd();
5426         for (; it != end; ++it) {
5427             // Don't resend to sender
5428             if (it.key() != ev->part()) {
5429                 //qCDebug(KONQUEROR_LOG) << "Sending event to view" << it.key()->metaObject()->className();
5430                 QApplication::sendEvent(it.key(), e);
5431             }
5432         }
5433     }
5434     return KParts::MainWindow::event(e);
5435 }
5436 
5437 void KonqMainWindow::slotUndoTextChanged(const QString &newText)
5438 {
5439     m_paUndo->setText(newText);
5440 }
5441 
5442 KonqView *KonqMainWindow::currentView() const
5443 {
5444     return m_currentView;
5445 }
5446 
5447 bool KonqMainWindow::accept(KonqFrameVisitor *visitor)
5448 {
5449     return visitor->visit(this)
5450            && (!m_pChildFrame || m_pChildFrame->accept(visitor))
5451            && visitor->endVisit(this);
5452 }
5453 
5454 QLineEdit *KonqMainWindow::comboEdit()
5455 {
5456     return m_combo ? m_combo->lineEdit() : nullptr;
5457 }
5458 
5459 void KonqMainWindow::updateProxyForWebEngine(bool updateProtocolManager)
5460 {
5461     if (updateProtocolManager) {
5462         KProtocolManager::reparseConfiguration();
5463     }
5464 
5465     KPluginMetaData part = preferredPart(QStringLiteral("text/html"));
5466     Q_ASSERT(part.isValid());
5467     const bool webengineIsDefault = part.pluginId() == QLatin1String("webenginepart");
5468     if (!webengineIsDefault) {
5469         return;
5470     }
5471 
5472     int proxyTypeAsInt =  KConfig(QStringLiteral("kioslaverc"), KConfig::NoGlobals).group("Proxy Settings").readEntry("ProxyType", 0);
5473     //According to kioextras/kcms/saveioconfig.h, 2 is PACProxy and 3 is WPADProxy
5474     if (proxyTypeAsInt == 2 || proxyTypeAsInt == 3) {
5475         QString msg = i18n("Your proxy configuration can't be used with the QtWebEngine HTML engine. "
5476                            "No proxy will be used\n\n QtWebEngine only support a fixed proxy, so proxy auto-configuration (PAC) "
5477                            "and Web Proxy Auto-Discovery protocol can't be used with QtWebEngine. If you need a proxy, please select "
5478                            "the system proxy configuration or specify a proxy URL manually in the settings dialog. Do you want to "
5479                            "change proxy settings now?");
5480         KMessageBox::ButtonCode ans = KMessageBox::warningTwoActions(this, msg, i18n("Unsupported proxy configuration"), KGuiItem(i18n("Don't use a proxy")),
5481                                                                 KGuiItem(i18n("Show proxy configuration dialog")), "WebEngineUnsupportedProxyType");
5482         QNetworkProxy::setApplicationProxy(QNetworkProxy(QNetworkProxy::NoProxy));
5483         if (ans == KMessageBox::SecondaryAction) {
5484             slotConfigure(Konq::ConfigDialog::ProxyModule);
5485             return;
5486         }
5487     }
5488 
5489     bool proxyConfigurationSupported = false;
5490     QNetworkProxy httpProxy;
5491     QNetworkProxy httpsProxy;
5492 #if QT_VERSION_MAJOR < 6
5493     QString httpProxyHost = KProtocolManager::proxyFor(QStringLiteral("http"));
5494     QString httpsProxyHost = KProtocolManager::proxyFor(QStringLiteral("https"));
5495     proxyConfigurationSupported = httpsProxyHost == httpProxyHost;
5496     if ((httpProxyHost.isEmpty() && httpsProxyHost.isEmpty()) || (httpProxyHost == "DIRECT" && httpsProxyHost == "DIRECT")) {
5497         QNetworkProxy::setApplicationProxy(QNetworkProxy(QNetworkProxy::NoProxy));
5498         return;
5499     }
5500     if (!httpProxyHost.isEmpty() && httpProxyHost != QStringLiteral("DIRECT")) {
5501         httpProxy = {QNetworkProxy::HttpProxy, httpProxyHost};
5502     }
5503     if (!httpsProxyHost.isEmpty() && httpsProxyHost != QStringLiteral("DIRECT")) {
5504         httpsProxy = {QNetworkProxy::HttpProxy, httpsProxyHost};
5505     }
5506 #else
5507     QList<QNetworkProxy> httpProxies = QNetworkProxyFactory::proxyForQuery(QNetworkProxyQuery{QUrl("http:")});
5508     QList<QNetworkProxy> httpsProxies = QNetworkProxyFactory::proxyForQuery(QNetworkProxyQuery{QUrl("https:")});
5509     if (!httpProxies.isEmpty()) {
5510         httpProxy = httpProxies.first();
5511     }
5512     if (!httpsProxies.isEmpty()) {
5513         httpsProxy = httpsProxies.first();
5514     }
5515     proxyConfigurationSupported = httpProxy == httpsProxy;
5516 #endif
5517 
5518     QNetworkProxy proxy = httpsProxy;
5519 
5520     if (!proxyConfigurationSupported) {
5521         QString msg =  i18n("Your proxy configuration can't be used with the QtWebEngine HTML engine because it doesn't support having different proxies for the HTTP and HTTPS protocols. Your current settings are:"
5522         "<p><b>HTTP proxy:</b> <tt>%1</tt></p><p><b>HTTPS proxy: </b><tt>%2</tt></p>"
5523         "What do you want to do?", httpProxy.hostName(), httpsProxy.hostName());
5524         KMessageBox::ButtonCode ans = KMessageBox::questionTwoActionsCancel(this, msg, i18n("Conflicting proxy configuration"),
5525             KGuiItem(i18n("Use HTTP proxy (only this time)")), KGuiItem(i18n("Use HTTPS proxy (only this time)")), KGuiItem(i18n("Show proxy configuration dialog")), "WebEngineConflictingProxy");
5526         if (ans == KMessageBox::PrimaryAction) {
5527             proxy = httpProxy;
5528         } else if (ans == KMessageBox::Cancel) {
5529             slotConfigure(Konq::ConfigDialog::ProxyModule);
5530             return;
5531         }
5532     }
5533     QNetworkProxy::setApplicationProxy(proxy);
5534 }
5535 
5536 void KonqMainWindow::toggleCompleteFullScreen(bool on)
5537 {
5538     //Do nothing if already in complete full screen mode and on is true or not in complete full screen mode and on is false
5539     if (on == (m_fullScreenData.currentState == FullScreenState::CompleteFullScreen)) {
5540         return;
5541     }
5542     if (on) {
5543         slotForceSaveMainWindowSettings();
5544         resetAutoSaveSettings();
5545 
5546         //Hide the menu bar
5547         menuBar()->setVisible(false);
5548 
5549         //Hide the side bar
5550         if (m_toggleViewGUIClient) {
5551             QAction *a = m_toggleViewGUIClient->action(QStringLiteral("konq_sidebartng"));
5552             if (a) {
5553                 KToggleAction *ta = static_cast<KToggleAction*>(a);
5554                 if (ta){
5555                     m_fullScreenData.wasSidebarVisible = ta->isChecked();
5556                     a->setChecked(false);
5557                 }
5558             }
5559         } else {
5560             m_fullScreenData.wasSidebarVisible = false;
5561         }
5562 
5563         //Hide the tool bars
5564         const QList<QAction*> actions = toolBarMenuAction()->menu()->actions();
5565         for (QAction *a : actions) {
5566             a->setChecked(false);
5567         }
5568     } else {
5569         setAutoSaveSettings();
5570     }
5571 
5572     //Status bar and side bar are not managed by autoSaveSettings
5573 
5574     //Hide or show the sidebar
5575     //TODO: isn't this a duplicate of the above?
5576     if (m_toggleViewGUIClient) {
5577         QAction *a = m_toggleViewGUIClient->action(QStringLiteral("konq_sidebartng"));
5578         KToggleAction *sideBarAction = qobject_cast<KToggleAction*>(a);
5579         if (sideBarAction) {
5580             if (on) {
5581                 m_fullScreenData.wasSidebarVisible = sideBarAction ->isChecked();
5582                 sideBarAction ->setChecked(false);
5583             } else if (m_fullScreenData.wasSidebarVisible) {
5584                 sideBarAction->setChecked(true);
5585             }
5586         }
5587     }
5588 
5589     //Hide or show the status bar
5590     if (m_currentView) {
5591         QStatusBar *statusBar = m_currentView->frame()->statusbar();
5592         if (on) {
5593             m_fullScreenData.wasStatusBarVisible = statusBar->isVisible();
5594             statusBar->setVisible(false);
5595         } else if (m_fullScreenData.wasStatusBarVisible) {
5596             statusBar->setVisible(true);
5597         }
5598     }
5599 
5600     if (on || m_fullScreenData.previousState == FullScreenState::NoFullScreen) {
5601         disconnect(m_ptaFullScreen, &KToggleAction::toggled, this, &KonqMainWindow::slotUpdateFullScreen);
5602         KToggleFullScreenAction::setFullScreen(this, on);
5603         connect(m_ptaFullScreen, &KToggleAction::toggled, this, &KonqMainWindow::slotUpdateFullScreen);
5604     }
5605     m_pViewManager->forceHideTabBar(on);
5606 
5607     if (on) {
5608     QString msg = i18n("You have entered Complete Full Screen mode (the user interface is completely hidden)."
5609     " You can exit it by pressing the keyboard shortcut for Full Screen Mode (%1)", m_ptaFullScreen->shortcut().toString());
5610         KMessageBox::information(this, msg, QString(), "Complete Full Screen Warning");
5611     }
5612 
5613     m_fullScreenData.switchToState(on ? FullScreenState::CompleteFullScreen : m_fullScreenData.previousState);
5614 }
5615 
5616 void KonqMainWindow::FullScreenData::switchToState(KonqMainWindow::FullScreenState newState)
5617 {
5618     if (newState != currentState) {
5619         previousState = currentState;
5620         currentState = newState;
5621     }
5622 }
5623 
5624 void KonqMainWindow::inspectCurrentPage()
5625 {
5626     if (!m_currentView || !m_currentView->isWebEngineView()) {
5627         return;
5628     }
5629     KParts::ReadOnlyPart *partToInspect = m_currentView->part();
5630     KonqView *devToolsView = m_pViewManager->splitView(m_currentView, Qt::Vertical);
5631     if (devToolsView == nullptr) {
5632         return;
5633     }
5634     KonqOpenURLRequest req;
5635     req.forceAutoEmbed = true;
5636 
5637     openView("text/html", QUrl(), devToolsView, req);
5638     QMetaObject::invokeMethod(devToolsView->part(), "setInspectedPart", Qt::DirectConnection, Q_ARG(KParts::ReadOnlyPart*, partToInspect));
5639 }
5640 
5641 void KonqMainWindow::saveGlobalProperties(KConfig* sessionConfig)
5642 {
5643     QList<int> preloadedNumbers;
5644     const QList<KMainWindow*> windows = KMainWindow::memberList();
5645     for (int i = 0; i < windows.length(); ++i) {
5646         KonqMainWindow *kw = qobject_cast<KonqMainWindow*>(windows.at(i));
5647         if (kw && kw->isPreloaded()) {
5648             preloadedNumbers << (i+1); //KMainWindow::restore numbers windows from 1
5649         }
5650     }
5651 
5652     KConfigGroup cg = sessionConfig->group(QStringLiteral("PreloadedWindows"));
5653     cg.writeEntry(QStringLiteral("PreloadedWindowsNumber"), preloadedNumbers);
5654     cg.sync();
5655 }
5656 
5657 void KonqMainWindow::readGlobalProperties(KConfig* sessionConfig)
5658 {
5659     KConfigGroup cg = sessionConfig->group(QStringLiteral("PreloadedWindows"));
5660     QList<int> preloadedNumbers = cg.readEntry(QStringLiteral("PreloadedWindowsNumber"), QList<int>{});
5661     KonqSessionManager::self()->setPreloadedWindowsNumber(preloadedNumbers);
5662 }
5663 
5664 qint64 KonqMainWindow::lastDeactivationTime() const
5665 {
5666     return m_lastDeactivationTime;
5667 }
5668 
5669 QStringList KonqMainWindow::activities() const
5670 {
5671     return KWindowInfo(winId(), NET::Properties(), NET::WM2Activities).activities();
5672 }
5673 
5674 void KonqMainWindow::setOnActivities(const QStringList& ids) const
5675 {
5676     KX11Extras::setOnActivities(winId(), ids);
5677 }