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 }