diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 108cb97af..83022724b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,127 +1,127 @@ if(BUILD_TESTING) # only with this definition will the KONQ_TESTS_EXPORT macro do something add_definitions(-DBUILD_TESTING) endif(BUILD_TESTING) add_subdirectory( tests ) add_definitions(-DTRANSLATION_DOMAIN=\"konqueror\") if (KActivities_FOUND) include_directories(${KACTIVITIES_INCLUDE_DIRS}) endif (KActivities_FOUND) ########### libkonquerorprivate, shared with unit tests and sidebar modules ############### set(konquerorprivate_SRCS + konqaboutpage.cpp konqhistorymanager.cpp # for unit tests konqpixmapprovider.cpp # needed ?!? # for the sidebar history module konqhistorymodel.cpp ksortfilterproxymodel.cpp konqhistoryproxymodel.cpp konqhistoryview.cpp konqhistorysettings.cpp ) add_library(konquerorprivate SHARED ${konquerorprivate_SRCS}) target_link_libraries(konquerorprivate KF5::IconThemes KF5::Konq KF5::Parts KF5::KIOGui ) if(X11_FOUND) target_link_libraries(konquerorprivate Qt5::X11Extras) endif(X11_FOUND) set_target_properties(konquerorprivate PROPERTIES VERSION ${KONQUEROR_LIB_VERSION} SOVERSION "5" ) install(TARGETS konquerorprivate ${KDE_INSTALL_TARGETS_DEFAULT_ARGS} LIBRARY NAMELINK_SKIP) include(GenerateExportHeader) generate_export_header(konquerorprivate BASE_NAME konquerorprivate EXPORT_FILE_NAME konquerorprivate_export.h) ########### konqueror ############### set(konqueror_KDEINIT_SRCS - konqaboutpage.cpp konqapplication.cpp konqguiclients.cpp konqrun.cpp konqview.cpp konqviewmanager.cpp konqmouseeventfilter.cpp konqmisc.cpp konqdraggablelabel.cpp konqframe.cpp konqframevisitor.cpp konqframestatusbar.cpp konqframecontainer.cpp konqtabs.cpp konqactions.cpp konqsessiondlg.cpp konqfactory.cpp konqcombo.cpp konqbrowseriface.cpp delayedinitializer.cpp konqanimatedlogo.cpp konqmainwindow.cpp konqmainwindowfactory.cpp konqextensionmanager.cpp konqbookmarkbar.cpp konqsettings.cpp KonquerorAdaptor.cpp KonqMainWindowAdaptor.cpp KonqViewAdaptor.cpp konqundomanager.cpp konqclosedwindowsmanager.cpp konqsessionmanager.cpp konqcloseditem.cpp konqhistorydialog.cpp konqstatusbarmessagelabel.cpp ) kconfig_add_kcfg_files(konqueror_KDEINIT_SRCS konqsettingsxt.kcfgc) ki18n_wrap_ui(konqueror_KDEINIT_SRCS konqsessiondlg_base.ui) ki18n_wrap_ui(konqueror_KDEINIT_SRCS konqnewsessiondlg_base.ui) qt5_add_dbus_interface(konqueror_KDEINIT_SRCS org.kde.Konqueror.Main.xml konqueror_interface) qt5_add_dbus_adaptor(konqueror_KDEINIT_SRCS org.kde.Konqueror.UndoManager.xml konqclosedwindowsmanager.h KonqClosedWindowsManager konqclosedwindowsmanageradaptor KonqClosedWindowsManagerAdaptor) qt5_add_dbus_interface(konqueror_KDEINIT_SRCS org.kde.Konqueror.UndoManager.xml konqclosedwindowsmanager_interface) qt5_add_dbus_adaptor(konqueror_KDEINIT_SRCS org.kde.Konqueror.SessionManager.xml konqsessionmanager.h KonqSessionManager konqsessionmanageradaptor KonqSessionManagerAdaptor) qt5_add_dbus_interface(konqueror_KDEINIT_SRCS org.kde.Konqueror.SessionManager.xml konqsessionmanager_interface) file(GLOB ICONS_SRCS "${CMAKE_CURRENT_SOURCE_DIR}/../pics/*-apps-konqueror.png") ecm_add_app_icon(konqueror_KDEINIT_SRCS ICONS ${ICONS_SRCS}) kf5_add_kdeinit_executable(konqueror ${konqueror_KDEINIT_SRCS} konqmain.cpp) target_link_libraries(kdeinit_konqueror konquerorprivate KF5::Archive KF5::KCMUtils KF5::Konq KF5::Parts KF5::DBusAddons KF5::KDELibs4Support KF5::Crash ) if (X11_FOUND) target_link_libraries(kdeinit_konqueror ${X11_LIBRARIES}) endif () if (KActivities_FOUND) target_link_libraries(kdeinit_konqueror ${KACTIVITIES_LIBRARY}) endif (KActivities_FOUND) if (NOT WIN32) install(TARGETS kdeinit_konqueror ${KDE_INSTALL_TARGETS_DEFAULT_ARGS} ) endif (NOT WIN32) install(TARGETS konqueror ${KDE_INSTALL_TARGETS_DEFAULT_ARGS}) ########### install files ############### install( FILES konqueror.kcfg DESTINATION ${KDE_INSTALL_KCFGDIR} ) install( FILES konqueror.rc DESTINATION ${KDE_INSTALL_KXMLGUI5DIR}/konqueror ) install( FILES org.kde.Konqueror.Main.xml org.kde.Konqueror.MainWindow.xml DESTINATION ${KDE_INSTALL_DBUSINTERFACEDIR} ) diff --git a/src/konqaboutpage.cpp b/src/konqaboutpage.cpp index cf65ba062..8d6914207 100644 --- a/src/konqaboutpage.cpp +++ b/src/konqaboutpage.cpp @@ -1,331 +1,336 @@ /* * This file is part of the KDE project * Copyright (C) 2017 David Faure * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "konqaboutpage.h" #include #include #include #include #include #include #include #include KonqAboutPage::KonqAboutPage() { } KonqAboutPage::~KonqAboutPage() { } -QString KonqAboutPage::pageForUrl(const QString &url) const +QString KonqAboutPage::aboutProtocol() { - if (url == QLatin1String("about:plugins")) { + return QStringLiteral("about"); +} + +QString KonqAboutPage::pageContents(const QString &path) const +{ + if (path == QLatin1String("plugins")) { return plugins(); - } else if (url == QLatin1String("about:konqueror/intro")) { + } else if (path == QLatin1String("konqueror/intro")) { return intro(); - } else if (url == QLatin1String("about:konqueror/specs")) { + } else if (path == QLatin1String("konqueror/specs")) { return specs(); - } else if (url == QLatin1String("about:konqueror/tips")) { + } else if (path == QLatin1String("konqueror/tips")) { return tips(); } else { return launch(); } } static QString loadFile(const QString &relativeFile) { const QString file = QStandardPaths::locate(QStandardPaths::GenericDataLocation, relativeFile); if (file.isEmpty()) { qWarning() << "File not found:" << relativeFile; } else { QFile f(file); if (!f.open(QIODevice::ReadOnly)) { qWarning() << "Error opening" << file << ":" << f.errorString(); } else { const QString data = QString::fromLatin1(f.readAll()); return data; } } return {}; } static QString infoPageCssUrl() { return QUrl::fromLocalFile(QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("kf5/infopage/kde_infopage.css"))).toString(); } static QString otherCssImports() { QString imports; if (qApp->layoutDirection() == Qt::RightToLeft) { imports = QStringLiteral("@import \"%1\";").arg(QUrl::fromLocalFile(QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("kf5/infopage/kde_infopage_rtl.css"))).toString()); } imports += QStringLiteral("\n@import \"%1\";").arg(QUrl::fromLocalFile(QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("konqueror/about/konq.css"))).toString()); return imports; } QString KonqAboutPage::launch() const { QString res = loadFile(QStringLiteral("konqueror/about/launch.html")); if (res.isEmpty()) { return res; } KIconLoader *iconloader = KIconLoader::global(); int iconSize = iconloader->currentSize(KIconLoader::Desktop); QString home_icon_path = QUrl::fromLocalFile(iconloader->iconPath(QStringLiteral("user-home"), KIconLoader::Desktop)).toString(); QString remote_icon_path = QUrl::fromLocalFile(iconloader->iconPath(QStringLiteral("folder-remote"), KIconLoader::Desktop)).toString(); QString wastebin_icon_path = QUrl::fromLocalFile(iconloader->iconPath(QStringLiteral("user-trash-full"), KIconLoader::Desktop)).toString(); QString bookmarks_icon_path = QUrl::fromLocalFile(iconloader->iconPath(QStringLiteral("bookmarks"), KIconLoader::Desktop)).toString(); QString home_folder = QUrl::fromLocalFile(QDir::homePath()).toString(); QString continue_icon_path = QUrl::fromLocalFile(iconloader->iconPath(QApplication::isRightToLeft() ? "go-previous" : "go-next", KIconLoader::Small)).toString(); res = res.arg(infoPageCssUrl(), otherCssImports()); res = res.arg(i18nc("KDE 4 tag line, see http://kde.org/img/kde40.png", "Be free.")) .arg(i18n("Konqueror")) .arg(i18nc("KDE 4 tag line, see http://kde.org/img/kde40.png", "Be free.")) .arg(i18n("Konqueror is a web browser, file manager and universal document viewer.")) .arg(i18nc("Link that points to the first page of the Konqueror 'about page', Starting Points contains links to Home, Network Folders, Trash, etc.", "Starting Points")) .arg(i18n("Introduction")) .arg(i18n("Tips")) .arg(i18n("Specifications")) .arg(home_folder) .arg(home_icon_path) .arg(iconSize).arg(iconSize) .arg(home_folder) .arg(i18n("Home Folder")) .arg(i18n("Your personal files")) .arg(wastebin_icon_path) .arg(iconSize).arg(iconSize) .arg(i18n("Trash")) .arg(i18n("Browse and restore the trash")) .arg(remote_icon_path) .arg(iconSize).arg(iconSize) .arg(i18n("Network Folders")) .arg(i18n("Shared files and folders")) .arg(bookmarks_icon_path) .arg(iconSize).arg(iconSize) .arg(i18n("Bookmarks")) .arg(i18n("Quick access to your bookmarks")) .arg(continue_icon_path) .arg(KIconLoader::SizeSmall).arg(KIconLoader::SizeSmall) .arg(i18n("Next: An Introduction to Konqueror")) ; i18n("Search the Web");//i18n for possible future use return res; } QString KonqAboutPage::intro() const { QString res = loadFile(QStringLiteral("konqueror/about/intro.html")); if (res.isEmpty()) { return res; } KIconLoader *iconloader = KIconLoader::global(); QString back_icon_path = QUrl::fromLocalFile(iconloader->iconPath(QApplication::isRightToLeft() ? "go-next" : "go-previous", KIconLoader::Small)).toString(); QString gohome_icon_path = QUrl::fromLocalFile(iconloader->iconPath(QStringLiteral("go-home"), KIconLoader::Small)).toString(); QString continue_icon_path = QUrl::fromLocalFile(iconloader->iconPath(QApplication::isRightToLeft() ? "go-previous" : "go-next", KIconLoader::Small)).toString(); res = res.arg(infoPageCssUrl(), otherCssImports()); res = res.arg(i18nc("KDE 4 tag line, see http://kde.org/img/kde40.png", "Be free.")) .arg(i18n("Konqueror")) .arg(i18nc("KDE 4 tag line, see http://kde.org/img/kde40.png", "Be free.")) .arg(i18n("Konqueror is a web browser, file manager and universal document viewer.")) .arg(i18nc("Link that points to the first page of the Konqueror 'about page', Starting Points contains links to Home, Network Folders, Trash, etc.", "Starting Points")) .arg(i18n("Introduction")) .arg(i18n("Tips")) .arg(i18n("Specifications")) .arg(i18n("Konqueror makes working with and managing your files easy. You can browse " "both local and networked folders while enjoying advanced features " "such as the powerful sidebar and file previews." )) .arg(i18n("Konqueror is also a full featured and easy to use web browser which you " "can use to explore the Internet. " "Enter the address (e.g. http://www.kde.org) " "of a web page you would like to visit in the location bar and press Enter, " "or choose an entry from the Bookmarks menu.")) .arg(i18n("To return to the previous " "location, press the back button " "in the toolbar. ", back_icon_path)) .arg(i18n("To quickly go to your Home folder press the " "home button .", gohome_icon_path)) .arg(i18n("For more detailed documentation on Konqueror click here.", QStringLiteral("exec:/khelpcenter help:/konqueror"))) .arg(QStringLiteral("")).arg(continue_icon_path) .arg(i18n("Next: Tips & Tricks")) ; return res; } QString KonqAboutPage::specs() const { KIconLoader *iconloader = KIconLoader::global(); QString res = loadFile(QStringLiteral("konqueror/about/specs.html")); QString continue_icon_path = QUrl::fromLocalFile(iconloader->iconPath(QApplication::isRightToLeft() ? "go-previous" : "go-next", KIconLoader::Small)).toString(); if (res.isEmpty()) { return res; } res = res.arg(infoPageCssUrl(), otherCssImports()); res = res.arg(i18nc("KDE 4 tag line, see http://kde.org/img/kde40.png", "Be free.")) .arg(i18n("Konqueror")) .arg(i18nc("KDE 4 tag line, see http://kde.org/img/kde40.png", "Be free.")) .arg(i18n("Konqueror is a web browser, file manager and universal document viewer.")) .arg(i18nc("Link that points to the first page of the Konqueror 'about page', Starting Points contains links to Home, Network Folders, Trash, etc.", "Starting Points")) .arg(i18n("Introduction")) .arg(i18n("Tips")) .arg(i18n("Specifications")) .arg(i18n("Specifications")) .arg(i18n("Konqueror is designed to embrace and support Internet standards. " "The aim is to fully implement the officially sanctioned standards " "from organizations such as the W3 and OASIS, while also adding " "extra support for other common usability features that arise as " "de facto standards across the Internet. Along with this support, " "for such functions as favicons, Web Shortcuts, and XBEL bookmarks, " "Konqueror also implements:", QStringLiteral("http://xbel.sourceforge.net/"))) .arg(i18n("Web Browsing")) .arg(i18n("Supported standards")) .arg(i18n("Additional requirements*")) .arg(i18n("DOM (Level 1, partially Level 2) based " "HTML 4.01", QStringLiteral("http://www.w3.org/DOM"), QStringLiteral("http://www.w3.org/TR/html4/"))) .arg(i18n("built-in")) .arg(i18n("Cascading Style Sheets (CSS 1, partially CSS 2)", QStringLiteral("http://www.w3.org/Style/CSS/"))) .arg(i18n("built-in")) .arg(i18n("ECMA-262 Edition 3 (roughly equals JavaScript 1.5)", QStringLiteral("http://www.ecma-international.org/publications/standards/ECMA-262.HTM"))) .arg(i18n("JavaScript disabled (globally). Enable JavaScript here.", QStringLiteral("exec:/kcmshell5 khtml_java_js"))) .arg(i18n("JavaScript enabled (globally). Configure JavaScript here.", QStringLiteral("exec:/kcmshell5 khtml_java_js"))) // leave the double backslashes here, they are necessary for javascript ! .arg(i18n("Secure Java® support", QStringLiteral("http://www.oracle.com/technetwork/java/index.html"))) .arg(i18n("JDK 1.2.0 (Java 2) compatible VM (OpenJDK or Sun/Oracle)", QStringLiteral("http://openjdk.java.net/"), QStringLiteral("http://www.oracle.com/technetwork/java/index.html"))) .arg(i18n("Enable Java (globally) here.", QStringLiteral("exec:/kcmshell5 khtml_java_js"))) // TODO Maybe test if Java is enabled ? .arg(i18n("NPAPI plugins (for viewing Flash®, etc.)", QStringLiteral("https://get.adobe.com/flashplayer/"), - QStringLiteral("about:plugins"))) + aboutProtocol() + QStringLiteral(":plugins"))) .arg(i18n("built-in")) .arg(i18n("Secure Sockets Layer")) .arg(i18n("(TLS/SSL v2/3) for secure communications up to 168bit")) .arg(i18n("OpenSSL")) .arg(i18n("Bidirectional 16bit unicode support")) .arg(i18n("built-in")) .arg(i18n("AutoCompletion for forms")) .arg(i18n("built-in")) .arg(i18nc("Title of an html 'group box' explaining konqueror features", "General")) .arg(i18n("Feature")) .arg(i18n("Details")) .arg(i18n("Image formats")) .arg(i18n("PNG
JPG
GIF")) .arg(i18n("Transfer protocols")) .arg(i18n("HTTP 1.1 (including gzip/bzip2 compression)")) .arg(i18n("FTP")) .arg(i18n("and many more (see Kioslaves in KHelpCenter)...", QStringLiteral("exec:/khelpcenter"))) .arg(i18nc("A feature of Konqueror", "URL-Completion")) .arg(i18n("Manual")) .arg(i18n("Popup")) .arg(i18n("(Short-) Automatic")) .arg(QStringLiteral("")).arg(continue_icon_path) - .arg(i18nc("Link that points to the first page of the Konqueror 'about page', Starting Points contains links to Home, Network Folders, Trash, etc.", "Return to Starting Points", QStringLiteral("about:konqueror"))) + .arg(i18nc("Link that points to the first page of the Konqueror 'about page', Starting Points contains links to Home, Network Folders, Trash, etc.", "Return to Starting Points", aboutProtocol() + QStringLiteral(":konqueror"))) ; return res; } QString KonqAboutPage::tips() const { QString res = loadFile(QStringLiteral("konqueror/about/tips.html")); if (res.isEmpty()) { return res; } KIconLoader *iconloader = KIconLoader::global(); QString viewmag_icon_path = QUrl::fromLocalFile(iconloader->iconPath(QStringLiteral("format-font-size-more"), KIconLoader::Small)).toString(); QString history_icon_path = QUrl::fromLocalFile(iconloader->iconPath(QStringLiteral("view-history"), KIconLoader::Small)).toString(); QString openterm_icon_path = QUrl::fromLocalFile(iconloader->iconPath(QStringLiteral("utilities-terminal"), KIconLoader::Small)).toString(); QString locationbar_erase_rtl_icon_path = QUrl::fromLocalFile(iconloader->iconPath(QStringLiteral("edit-clear-locationbar-ltr"), KIconLoader::Small)).toString(); QString locationbar_erase_icon_path = QUrl::fromLocalFile(iconloader->iconPath(QStringLiteral("edit-clear-locationbar-rtl"), KIconLoader::Small)).toString(); QString window_fullscreen_icon_path = QUrl::fromLocalFile(iconloader->iconPath(QStringLiteral("view-fullscreen"), KIconLoader::Small)).toString(); QString view_left_right_icon_path = QUrl::fromLocalFile(iconloader->iconPath(QStringLiteral("view-split-left-right"), KIconLoader::Small)).toString(); QString continue_icon_path = QUrl::fromLocalFile(iconloader->iconPath(QApplication::isRightToLeft() ? "go-previous" : "go-next", KIconLoader::Small)).toString(); res = res.arg(infoPageCssUrl(), otherCssImports()); res = res.arg(i18nc("KDE 4 tag line, see http://kde.org/img/kde40.png", "Be free.")) .arg(i18n("Konqueror")) .arg(i18nc("KDE 4 tag line, see http://kde.org/img/kde40.png", "Be free.")) .arg(i18n("Konqueror is a web browser, file manager and universal document viewer.")) .arg(i18nc("Link that points to the first page of the Konqueror 'about page', Starting Points contains links to Home, Network Folders, Trash, etc.", "Starting Points")) .arg(i18n("Introduction")) .arg(i18n("Tips")) .arg(i18n("Specifications")) .arg(i18n("Tips & Tricks")) .arg(i18n("Use Web-Shortcuts: by typing \"gg: KDE\" one can search the Internet, " "using Google, for the search phrase \"KDE\". There are a lot of " "Web-Shortcuts predefined to make searching for software or looking " "up certain words in an encyclopedia a breeze. You can even " "create your own Web-Shortcuts.", QStringLiteral("exec:/kcmshell5 webshortcuts"))) .arg(i18n("Use the magnifier button in the HTML" " toolbar to increase the font size on your web page.", viewmag_icon_path)) .arg(i18n("When you want to paste a new address into the Location toolbar you might want to " "clear the current entry by pressing the black arrow with the white cross " " in the toolbar.", QApplication::isRightToLeft() ? locationbar_erase_rtl_icon_path : locationbar_erase_icon_path)) .arg(i18n("To create a link on your desktop pointing to the current page, " "simply drag the icon (favicon) that is to the left of the Location toolbar, drop it on to " "the desktop, and choose \"Icon\".")) .arg(i18n("You can also find \"Full-Screen Mode\" " "in the Settings menu. This feature is very useful for \"Talk\" " "sessions.", window_fullscreen_icon_path)) .arg(i18n("Divide et impera (lat. \"Divide and conquer\") - by splitting a window " "into two parts (e.g. Window -> Split View " "Left/Right) you can make Konqueror appear the way you like.", view_left_right_icon_path)) .arg(i18n("Use the user-agent feature if the website you are visiting " "asks you to use a different browser " "(and do not forget to send a complaint to the webmaster!)", QStringLiteral("exec:/kcmshell5 useragent"))) .arg(i18n("The History in your Sidebar ensures " "that you can keep track of the pages you have visited recently.", history_icon_path)) .arg(i18n("Use a caching proxy to speed up your" " Internet connection.", QStringLiteral("exec:/kcmshell5 proxy"))) .arg(i18n("Advanced users will appreciate the Konsole which you can embed into " "Konqueror (Settings -> Show " "Terminal Emulator).", openterm_icon_path)) .arg(QStringLiteral("")).arg(continue_icon_path) .arg(i18n("Next: Specifications")) ; return res; } QString KonqAboutPage::plugins() const { QString res = loadFile(qApp->layoutDirection() == Qt::RightToLeft ? "konqueror/about/plugins_rtl.html" : "konqueror/about/plugins.html") .arg(i18n("Installed Plugins")) .arg(i18n("PluginDescriptionFileTypes")) .arg(i18n("Installed")) .arg(i18n("Mime TypeDescriptionSuffixesPlugin")); return res; } diff --git a/src/konqaboutpage.h b/src/konqaboutpage.h index a95fd44e7..d2fa74f4b 100644 --- a/src/konqaboutpage.h +++ b/src/konqaboutpage.h @@ -1,43 +1,46 @@ /* * This file is part of the KDE project * Copyright (C) 2017 David Faure * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KONQ_ABOUTPAGE_H #define KONQ_ABOUTPAGE_H +#include #include class QUrl; -class KonqAboutPage +class KONQUERORPRIVATE_EXPORT KonqAboutPage { public: KonqAboutPage(); ~KonqAboutPage(); - QString pageForUrl(const QString &url) const; + static QString aboutProtocol(); + + QString pageContents(const QString &path) const; private: QString launch() const; QString intro() const; QString specs() const; QString tips() const; QString plugins() const; }; #endif diff --git a/src/konqhistorymanager.cpp b/src/konqhistorymanager.cpp index 951d54905..b7370f2d0 100644 --- a/src/konqhistorymanager.cpp +++ b/src/konqhistorymanager.cpp @@ -1,283 +1,284 @@ /* This file is part of the KDE project Copyright (C) 2000,2001 Carsten Pfeiffer Copyright 2007 David Faure This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "konqhistorymanager.h" #include +#include "konqaboutpage.h" #include #include #include #include #include #include KonqHistoryManager::KonqHistoryManager(KBookmarkManager *bookmarkManager, QObject *parent) : KonqHistoryProvider(parent), m_bookmarkManager(bookmarkManager) { m_updateTimer = new QTimer(this); // take care of the completion object m_pCompletion = new KCompletion; m_pCompletion->setOrder(KCompletion::Weighted); // and load the history loadHistory(); connect(m_updateTimer, &QTimer::timeout, this, &KonqHistoryManager::slotEmitUpdated); connect(this, &KonqHistoryManager::cleared, this, &KonqHistoryManager::slotCleared); connect(this, &KonqHistoryManager::entryRemoved, this, &KonqHistoryManager::slotEntryRemoved); } KonqHistoryManager::~KonqHistoryManager() { delete m_pCompletion; clearPending(); } bool KonqHistoryManager::loadHistory() { clearPending(); m_pCompletion->clear(); if (!KonqHistoryProvider::loadHistory()) { return false; } QListIterator it(entries()); while (it.hasNext()) { const KonqHistoryEntry &entry = it.next(); const QString prettyUrlString = entry.url.toDisplayString(); addToCompletion(prettyUrlString, entry.typedUrl, entry.numberOfTimesVisited); } return true; } void KonqHistoryManager::addPending(const QUrl &url, const QString &typedUrl, const QString &title) { addToHistory(true, url, typedUrl, title); } void KonqHistoryManager::confirmPending(const QUrl &url, const QString &typedUrl, const QString &title) { addToHistory(false, url, typedUrl, title); } void KonqHistoryManager::addToHistory(bool pending, const QUrl &_url, const QString &typedUrl, const QString &title) { //qDebug() << _url << "Typed URL:" << typedUrl << ", Title:" << title; if (filterOut(_url)) { // we only want remote URLs return; } // http URLs without a path will get redirected immediately to url + '/' if (_url.path().isEmpty() && _url.scheme().startsWith(QLatin1String("http"))) { return; } QUrl url(_url); bool hasPass = !url.password().isEmpty(); url.setPassword(QString()); // No password in the history, especially not in the completion! url.setHost(url.host().toLower()); // All host parts lower case KonqHistoryEntry entry; QString u = url.toDisplayString(); entry.url = url; if ((u != typedUrl) && !hasPass) { entry.typedUrl = typedUrl; } // we only keep the title if we are confirming an entry. Otherwise, // we might get bogus titles from the previous url (actually it's just // konqueror's window caption). if (!pending && u != title) { entry.title = title; } entry.firstVisited = QDateTime::currentDateTime(); entry.lastVisited = entry.firstVisited; // always remove from pending if available, otherwise the else branch leaks // if the map already contains an entry for this key. QMap::iterator it = m_pending.find(u); if (it != m_pending.end()) { delete it.value(); m_pending.erase(it); } if (!pending) { if (it != m_pending.end()) { // we make a pending entry official, so we just have to update // and not increment the counter. No need to care about // firstVisited, as this is not taken into account on update. entry.numberOfTimesVisited = 0; } } else { // We add a copy of the current history entry of the url to the // pending list, so that we can restore it if the user canceled. // If there is no entry for the url yet, we just store the url. KonqHistoryList::const_iterator oldEntry = constFindEntry(url); m_pending.insert(u, (oldEntry != entries().constEnd()) ? new KonqHistoryEntry(*oldEntry) : 0); } // notify all konqueror instances about the entry emitAddToHistory(entry); } // interface of KParts::HistoryManager // Usually, we only record the history for non-local URLs (i.e. filterOut() // returns false). But when using the HistoryProvider interface, we record // exactly those filtered-out urls. // Moreover, we don't get any pending/confirming entries, just one insert() void KonqHistoryManager::insert(const QString &url) { QUrl u(url); - if (!filterOut(u) || u.scheme() == QLatin1String("about")) { // remote URL + if (!filterOut(u) || u.scheme() == KonqAboutPage::aboutProtocol()) { // remote URL return; } // Local URL -> add to history KonqHistoryEntry entry; entry.url = u; entry.firstVisited = QDateTime::currentDateTime(); entry.lastVisited = entry.firstVisited; emitAddToHistory(entry); } void KonqHistoryManager::removePending(const QUrl &url) { // qDebug() << "Removing pending..." << url; if (url.isLocalFile()) { return; } QMap::iterator it = m_pending.find(url.toDisplayString()); if (it != m_pending.end()) { KonqHistoryEntry *oldEntry = it.value(); // the old entry, may be 0 emitRemoveFromHistory(url); // remove the current pending entry if (oldEntry) { // we had an entry before, now use that instead emitAddToHistory(*oldEntry); } delete oldEntry; m_pending.erase(it); } } // clears the pending list and makes sure the entries get deleted. void KonqHistoryManager::clearPending() { QMap::iterator it = m_pending.begin(); while (it != m_pending.end()) { delete it.value(); ++it; } m_pending.clear(); } /////////////////////////////////////////////////////////////////// // DBUS called methods bool KonqHistoryManager::filterOut(const QUrl &url) { return (url.isLocalFile() || url.host().isEmpty()); } void KonqHistoryManager::slotEmitUpdated() { emit KParts::HistoryProvider::updated(m_updateURLs); m_updateURLs.clear(); } #if 0 // unused QStringList KonqHistoryManager::allURLs() const { QStringList list; QListIterator it(entries()); while (it.hasNext()) { list.append(it.next().url.url()); } return list; } #endif void KonqHistoryManager::addToCompletion(const QString &url, const QString &typedUrl, int numberOfTimesVisited) { m_pCompletion->addItem(url, numberOfTimesVisited); // typed urls have a higher priority m_pCompletion->addItem(typedUrl, numberOfTimesVisited + 10); } void KonqHistoryManager::removeFromCompletion(const QString &url, const QString &typedUrl) { m_pCompletion->removeItem(url); m_pCompletion->removeItem(typedUrl); } void KonqHistoryManager::addToUpdateList(const QString &url) { m_updateURLs.append(url); m_updateTimer->setSingleShot(true); m_updateTimer->start(500); } // Called by KonqHistoryProviderPrivate::slotNotifyClear() void KonqHistoryManager::slotCleared() { clearPending(); m_pCompletion->clear(); } void KonqHistoryManager::finishAddingEntry(const KonqHistoryEntry &entry, bool isSender) { const QString urlString = entry.url.url(); addToCompletion(entry.url.toDisplayString(), entry.typedUrl); addToUpdateList(urlString); KonqHistoryProvider::finishAddingEntry(entry, isSender); // note, no need to do the updateBookmarkMetadata for every // history object, only need to for the broadcast sender as // the history object itself keeps the data consistant. // ### why does the comment do exactly the opposite from the code? const bool updated = m_bookmarkManager ? m_bookmarkManager->updateAccessMetadata(urlString) : false; if (isSender) { // note, bk save does not notify, and we don't want to! if (updated) { m_bookmarkManager->save(); } } } void KonqHistoryManager::slotEntryRemoved(const KonqHistoryEntry &entry) { const QString urlString = entry.url.url(); removeFromCompletion(entry.url.toDisplayString(), entry.typedUrl); addToUpdateList(urlString); } diff --git a/src/konqmainwindow.cpp b/src/konqmainwindow.cpp index d7af0cdba..cc40a8a6f 100644 --- a/src/konqmainwindow.cpp +++ b/src/konqmainwindow.cpp @@ -1,5534 +1,5534 @@ /* This file is part of the KDE project Copyright (C) 1998, 1999 Simon Hausmann Copyright (C) 2000 Carsten Pfeiffer Copyright (C) 2000-2005 David Faure Copyright (C) 2007 Eduardo Robles Elvira Copyright (C) 2007 Daniel GarcĂ­a Moreno This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "konqmainwindow.h" #include "konqmouseeventfilter.h" #include "konqclosedwindowsmanager.h" #include "konqsessionmanager.h" #include "konqsessiondlg.h" #include "konqdraggablelabel.h" #include "konqcloseditem.h" #include "konqapplication.h" #include "konqguiclients.h" #include "konqmainwindowfactory.h" #include "KonqMainWindowAdaptor.h" #include "KonquerorAdaptor.h" #include "konqview.h" #include "konqrun.h" #include "konqmisc.h" #include "konqviewmanager.h" #include "konqframestatusbar.h" #include "konqtabs.h" #include "konqactions.h" #include "konqsettingsxt.h" #include "konqextensionmanager.h" #include "konqueror_interface.h" #include "delayedinitializer.h" #include "konqextendedbookmarkowner.h" #include "konqframevisitor.h" #include "konqbookmarkbar.h" #include "konqundomanager.h" #include "konqhistorydialog.h" +#include "konqaboutpage.h" #include #include #include #include #include #include #include #include #include #include // we define STRICT_ANSI to get rid of some warnings in glibc #ifndef __STRICT_ANSI__ #define __STRICT_ANSI__ #define _WE_DEFINED_IT_ #endif #include #ifdef _WE_DEFINED_IT_ #undef __STRICT_ANSI__ #undef _WE_DEFINED_IT_ #endif #include #include #include #include #include #include #include #include #include #include #include #include #if KONQ_HAVE_X11 #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "konqsettings.h" #include "konqanimatedlogo_p.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include template class QList; template class QList; static KBookmarkManager *s_bookmarkManager = 0; QList *KonqMainWindow::s_lstMainWindows = 0; KConfig *KonqMainWindow::s_comboConfig = 0; KCompletion *KonqMainWindow::s_pCompletion = 0; KonqOpenURLRequest KonqOpenURLRequest::null; static const unsigned short int s_closedItemsListLength = 10; static void raiseWindow(KonqMainWindow *window) { if (!window) { return; } if (window->isMinimized()) { KWindowSystem::unminimizeWindow(window->winId()); } window->activateWindow(); window->raise(); } KonqExtendedBookmarkOwner::KonqExtendedBookmarkOwner(KonqMainWindow *w) { m_pKonqMainWindow = w; } KonqMainWindow::KonqMainWindow(const QUrl &initialURL) : KParts::MainWindow() , m_paClosedItems(0) , m_fullyConstructed(false) , m_bLocationBarConnected(false) , m_bURLEnterLock(false) , m_urlCompletionStarted(false) , m_prevMenuBarVisible(true) , m_goBuffer(0) , m_pBookmarkMenu(0) , m_configureDialog(0) , m_pURLCompletion(0) , m_isPopupWithProxyWindow(false) { if (!s_lstMainWindows) { s_lstMainWindows = new QList; } s_lstMainWindows->append(this); KonqMouseEventFilter::self(); // create it m_pChildFrame = 0; m_pActiveChild = 0; m_workingTab = 0; (void) new KonqMainWindowAdaptor(this); m_paBookmarkBar = 0; m_viewModesGroup = new QActionGroup(this); m_viewModesGroup->setExclusive(true); connect(m_viewModesGroup, SIGNAL(triggered(QAction*)), this, SLOT(slotViewModeTriggered(QAction*)), Qt::QueuedConnection); // Queued so that we don't delete the action from the code that triggered it. // This has to be called before any action is created for this mainwindow setComponentData(KComponentData::mainComponent(), false /*don't load plugins yet*/); m_pViewManager = new KonqViewManager(this); m_viewModeMenu = 0; m_openWithMenu = 0; m_paCopyFiles = 0; m_paMoveFiles = 0; m_bookmarkBarInitialized = false; m_toggleViewGUIClient = new ToggleViewGUIClient(this); m_pBookmarksOwner = new KonqExtendedBookmarkOwner(this); // init history-manager, load history, get completion object if (!s_pCompletion) { s_bookmarkManager = KBookmarkManager::userBookmarksManager(); // let the KBookmarkManager know that we are a browser, equals to "keditbookmarks --browser" s_bookmarkManager->setEditorOptions(QStringLiteral("konqueror"), true); KonqHistoryManager *mgr = new KonqHistoryManager(s_bookmarkManager); s_pCompletion = mgr->completionObject(); // setup the completion object before createGUI(), so that the combo // picks up the correct mode from the HistoryManager (in slotComboPlugged) int mode = KonqSettings::settingsCompletionMode(); s_pCompletion->setCompletionMode(static_cast(mode)); } connect(KParts::HistoryProvider::self(), &KParts::HistoryProvider::cleared, this, &KonqMainWindow::slotClearComboHistory); KonqPixmapProvider *prov = KonqPixmapProvider::self(); if (!s_comboConfig) { s_comboConfig = new KConfig(QStringLiteral("konq_history"), KConfig::NoGlobals); KonqCombo::setConfig(s_comboConfig); KConfigGroup locationBarGroup(s_comboConfig, "Location Bar"); prov->load(locationBarGroup, QStringLiteral("ComboIconCache")); } connect(prov, SIGNAL(changed()), SLOT(slotIconsChanged())); m_pUndoManager = new KonqUndoManager(this); connect(m_pUndoManager, SIGNAL(undoAvailable(bool)), this, SLOT(slotUndoAvailable(bool))); initCombo(); initActions(); connect(KGlobalSettings::self(), &KGlobalSettings::kdisplayFontChanged, this, &KonqMainWindow::slotReconfigure); setXMLFile(QStringLiteral("konqueror.rc")); setStandardToolBarMenuEnabled(true); createGUI(Q_NULLPTR); m_combo->setParent(toolBar(QStringLiteral("locationToolBar"))); m_combo->setFont(QFontDatabase::systemFont(QFontDatabase::GeneralFont)); m_combo->show(); checkDisableClearButton(); connect(toolBarMenuAction(), SIGNAL(triggered()), this, SLOT(slotForceSaveMainWindowSettings())); if (!m_toggleViewGUIClient->empty()) { plugActionList(QStringLiteral("toggleview"), m_toggleViewGUIClient->actions()); } else { delete m_toggleViewGUIClient; m_toggleViewGUIClient = 0; } m_bNeedApplyKonqMainWindowSettings = true; if (!initialURL.isEmpty()) { openFilteredUrl(initialURL.url()); } else { // silent m_bNeedApplyKonqMainWindowSettings = false; } resize(700, 480); setAutoSaveSettings(); //qDebug() << this << "created"; KonqSessionManager::self(); m_fullyConstructed = true; } KonqMainWindow::~KonqMainWindow() { //qDebug() << this; delete m_pViewManager; m_pViewManager = 0; if (s_lstMainWindows) { s_lstMainWindows->removeAll(this); if (s_lstMainWindows->isEmpty()) { delete s_lstMainWindows; s_lstMainWindows = 0; } } qDeleteAll(m_openWithActions); m_openWithActions.clear(); delete m_pBookmarkMenu; delete m_paBookmarkBar; delete m_pBookmarksOwner; delete m_pURLCompletion; delete m_paClosedItems; if (s_lstMainWindows == 0) { delete s_comboConfig; s_comboConfig = 0; } delete m_configureDialog; m_configureDialog = 0; delete m_combo; m_combo = 0; delete m_locationLabel; m_locationLabel = 0; m_pUndoManager->disconnect(); delete m_pUndoManager; //qDebug() << this << "deleted"; } QWidget *KonqMainWindow::createContainer(QWidget *parent, int index, const QDomElement &element, QAction *&containerAction) { QWidget *res = KParts::MainWindow::createContainer(parent, index, element, containerAction); static QString nameBookmarkBar = QStringLiteral("bookmarkToolBar"); static QString tagToolBar = QStringLiteral("ToolBar"); if (res && (element.tagName() == tagToolBar) && (element.attribute(QStringLiteral("name")) == nameBookmarkBar)) { Q_ASSERT(::qobject_cast(res)); if (!KAuthorized::authorizeAction(QStringLiteral("bookmarks"))) { delete res; return 0; } if (!m_bookmarkBarInitialized) { // The actual menu needs a different action collection, so that the bookmarks // don't appear in kedittoolbar m_bookmarkBarInitialized = true; DelayedInitializer *initializer = new DelayedInitializer(QEvent::Show, res); connect(initializer, &DelayedInitializer::initialize, this, &KonqMainWindow::initBookmarkBar); } } if (res && element.tagName() == QLatin1String("Menu")) { const QString &menuName = element.attribute(QStringLiteral("name")); if (menuName == QLatin1String("edit") || menuName == QLatin1String("tools")) { Q_ASSERT(qobject_cast(res)); KAcceleratorManager::manage(static_cast(res)); } } return res; } void KonqMainWindow::initBookmarkBar() { KToolBar *bar = qFindChild(this, QStringLiteral("bookmarkToolBar")); if (!bar) { return; } const bool wasVisible = bar->isVisible(); delete m_paBookmarkBar; m_paBookmarkBar = new KBookmarkBar(s_bookmarkManager, m_pBookmarksOwner, bar, this); // hide if empty if (bar->actions().count() == 0 || !wasVisible) { bar->hide(); } } void KonqMainWindow::removeContainer(QWidget *container, QWidget *parent, QDomElement &element, QAction *containerAction) { static QString nameBookmarkBar = QStringLiteral("bookmarkToolBar"); static QString tagToolBar = QStringLiteral("ToolBar"); if (element.tagName() == tagToolBar && element.attribute(QStringLiteral("name")) == nameBookmarkBar) { Q_ASSERT(::qobject_cast(container)); if (m_paBookmarkBar) { m_paBookmarkBar->clear(); } } KParts::MainWindow::removeContainer(container, parent, element, containerAction); } // Detect a name filter (e.g. *.txt) in the url. // Note that KShortURIFilter does the same, but we have no way of getting it from there // // Note: this removes the filter from the URL. QString KonqMainWindow::detectNameFilter(QUrl &url) { if (!KProtocolManager::supportsListing(url)) { return QString(); } // Look for wildcard selection QString nameFilter; QString path = url.path(); int lastSlash = path.lastIndexOf('/'); if (lastSlash > -1) { if (!url.query().isEmpty() && lastSlash == path.length() - 1) { // In /tmp/?foo, foo isn't a query path += url.query(); // includes the '?' } QString fileName = path.mid(lastSlash + 1); if (fileName.indexOf('*') != -1 || fileName.indexOf('[') != -1 || fileName.indexOf('?') != -1) { // Check that a file or dir with all the special chars in the filename doesn't exist // (NetAccess::exists has a fast path for local files) if (!KIO::NetAccess::exists(url, KIO::NetAccess::DestinationSide, this)) { nameFilter = fileName; url = url.adjusted(QUrl::RemoveFilename | QUrl::RemoveQuery); qDebug() << "Found wildcard. nameFilter=" << nameFilter << " New url=" << url; } } } return nameFilter; } void KonqMainWindow::openFilteredUrl(const QString &url, const KonqOpenURLRequest &req) { // Filter URL to build a correct one if (m_currentDir.isEmpty() && m_currentView) { m_currentDir = m_currentView->url(); } QUrl filteredURL(KonqMisc::konqFilteredURL(this, url, m_currentDir)); qDebug() << "url" << url << "filtered into" << filteredURL; if (filteredURL.isEmpty()) { // initially empty, or error (e.g. ~unknown_user) return; } m_currentDir.clear(); openUrl(0, filteredURL, QString(), req); // #4070: Give focus to view after URL was entered manually // Note: we do it here if the view mode (i.e. part) wasn't changed // If it is changed, then it's done in KonqViewManager::doSetActivePart if (m_currentView) { m_currentView->setFocus(); } } void KonqMainWindow::openFilteredUrl(const QString &_url, bool inNewTab, bool tempFile) { KonqOpenURLRequest req(_url); req.browserArgs.setNewTab(inNewTab); req.newTabInFront = true; req.tempFile = tempFile; openFilteredUrl(_url, req); } void KonqMainWindow::openFilteredUrl(const QString &_url, const QString &_mimeType, bool inNewTab, bool tempFile) { KonqOpenURLRequest req(_url); req.browserArgs.setNewTab(inNewTab); req.newTabInFront = true; req.tempFile = tempFile; req.args.setMimeType(_mimeType); openFilteredUrl(_url, req); } void KonqMainWindow::openUrl(KonqView *_view, const QUrl &_url, const QString &_mimeType, const KonqOpenURLRequest &_req, bool trustedSource) { #ifndef NDEBUG // needed for req.debug() qDebug() << "url=" << _url << "mimeType=" << _mimeType << "_req=" << _req.debug() << "view=" << _view; #endif // We like modifying args in this method :) QUrl url(_url); QString mimeType(_mimeType); KonqOpenURLRequest req(_req); if (mimeType.isEmpty()) { mimeType = req.args.mimeType(); } - if (url.scheme() != QLatin1String("error") && url.scheme() != QLatin1String("about")) { + if (url.scheme() != QLatin1String("error") && url.scheme() != KonqAboutPage::aboutProtocol()) { if (!url.isValid()) { // I think we can't really get here anymore; I tried and didn't succeed. // URL filtering catches this case before hand, and in cases without filtering // (e.g. HTML link), the url is empty here, not invalid. // But just to be safe, let's keep this code path url = KParts::BrowserRun::makeErrorUrl(KIO::ERR_MALFORMED_URL, url.url(), url); } else if (!KProtocolInfo::isKnownProtocol(url)) { url = KParts::BrowserRun::makeErrorUrl(KIO::ERR_UNSUPPORTED_PROTOCOL, url.scheme(), url); } } - if (url.scheme() == QLatin1String("about") || url.scheme() == QLatin1String("error")) { + if (url.scheme() == KonqAboutPage::aboutProtocol() || url.scheme() == QLatin1String("error")) { mimeType = QStringLiteral("text/html"); } const QString nameFilter = detectNameFilter(url); if (!nameFilter.isEmpty()) { req.nameFilter = nameFilter; url = url.adjusted(QUrl::RemoveFilename); } QLineEdit *edit = comboEdit(); if (edit) { edit->setModified(false); } KonqView *view = _view; // When clicking a 'follow active' view (e.g. view is the sidebar), // open the URL in the active view if (view && view->isFollowActive()) { view = m_currentView; } if (!view && !req.browserArgs.newTab()) { view = m_currentView; /* Note, this can be 0, e.g. on startup */ } else if (!view && req.browserArgs.newTab()) { // The URL should be opened in a new tab. Let's create the tab right away, // it gives faster user feedback (#163628). For a short while (kde-4.1-beta1) // I removed this entire block so that we wouldn't end up with a useless tab when // launching an external application for this mimetype. But user feedback // in all cases is more important than empty tabs in some cases. view = m_pViewManager->addTab(QStringLiteral("text/html"), QString(), false, req.openAfterCurrentPage); if (view) { view->setCaption(i18nc("@title:tab", "Loading...")); view->setLocationBarURL(_url); if (!req.browserArgs.frameName.isEmpty()) { view->setViewName(req.browserArgs.frameName); // #44961 } if (req.newTabInFront) { m_pViewManager->showTab(view); } updateViewActions(); //A new tab created -- we may need to enable the "remove tab" button (#56318) } else { req.browserArgs.setNewTab(false); } } const QString oldLocationBarURL = locationBarURL(); if (view) { if (view == m_currentView) { //will do all the stuff below plus GUI stuff abortLoading(); } else { view->stop(); // Don't change location bar if not current view } } // Fast mode for local files: do the stat ourselves instead of letting KRun do it. if (mimeType.isEmpty() && url.isLocalFile()) { QMimeDatabase db; mimeType = db.mimeTypeForFile(url.toLocalFile()).name(); } if (url.isLocalFile()) { // Generic mechanism for redirecting to tar:// when clicking on a tar file, // zip:// when clicking on a zip file, etc. // The .protocol file specifies the mimetype that the kioslave handles. // Note that we don't use mimetype inheritance since we don't want to // open OpenDocument files as zip folders... // Also note that we do this here and not in openView anymore, // because in the case of foo.bz2 we don't know the final mimetype, we need a konqrun... const QString protocol = KProtocolManager::protocolForArchiveMimetype(mimeType); if (!protocol.isEmpty() && KonqFMSettings::settings()->shouldEmbed(mimeType)) { url.setScheme(protocol); if (mimeType == QLatin1String("application/x-webarchive")) { url.setPath(url.path() + "/index.html"); mimeType = QStringLiteral("text/html"); } else { if (KProtocolManager::outputType(url) == KProtocolInfo::T_FILESYSTEM) { if (!url.path().endsWith('/')) { url.setPath(url.path() + '/'); } mimeType = QStringLiteral("inode/directory"); } else { mimeType.clear(); } } } // Redirect to the url in Type=Link desktop files if (mimeType == QLatin1String("application/x-desktop")) { KDesktopFile df(url.toLocalFile()); if (df.hasLinkType()) { url = QUrl(df.readUrl()); mimeType.clear(); // to be determined again } } } const bool hasMimeType = (!mimeType.isEmpty() && mimeType != QLatin1String("application/octet-stream")); KService::Ptr offer; bool associatedAppIsKonqueror = false; if (hasMimeType) { offer = KMimeTypeTrader::self()->preferredService(mimeType, QStringLiteral("Application")); associatedAppIsKonqueror = isMimeTypeAssociatedWithSelf(mimeType, offer); // If the associated app is konqueror itself, then make sure we try to embed before bailing out. if (associatedAppIsKonqueror) { req.forceAutoEmbed = true; } } //qDebug() << "trying openView for" << url << "( mimeType" << mimeType << ")"; if (hasMimeType) { // Built-in view ? if (!openView(mimeType, url, view /* can be 0 */, req)) { //qDebug() << "openView returned false"; // Are we following another view ? Then forget about this URL. Otherwise fire app. if (!req.followMode) { //qDebug() << "we were not following. Fire app."; // The logic below is similar to BrowserRun::handleNonEmbeddable(), // but we don't have a BrowserRun instance here, and since it uses // some virtual methods [like save, for KHTMLRun], we can't just // move all the logic to static methods... catch 22... if (!url.isLocalFile() && !trustedSource && KonqRun::isTextExecutable(mimeType)) { mimeType = QStringLiteral("text/plain"); // view, don't execute } // Remote URL: save or open ? QString protClass = KProtocolInfo::protocolClass(url.scheme()); bool open = url.isLocalFile() || protClass == QLatin1String(":local") || KProtocolInfo::isHelperProtocol(url); if (!open) { KParts::BrowserOpenOrSaveQuestion dlg(this, url, mimeType); dlg.setFeatures(KParts::BrowserOpenOrSaveQuestion::ServiceSelection); const KParts::BrowserOpenOrSaveQuestion::Result res = dlg.askOpenOrSave(); if (res == KParts::BrowserOpenOrSaveQuestion::Save) { KParts::BrowserRun::saveUrl(url, QString(), this, req.args); } open = (res == KParts::BrowserOpenOrSaveQuestion::Open); if (open) { offer = dlg.selectedService(); } } if (open) { if (associatedAppIsKonqueror && refuseExecutingKonqueror(mimeType)) { return; } QList lst; lst.append(url); //qDebug() << "Got offer" << (offer ? offer->name() : QString("0")); const bool allowExecution = trustedSource || KParts::BrowserRun::allowExecution(mimeType, url); if (allowExecution) { const bool isExecutable = KonqRun::isExecutable(mimeType); // Open with no offer means the user clicked on "Open With..." button. if (!offer && !isExecutable) { (void) KRun::displayOpenWithDialog(lst, this); } else if (isExecutable || !KRun::runApplication(*offer, lst, this)) { setLocationBarURL(oldLocationBarURL); // Revert to previous locationbar URL (void)new KRun(url, this); } } } } } } else { // no known mimeType, use KonqRun bool earlySetLocationBarURL = false; if (!view && !m_currentView) { // no view yet, e.g. starting with url as argument earlySetLocationBarURL = true; } else if (view == m_currentView && view->url().isEmpty()) { // opening in current view earlySetLocationBarURL = true; } if (req.browserArgs.newTab()) { // it's going into a new tab anyway earlySetLocationBarURL = false; } if (earlySetLocationBarURL) { // Show it for now in the location bar, but we'll need to store it in the view // later on (can't do it yet since either view == 0 or updateHistoryEntry will be called). qDebug() << "url=" << url; setLocationBarURL(url); } qDebug() << "Creating new konqrun for" << url << "req.typedUrl=" << req.typedUrl; KonqRun *run = new KonqRun(this, view /* can be 0 */, url, req, trustedSource); // Never start in external browser run->setEnableExternalBrowser(false); if (view) { view->setRun(run); } if (view == m_currentView) { startAnimation(); } connect(run, &KonqRun::finished, this, &KonqMainWindow::slotRunFinished); } } // When opening a new view, for @p mimeType, prefer the part used in @p currentView, if possible. // Testcase: window.open after manually switching to another web engine, and with "open popups in tabs" off. static QString preferredService(KonqView *currentView, const QString &mimeType) { if (currentView && !mimeType.isEmpty() && currentView->supportsMimeType(mimeType)) { return currentView->service()->desktopEntryName(); } return QString(); } bool KonqMainWindow::openView(QString mimeType, const QUrl &_url, KonqView *childView, const KonqOpenURLRequest &req) { // Second argument is referring URL if (!KUrlAuthorized::authorizeUrlAction(QStringLiteral("open"), childView ? childView->url() : QUrl(), _url)) { QString msg = KIO::buildErrorString(KIO::ERR_ACCESS_DENIED, _url.toDisplayString()); QMessageBox::warning(this, i18n("Access denied"), msg); return true; // Nothing else to do. } if (KonqRun::isExecutable(mimeType)) { return false; // execute, don't open } // Contract: the caller of this method should ensure the view is stopped first. #ifndef NDEBUG qDebug() << mimeType << _url << "childView=" << childView << "req:" << req.debug(); #endif bool bOthersFollowed = false; if (childView) { // If we're not already following another view (and if we are not reloading) if (!req.followMode && !req.args.reload() && !m_pViewManager->isLoadingProfile()) { // When clicking a 'follow active' view (e.g. childView is the sidebar), // open the URL in the active view // (it won't do anything itself, since it's locked to its location) if (childView->isFollowActive() && childView != m_currentView) { abortLoading(); setLocationBarURL(_url); KonqOpenURLRequest newreq; newreq.forceAutoEmbed = true; newreq.followMode = true; newreq.args = req.args; newreq.browserArgs = req.browserArgs; bOthersFollowed = openView(mimeType, _url, m_currentView, newreq); } // "link views" feature, and "sidebar follows active view" feature bOthersFollowed = makeViewsFollow(_url, req.args, req.browserArgs, mimeType, childView) || bOthersFollowed; } if (childView->isLockedLocation() && !req.args.reload() /* allow to reload a locked view*/) { return bOthersFollowed; } } QUrl url(_url); // In case we open an index.html, we want the location bar // to still display the original URL (so that 'up' uses that URL, // and since that's what the user entered). // changePart will take care of setting and storing that url. QString originalURL = url.toDisplayString(QUrl::PreferLocalFile); if (!req.nameFilter.isEmpty()) { // keep filter in location bar if (!originalURL.endsWith('/')) { originalURL += '/'; } originalURL += req.nameFilter; } - const QString urlStr = url.url(); - if (urlStr == QLatin1String("about:") || urlStr.startsWith(QLatin1String("about:konqueror")) || urlStr == QLatin1String("about:plugins")) { + if (url.toString() == QLatin1String("about:blank") && req.typedUrl.isEmpty()) { + originalURL.clear(); + } else if (url.scheme() == KonqAboutPage::aboutProtocol()) { mimeType = QStringLiteral("text/html"); originalURL = req.typedUrl.isEmpty() ? QString() : req.typedUrl; - } else if (urlStr == QLatin1String("about:blank") && req.typedUrl.isEmpty()) { - originalURL.clear(); } bool forceAutoEmbed = req.forceAutoEmbed || req.userRequestedReload; if (!req.typedUrl.isEmpty()) { // the user _typed_ the URL, he wants it in Konq. forceAutoEmbed = true; } - if (url.scheme() == QLatin1String("about") || url.scheme() == QLatin1String("error")) { + if (url.scheme() == KonqAboutPage::aboutProtocol() || url.scheme() == QLatin1String("error")) { forceAutoEmbed = true; } // Related to KonqFactory::createView if (!forceAutoEmbed && !KonqFMSettings::settings()->shouldEmbed(mimeType)) { qDebug() << "KonqFMSettings says: don't embed this servicetype"; return false; } // Do we even have a part to embed? Otherwise don't ask, since we'd ask twice. if (!forceAutoEmbed) { KService::List partServiceOffers; KonqFactory::getOffers(mimeType, &partServiceOffers); if (partServiceOffers.isEmpty()) { qDebug() << "No part available for" << mimeType; return false; } } // If the protocol doesn't support writing (e.g. HTTP) then we might want to save instead of just embedding. // So (if embedding would succeed, hence the checks above) we ask the user // Otherwise the user will get asked 'open or save' in openUrl anyway. if (!forceAutoEmbed && !KProtocolManager::supportsWriting(url)) { QString suggestedFileName; KonqRun *run = childView ? childView->run() : 0; int attachment = 0; if (run) { suggestedFileName = run->suggestedFileName(); attachment = (run->serverSuggestsSave()) ? KParts::BrowserRun::AttachmentDisposition : KParts::BrowserRun::InlineDisposition; } KParts::BrowserOpenOrSaveQuestion dlg(this, url, mimeType); dlg.setSuggestedFileName(suggestedFileName); const KParts::BrowserOpenOrSaveQuestion::Result res = dlg.askEmbedOrSave(attachment); if (res == KParts::BrowserOpenOrSaveQuestion::Embed) { forceAutoEmbed = true; } else if (res == KParts::BrowserOpenOrSaveQuestion::Cancel) { return true; // handled, don't do anything else } else { // Save KParts::BrowserRun::saveUrl(url, suggestedFileName, this, req.args); return true; // handled } } bool ok = true; if (!childView) { if (req.browserArgs.newTab()) { KonqFrameTabs *tabContainer = m_pViewManager->tabContainer(); int index = tabContainer->currentIndex(); childView = m_pViewManager->addTab(mimeType, req.serviceName, false, req.openAfterCurrentPage); if (req.newTabInFront && childView) { if (req.openAfterCurrentPage) { tabContainer->setCurrentIndex(index + 1); } else { tabContainer->setCurrentIndex(tabContainer->count() - 1); } } } else { // Create a new view // createFirstView always uses force auto-embed even if user setting is "separate viewer", // since this window has no view yet - we don't want to keep an empty mainwindow. // This can happen with e.g. application/pdf from a target="_blank" link, or window.open. childView = m_pViewManager->createFirstView(mimeType, req.serviceName); if (childView) { enableAllActions(true); m_currentView = childView; } } if (!childView) { return false; // It didn't work out. } childView->setViewName(m_initialFrameName.isEmpty() ? req.browserArgs.frameName : m_initialFrameName); m_initialFrameName.clear(); } else { // We know the child view if (!childView->isLockedViewMode()) { if (ok) { // When typing a new URL, the current context doesn't matter anymore // -> select the preferred part for a given mimetype (even if the current part can handle this mimetype). // This fixes the "get katepart and then type a website URL -> loaded into katepart" problem // (first fixed in r168902 from 2002!, see also unittest KonqHtmlTest::textThenHtml()) if (!req.typedUrl.isEmpty() || !req.serviceName.isEmpty()) { if (childView->isLoading()) { // Stop the view first, #282641. childView->stop(); } ok = childView->changePart(mimeType, req.serviceName, forceAutoEmbed); } else { ok = childView->ensureViewSupports(mimeType, forceAutoEmbed); } } } } if (ok) { //qDebug() << "req.nameFilter= " << req.nameFilter; //qDebug() << "req.typedUrl= " << req.typedUrl; //qDebug() << "Browser extension? " << (childView->browserExtension() ? "YES" : "NO"); //qDebug() << "Referrer: " << req.args.metaData()["referrer"]; childView->setTypedURL(req.typedUrl); if (childView->part()) { childView->part()->setArguments(req.args); } if (childView->browserExtension()) { childView->browserExtension()->setBrowserArguments(req.browserArgs); } // see dolphinpart childView->part()->setProperty("filesToSelect", QVariant::fromValue(req.filesToSelect)); if (!url.isEmpty()) { childView->openUrl(url, originalURL, req.nameFilter, req.tempFile); } } //qDebug() << "ok=" << ok << "bOthersFollowed=" << bOthersFollowed // << "returning" << (ok || bOthersFollowed); return ok || bOthersFollowed; } static KonqView *findChildView(KParts::ReadOnlyPart *callingPart, const QString &name, KonqMainWindow *&mainWindow, KParts::BrowserHostExtension *&hostExtension, KParts::ReadOnlyPart **part) { if (!KonqMainWindow::mainWindowList()) { return 0; } foreach (KonqMainWindow *window, *KonqMainWindow::mainWindowList()) { KonqView *res = window->childView(callingPart, name, hostExtension, part); if (res) { mainWindow = window; return res; } } return 0; } void KonqMainWindow::slotOpenURLRequest(const QUrl &url, const KParts::OpenUrlArguments &args, const KParts::BrowserArguments &browserArgs) { KParts::ReadOnlyPart *callingPart = static_cast(sender()->parent()); //qDebug() << url << "from" << callingPart->url() << "frameName=" << browserArgs.frameName; - if (callingPart->url().scheme() == "about" && url.scheme() == "exec") { + if (callingPart->url().scheme() == KonqAboutPage::aboutProtocol() && url.scheme() == "exec") { QStringList execArgs = url.path().mid(1).split(QChar(' '), QString::SkipEmptyParts); const QString executable = execArgs.takeFirst(); if (executable == "khelpcenter" || executable.startsWith("kcmshell")) { QProcess::startDetached(executable, execArgs); } else { qWarning() << "Refused for security reasons: executing" << executable; } return; } QString frameName = browserArgs.frameName; if (!frameName.isEmpty()) { static QString _top = QStringLiteral("_top"); static QString _self = QStringLiteral("_self"); static QString _parent = QStringLiteral("_parent"); static QString _blank = QStringLiteral("_blank"); if (frameName.toLower() == _blank) { KonqMainWindow *mainWindow = (m_popupProxyWindow ? m_popupProxyWindow.data() : this); mainWindow->slotCreateNewWindow(url, args, browserArgs); if (m_isPopupWithProxyWindow) { raiseWindow(mainWindow); } return; } if (frameName.toLower() != _top && frameName.toLower() != _self && frameName.toLower() != _parent) { KParts::BrowserHostExtension *hostExtension = 0; KonqView *view = childView(callingPart, frameName, hostExtension, 0); if (!view) { KonqMainWindow *mainWindow = 0; view = findChildView(callingPart, frameName, mainWindow, hostExtension, 0); if (!view || !mainWindow) { slotCreateNewWindow(url, args, browserArgs); return; } if (hostExtension) { hostExtension->openUrlInFrame(url, args, browserArgs); } else { mainWindow->openUrlRequestHelper(view, url, args, browserArgs); } return; } if (hostExtension) { hostExtension->openUrlInFrame(url, args, browserArgs); } else { openUrlRequestHelper(view, url, args, browserArgs); } return; } } KonqView *view = browserArgs.newTab() ? 0 : childView(callingPart); openUrlRequestHelper(view, url, args, browserArgs); } //Called by slotOpenURLRequest void KonqMainWindow::openUrlRequestHelper(KonqView *childView, const QUrl &url, const KParts::OpenUrlArguments &args, const KParts::BrowserArguments &browserArgs) { //qDebug() << "url=" << url; KonqOpenURLRequest req; req.args = args; req.browserArgs = browserArgs; openUrl(childView, url, args.mimeType(), req, browserArgs.trustedSource); } QObject *KonqMainWindow::lastFrame(KonqView *view) { QObject *nextFrame, *viewFrame; nextFrame = view->frame(); viewFrame = 0; while (nextFrame != 0 && !::qobject_cast(nextFrame)) { viewFrame = nextFrame; nextFrame = nextFrame->parent(); } return nextFrame ? viewFrame : 0; } // Linked-views feature, plus "sidebar follows URL opened in the active view" feature bool KonqMainWindow::makeViewsFollow(const QUrl &url, const KParts::OpenUrlArguments &args, const KParts::BrowserArguments &browserArgs, const QString &serviceType, KonqView *senderView) { if (!senderView->isLinkedView() && senderView != m_currentView) { return false; // none of those features apply -> return } bool res = false; //qDebug() << senderView->metaObject()->className() << "url=" << url << "serviceType=" << serviceType; KonqOpenURLRequest req; req.forceAutoEmbed = true; req.followMode = true; req.args = args; req.browserArgs = browserArgs; // We can't iterate over the map here, and openUrl for each, because the map can get modified // (e.g. by part changes). Better copy the views into a list. const QList listViews = m_mapViews.values(); QObject *senderFrame = lastFrame(senderView); foreach (KonqView *view, listViews) { if (view == senderView) { continue; } bool followed = false; // Views that should follow this URL as both views are linked if (view->isLinkedView() && senderView->isLinkedView()) { QObject *viewFrame = lastFrame(view); // Only views in the same tab of the sender will follow if (senderFrame && viewFrame && viewFrame != senderFrame) { continue; } qDebug() << "sending openUrl to view" << view->part()->metaObject()->className() << "url=" << url; // XXX duplicate code from ::openUrl if (view == m_currentView) { abortLoading(); setLocationBarURL(url); } else { view->stop(); } followed = openView(serviceType, url, view, req); } else { // Make the sidebar follow the URLs opened in the active view if (view->isFollowActive() && senderView == m_currentView) { followed = openView(serviceType, url, view, req); } } // Ignore return value if the view followed but doesn't really // show the file contents. We still want to see that // file, e.g. in a separate viewer. // This happens in views locked to a directory mode, // like sidebar and konsolepart (#52161). const bool ignore = view->isLockedViewMode() && view->showsDirectory(); //qDebug() << "View " << view->service()->name() // << " supports dirs: " << view->showsDirectory() // << " is locked-view-mode:" << view->isLockedViewMode() // << " ignore=" << ignore; if (!ignore) { res = followed || res; } } return res; } void KonqMainWindow::abortLoading() { if (m_currentView) { m_currentView->stop(); // will take care of the statusbar stopAnimation(); } } // Are there any indications that this window has a strong popup // nature and should therefore not be embedded into a tab? static bool isPopupWindow(const KParts::WindowArgs &windowArgs) { // ### other settings to respect? return windowArgs.x() != -1 || windowArgs.y() != -1 || windowArgs.width() != -1 || windowArgs.height() != -1 || !windowArgs.isMenuBarVisible() || !windowArgs.toolBarsVisible() || !windowArgs.isStatusBarVisible(); } // This is called for the javascript window.open call. // Also called for MMB on link, target="_blank" link, MMB on folder, etc. void KonqMainWindow::slotCreateNewWindow(const QUrl &url, const KParts::OpenUrlArguments &args, const KParts::BrowserArguments &browserArgs, const KParts::WindowArgs &windowArgs, KParts::ReadOnlyPart **part) { // NOTE: 'part' may be null qDebug() << "url=" << url << "args.mimeType()=" << args.mimeType() << "browserArgs.frameName=" << browserArgs.frameName; // If we are a popup window, forward the request the proxy window. if (m_isPopupWithProxyWindow && m_popupProxyWindow) { m_popupProxyWindow->slotCreateNewWindow(url, args, browserArgs, windowArgs, part); raiseWindow(m_popupProxyWindow); return; } if (part) { *part = 0; // Make sure to be initialized in case of failure... } KonqMainWindow *mainWindow = 0; if (!browserArgs.frameName.isEmpty() && browserArgs.frameName.toLower() != QLatin1String("_blank")) { KParts::BrowserHostExtension *hostExtension = 0; KParts::ReadOnlyPart *ro_part = 0; KParts::BrowserExtension *be = ::qobject_cast(sender()); if (be) { ro_part = ::qobject_cast(be->parent()); } if (findChildView(ro_part, browserArgs.frameName, mainWindow, hostExtension, part)) { // Found a view. If url isn't empty, we should open it - but this never happens currently // findChildView put the resulting part in 'part', so we can just return now //qDebug() << "frame=" << browserArgs.frameName << "-> found part=" << part << part->name(); return; } } bool createTab = browserArgs.newTab(); if (!createTab && !browserArgs.forcesNewWindow() /* explicit "Open in New Window" action, e.g. on frame or history item */) { if (args.actionRequestedByUser()) { // MMB or some RMB popupmenu action createTab = KonqSettings::mmbOpensTab(); } else { // Javascript popup createTab = KonqSettings::popupsWithinTabs() && !isPopupWindow(windowArgs); } } qDebug() << "createTab=" << createTab << "part=" << part; if (createTab && !m_isPopupWithProxyWindow) { bool newtabsinfront = !windowArgs.lowerWindow(); if (KonqSettings::newTabsInFront()) { newtabsinfront = !newtabsinfront; } const bool aftercurrentpage = KonqSettings::openAfterCurrentPage(); KonqOpenURLRequest req; req.args = args; req.browserArgs = browserArgs; // Can we use the standard way (openUrl), or do we need the part pointer immediately? if (!part) { req.browserArgs.setNewTab(true); req.forceAutoEmbed = true; // testcase: MMB on link-to-PDF, when pdf setting is "show file in external browser". req.newTabInFront = newtabsinfront; req.openAfterCurrentPage = aftercurrentpage; openUrl(0, url, args.mimeType(), req); } else { KonqView *newView = m_pViewManager->addTab(QStringLiteral("text/html"), QString(), false, aftercurrentpage); if (newView == 0) { return; } if (newtabsinfront) { m_pViewManager->showTab(newView); } openUrl(newView, url.isEmpty() ? QUrl(QStringLiteral("about:blank")) : url, QString(), req); newView->setViewName(browserArgs.frameName); *part = newView->part(); } // Raise the current window if the request to create the tab came from a popup // window, e.g. clicking on links with target = "_blank" in popup windows. KParts::BrowserExtension *be = qobject_cast(sender()); KonqView *view = (be ? childView(qobject_cast(be->parent())) : 0); KonqMainWindow *window = view ? view->mainWindow() : 0; if (window && window->m_isPopupWithProxyWindow && !m_isPopupWithProxyWindow) { raiseWindow(this); } return; } KonqOpenURLRequest req; req.args = args; req.browserArgs = browserArgs; req.browserArgs.setNewTab(false); // we got a new window, no need for a new tab in that window req.forceAutoEmbed = true; req.serviceName = preferredService(m_currentView, args.mimeType()); mainWindow = KonqMainWindowFactory::createEmptyWindow(); mainWindow->resetAutoSaveSettings(); // Don't autosave // Do we know the mimetype? If not, go to generic openUrl which will use a KonqRun. if (args.mimeType().isEmpty()) { mainWindow->openUrl(0, url, QString(), req); } else { if (!mainWindow->openView(args.mimeType(), url, 0, req)) { // we have problems. abort. delete mainWindow; if (part) { *part = 0; } return; } } qDebug() << "newWindow" << mainWindow << "currentView" << mainWindow->currentView() << "views" << mainWindow->viewMap().count(); KonqView *view = 0; // cannot use activePart/currentView, because the activation through the partmanager // is delayed by a singleshot timer (see KonqViewManager::setActivePart) // ### TODO: not true anymore if (mainWindow->viewMap().count()) { MapViews::ConstIterator it = mainWindow->viewMap().begin(); view = it.value(); if (part) { *part = it.key(); } } // activate the view now in order to make the menuBar() hide call work if (part && *part) { mainWindow->viewManager()->setActivePart(*part); } #if KONQ_HAVE_X11 // WORKAROUND: Clear the window state information set by KMainWindow::restoreWindowSize // so that the size and location settings we set below always take effect. KWindowSystem::clearState(mainWindow->winId(), NET::Max); #endif // process the window args const int xPos = ((windowArgs.x() == -1) ? mainWindow->x() : windowArgs.x()); const int yPos = ((windowArgs.y() == -1) ? mainWindow->y() : windowArgs.y()); const int width = ((windowArgs.width() == -1) ? mainWindow->width() : windowArgs.width()); const int height = ((windowArgs.height() == -1) ? mainWindow->height() : windowArgs.height()); mainWindow->move(xPos, yPos); mainWindow->resize(width, height); // Make the window open properties configurable. This is equivalent to // Firefox's "dom.disable_window_open_feature.*" properties. For now // only LocationBar visiblity is configurable. KSharedConfig::Ptr config = KSharedConfig::openConfig(); KConfigGroup cfg(config, "DisableWindowOpenFeatures"); if (!windowArgs.isMenuBarVisible()) { mainWindow->menuBar()->hide(); mainWindow->m_paShowMenuBar->setChecked(false); } if (!windowArgs.toolBarsVisible()) { // For security reasons the address bar is NOT hidden by default. The // user can override the default setup by adding a config option // "LocationBar=false" to the [DisableWindowOpenFeatures] section of // konquerorrc. const bool showLocationBar = cfg.readEntry("LocationBar", true); KToolBar *locationToolBar = mainWindow->toolBar(QStringLiteral("locationToolBar")); Q_FOREACH (KToolBar *bar, mainWindow->findChildren()) { if (bar != locationToolBar || !showLocationBar) { bar->hide(); } } if (locationToolBar && showLocationBar && isPopupWindow(windowArgs)) { // Hide all the actions of the popup window KActionCollection *collection = mainWindow->actionCollection(); for (int i = 0, count = collection->count(); i < count; ++i) { collection->action(i)->setVisible(false); } // Show only those actions that are allowed in a popup window static const char *const s_allowedActions[] = { "go_back", "go_forward", "go_up", "reload", "hard_reload", "stop", "cut", "copy", "paste", "print", "fullscreen", "add_bookmark", "new_window", 0 }; for (int i = 0; s_allowedActions[i]; ++i) { if (QAction *action = collection->action(QLatin1String(s_allowedActions[i]))) { action->setVisible(true); } } // Make only the address widget available in the location toolbar locationToolBar->clear(); QAction *action = locationToolBar->addWidget(mainWindow->m_combo); action->setVisible(true); // Make the combo box non editable and clear it of previous history QLineEdit *edit = (mainWindow->m_combo ? mainWindow->m_combo->lineEdit() : 0); if (edit) { mainWindow->m_combo->clear(); mainWindow->m_combo->setCompletionMode(KCompletion::CompletionNone); edit->setReadOnly(true); } // Store the originating window as the popup's proxy window so that // new tab requests in the popup window are forwarded to it. mainWindow->m_popupProxyWindow = this; mainWindow->m_isPopupWithProxyWindow = true; } } if (view) { if (!windowArgs.scrollBarsVisible()) { view->disableScrolling(); } if (!windowArgs.isStatusBarVisible()) { view->frame()->statusbar()->hide(); mainWindow->m_paShowStatusBar->setChecked(false); } else { mainWindow->m_paShowStatusBar->setChecked(true); } } if (!windowArgs.isResizable()) // ### this doesn't seem to work :-( { mainWindow->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed)); } // Trying to show the window initially behind the current window is a bit tricky, // as this involves the window manager, which may see things differently. // Many WMs raise and activate new windows, which means without WM support this won't work very // well. If the WM has support for _NET_WM_USER_TIME, it will be just set to 0 (=don't focus on show), // and the WM should take care of it itself. bool wm_usertime_support = false; #if KONQ_HAVE_X11 if (KWindowSystem::platform() == KWindowSystem::Platform::X11) { auto saved_last_input_time = QX11Info::appUserTime(); if (windowArgs.lowerWindow()) { NETRootInfo wm_info(QX11Info::connection(), NET::Supported); wm_usertime_support = wm_info.isSupported(NET::WM2UserTime); if (wm_usertime_support) { // *sigh*, and I thought nobody would need QWidget::dontFocusOnShow(). // Avoid Qt's support for user time by setting it to 0, and // set the property ourselves. QX11Info::setAppUserTime(0); KWindowSystem::setUserTime(mainWindow->winId(), 0); } // Put below the current window before showing, in case that actually works with the WM. // First do complete lower(), then stackUnder(), because the latter may not work with many WMs. mainWindow->lower(); mainWindow->stackUnder(this); } mainWindow->show(); if (windowArgs.lowerWindow()) { QX11Info::setAppUserTime(saved_last_input_time); if (!wm_usertime_support) { // No WM support. Let's try ugly tricks. mainWindow->lower(); mainWindow->stackUnder(this); if (this->isActiveWindow()) { this->activateWindow(); } } } } #else // KONQ_HAVE_X11 mainWindow->show(); #endif if (windowArgs.isFullScreen()) { mainWindow->action("fullscreen")->trigger(); } } void KonqMainWindow::slotNewWindow() { KonqMainWindow *mainWin = KonqMainWindowFactory::createNewWindow(); mainWin->show(); } void KonqMainWindow::slotDuplicateWindow() { m_pViewManager->duplicateWindow()->show(); } void KonqMainWindow::slotSendURL() { const QList lst = currentURLs(); QString body; QString fileNameList; for (QList::ConstIterator it = lst.constBegin(); it != lst.constEnd(); ++it) { if (!body.isEmpty()) { body += '\n'; } body += (*it).toDisplayString(); if (!fileNameList.isEmpty()) { fileNameList += QLatin1String(", "); } fileNameList += (*it).fileName(); } QString subject; if (m_currentView && !m_currentView->showsDirectory()) { subject = m_currentView->caption(); } else { // directory view subject = fileNameList; } QUrl mailtoUrl; mailtoUrl.setScheme(QStringLiteral("mailto")); QUrlQuery query; query.addQueryItem(QStringLiteral("subject"), subject); query.addQueryItem(QStringLiteral("body"), body); mailtoUrl.setQuery(query); QDesktopServices::openUrl(mailtoUrl); } void KonqMainWindow::slotSendFile() { const QList lst = currentURLs(); QStringList urls; QString fileNameList; for (QList::ConstIterator it = lst.constBegin(); it != lst.constEnd(); ++it) { if (!fileNameList.isEmpty()) { fileNameList += QLatin1String(", "); } if ((*it).isLocalFile() && QFileInfo((*it).toLocalFile()).isDir()) { // Create a temp dir, so that we can put the ZIP file in it with a proper name // Problem: when to delete it? QTemporaryDir tempDir; tempDir.setAutoRemove(false); if (!tempDir.isValid()) { qWarning() << "Could not create temporary dir"; continue; } const QString zipFileName = tempDir.path() + '/' + (*it).fileName() + ".zip"; KZip zip(zipFileName); if (!zip.open(QIODevice::WriteOnly)) { qWarning() << "Could not open" << zipFileName << "for writing"; continue; } zip.addLocalDirectory((*it).path(), QString()); zip.close(); fileNameList += (*it).fileName() + ".zip"; urls.append(QUrl::fromLocalFile(zipFileName).url()); } else { fileNameList += (*it).fileName(); urls.append((*it).url()); } } QString subject; if (m_currentView && !m_currentView->showsDirectory()) { subject = m_currentView->caption(); } else { subject = fileNameList; } QUrl mailtoUrl; mailtoUrl.setScheme(QStringLiteral("mailto")); QUrlQuery query; query.addQueryItem(QStringLiteral("subject"), subject); for (const QString& url : urls) { query.addQueryItem(QStringLiteral("attachment"), url); } mailtoUrl.setQuery(query); QDesktopServices::openUrl(mailtoUrl); } void KonqMainWindow::slotOpenLocation() { focusLocationBar(); QLineEdit *edit = comboEdit(); if (edit) { edit->selectAll(); } } void KonqMainWindow::slotOpenFile() { QUrl currentUrl; if (m_currentView && m_currentView->url().isLocalFile()) { currentUrl = m_currentView->url(); } else { currentUrl = QUrl::fromLocalFile(QDir::homePath()); } QUrl url = KFileDialog::getOpenUrl(currentUrl, QString(), this); if (!url.isEmpty()) { openFilteredUrl(url.url().trimmed()); } } void KonqMainWindow::slotIconsChanged() { qDebug(); if (m_combo) { m_combo->updatePixmaps(); } m_pViewManager->updatePixmaps(); updateWindowIcon(); } void KonqMainWindow::slotOpenWith() { if (!m_currentView) { return; } const QList lst{ m_currentView->url() }; const QString serviceName = sender()->objectName(); const KService::List offers = m_currentView->appServiceOffers(); KService::List::ConstIterator it = offers.begin(); const KService::List::ConstIterator end = offers.end(); for (; it != end; ++it) { if ((*it)->desktopEntryName() == serviceName) { KRun::runApplication(**it, lst, this); return; } } } void KonqMainWindow::slotViewModeTriggered(QAction *action) { if (!m_currentView) { return; } // Gather data from the action, since the action will be deleted by changePart QString modeName = action->objectName(); Q_ASSERT(modeName.endsWith("-viewmode")); modeName.chop(9); const QString internalViewMode = action->data().toString(); if (m_currentView->service()->desktopEntryName() != modeName) { m_currentView->stop(); m_currentView->lockHistory(); // Save those, because changePart will lose them const QUrl url = m_currentView->url(); const QString locationBarURL = m_currentView->locationBarURL(); #if 0 // Problem: dolphinpart doesn't currently implement it. But we don't need it that much // now that it's the main filemanagement part for all standard modes. QList filesToSelect = childView->part()->property("filesToSelect").value>(); #endif m_currentView->changePart(m_currentView->serviceType(), modeName); m_currentView->openUrl(url, locationBarURL); } if (!internalViewMode.isEmpty() && internalViewMode != m_currentView->internalViewMode()) { m_currentView->setInternalViewMode(internalViewMode); } } void KonqMainWindow::slotLockView() { if (!m_currentView) { return; } m_currentView->setLockedLocation(m_paLockView->isChecked()); } void KonqMainWindow::slotStop() { abortLoading(); if (m_currentView) { m_currentView->frame()->statusbar()->message(i18n("Canceled.")); } } void KonqMainWindow::slotLinkView() { if (!m_currentView) { return; } // Can't access this action in passive mode anyway Q_ASSERT(!m_currentView->isPassiveMode()); const bool mode = !m_currentView->isLinkedView(); const QList linkableViews = KonqLinkableViewsCollector::collect(this); if (linkableViews.count() == 2) { // Exactly two linkable views : link both linkableViews.at(0)->setLinkedView(mode); linkableViews.at(1)->setLinkedView(mode); } else { // Normal case : just this view m_currentView->setLinkedView(mode); } } void KonqMainWindow::slotReload(KonqView *reloadView, bool softReload) { if (!reloadView) { reloadView = m_currentView; } if (!reloadView || (reloadView->url().isEmpty() && reloadView->locationBarURL().isEmpty())) { return; } if (reloadView->isModified()) { if (KMessageBox::warningContinueCancel(this, i18n("This page contains changes that have not been submitted.\nReloading the page will discard these changes."), i18nc("@title:window", "Discard Changes?"), KGuiItem(i18n("&Discard Changes"), QStringLiteral("view-refresh")), KStandardGuiItem::cancel(), QStringLiteral("discardchangesreload")) != KMessageBox::Continue) { return; } } KonqOpenURLRequest req(reloadView->typedUrl()); req.userRequestedReload = true; if (reloadView->prepareReload(req.args, req.browserArgs, softReload)) { reloadView->lockHistory(); // Reuse current servicetype for local files, but not for remote files (it could have changed, e.g. over HTTP) QString serviceType = reloadView->url().isLocalFile() ? reloadView->serviceType() : QString(); // By using locationBarURL instead of url, we preserve name filters (#54687) QUrl reloadUrl = QUrl::fromUserInput(reloadView->locationBarURL(), QString(), QUrl::AssumeLocalFile); if (reloadUrl.isEmpty()) { // e.g. initial screen reloadUrl = reloadView->url(); } openUrl(reloadView, reloadUrl, serviceType, req); } } void KonqMainWindow::slotForceReload() { // A forced reload is simply a "hard" (i.e. - not soft!) reload. slotReload(0L /* Current view */, false /* Not softReload*/); } void KonqMainWindow::slotReloadPopup() { KonqFrameBase *tab = m_pViewManager->tabContainer()->tabAt(m_workingTab); if (tab) { slotReload(tab->activeChildView()); } } void KonqMainWindow::slotHome() { const QString homeURL = m_paHomePopup->data().toString(); KonqOpenURLRequest req; req.browserArgs.setNewTab(true); req.newTabInFront = KonqSettings::newTabsInFront(); Qt::MouseButtons buttons = QApplication::mouseButtons(); Qt::KeyboardModifiers modifiers = QApplication::keyboardModifiers(); if (modifiers & Qt::ShiftModifier) { req.newTabInFront = !req.newTabInFront; } if (modifiers & Qt::ControlModifier) { // Ctrl Left/MMB openFilteredUrl(homeURL, req); } else if (buttons & Qt::MiddleButton) { if (KonqSettings::mmbOpensTab()) { openFilteredUrl(homeURL, req); } else { const QUrl finalURL = KonqMisc::konqFilteredURL(this, homeURL); KonqMainWindow *mw = KonqMainWindowFactory::createNewWindow(finalURL); mw->show(); } } else { openFilteredUrl(homeURL, false); } } void KonqMainWindow::slotHomePopupActivated(QAction *action) { openUrl(0, QUrl(action->data().toString())); } void KonqMainWindow::slotGoHistory() { if (!m_historyDialog) { m_historyDialog = new KonqHistoryDialog(this); m_historyDialog->setAttribute(Qt::WA_DeleteOnClose); m_historyDialog->setModal(false); } m_historyDialog->show(); } void KonqMainWindow::slotConfigureExtensions() { KonqExtensionManager extensionManager(this, this, m_currentView ? m_currentView->part() : 0); extensionManager.exec(); } void KonqMainWindow::slotConfigure() { if (!m_configureDialog) { m_configureDialog = new KCMultiDialog(this); m_configureDialog->setObjectName(QStringLiteral("configureDialog")); connect(m_configureDialog, &KCMultiDialog::finished, this, &KonqMainWindow::slotConfigureDone); //BEGIN SYNC with initActions() const char *const toplevelModules[] = { "khtml_general", #ifndef Q_OS_WIN "kcmkonqyperformance", #endif "bookmarks" }; for (uint i = 0; i < sizeof(toplevelModules) / sizeof(char *); ++i) if (KAuthorized::authorizeControlModule(toplevelModules[i])) { m_configureDialog->addModule(KCModuleInfo(QString(toplevelModules[i]) + ".desktop")); } if (KAuthorized::authorizeControlModule(QStringLiteral("filebehavior"))) { KPageWidgetItem *fileManagementGroup = m_configureDialog->addModule(QStringLiteral("filebehavior")); if (fileManagementGroup) { fileManagementGroup->setName(i18n("File Management")); const char *const fmModules[] = { "kcmdolphinviewmodes", "kcmdolphinnavigation", "kcmdolphinservices", "kcmdolphingeneral", "filetypes", "kcmtrash" }; for (uint i = 0; i < sizeof(fmModules) / sizeof(char *); ++i) if (KAuthorized::authorizeControlModule(fmModules[i])) { m_configureDialog->addModule(KCModuleInfo(QString(fmModules[i]) + ".desktop"), fileManagementGroup); } } else { qWarning() << "Unable to load the \"File Management\" configuration module"; } } if (KAuthorized::authorizeControlModule(QStringLiteral("khtml_behavior"))) { KPageWidgetItem *webGroup = m_configureDialog->addModule(QStringLiteral("khtml_behavior")); if (webGroup) { webGroup->setName(i18n("Web Browsing")); const char *const webModules[] = { "khtml_appearance", "khtml_filter", "webshortcuts", "cache", "proxy", "kcmhistory", "cookies", "useragent", "khtml_java_js", "khtml_plugins" }; for (uint i = 0; i < sizeof(webModules) / sizeof(char *); ++i) if (KAuthorized::authorizeControlModule(webModules[i])) { m_configureDialog->addModule(KCModuleInfo(QString(webModules[i]) + ".desktop"), webGroup); } } else { qWarning() << "Unable to load the \"Web Browsing\" configuration module"; } } //END SYNC with initActions() } m_configureDialog->show(); } void KonqMainWindow::slotConfigureDone() { // Cleanup the dialog so other instances can use it.. if (m_configureDialog) { m_configureDialog->deleteLater(); m_configureDialog = 0; } } void KonqMainWindow::slotConfigureSpellChecking() { #pragma message("TODO KF5: Port Sonnet::ConfigDialog usage somehow") #if 0 // KF5 TODO Sonnet::ConfigDialog dialog(KSharedConfig::openConfig().data(), this); dialog.setWindowIcon(QIcon::fromTheme("konqueror")); dialog.exec(); #endif } void KonqMainWindow::slotConfigureToolbars() { slotForceSaveMainWindowSettings(); KEditToolBar dlg(factory(), this); connect(&dlg, &KEditToolBar::newToolBarConfig, this, &KonqMainWindow::slotNewToolbarConfig); connect(&dlg, &KEditToolBar::newToolBarConfig, this, &KonqMainWindow::initBookmarkBar); dlg.exec(); checkDisableClearButton(); } void KonqMainWindow::slotNewToolbarConfig() // This is called when OK or Apply is clicked { if (m_toggleViewGUIClient) { plugActionList(QStringLiteral("toggleview"), m_toggleViewGUIClient->actions()); } if (m_currentView && m_currentView->appServiceOffers().count() > 0) { plugActionList(QStringLiteral("openwith"), m_openWithActions); } plugViewModeActions(); KConfigGroup cg = KSharedConfig::openConfig()->group("KonqMainWindow"); applyMainWindowSettings(cg); } void KonqMainWindow::slotUndoAvailable(bool avail) { m_paUndo->setEnabled(avail); } void KonqMainWindow::slotPartChanged(KonqView *childView, KParts::ReadOnlyPart *oldPart, KParts::ReadOnlyPart *newPart) { m_mapViews.remove(oldPart); m_mapViews.insert(newPart, childView); // Remove the old part, and add the new part to the manager const bool wasActive = m_pViewManager->activePart() == oldPart; m_pViewManager->replacePart(oldPart, newPart, false); // Set active immediately - but only if the old part was the active one (#67956) if (wasActive) { // Note: this makes the new part active... so it calls slotPartActivated m_pViewManager->setActivePart(newPart); } viewsChanged(); } void KonqMainWindow::slotRunFinished() { const KonqRun *run = static_cast(sender()); if (!run->mailtoURL().isEmpty()) { QDesktopServices::openUrl(run->mailtoURL()); } if (run->hasError()) { // we had an error QDBusMessage message = QDBusMessage::createSignal(KONQ_MAIN_PATH, QStringLiteral("org.kde.Konqueror.Main"), QStringLiteral("removeFromCombo")); message << run->url().toDisplayString(); QDBusConnection::sessionBus().send(message); } KonqView *childView = run->childView(); // Check if we found a mimetype _and_ we got no error (example: cancel in openwith dialog) if (run->wasMimeTypeFound() && !run->hasError()) { // We do this here and not in the constructor, because // we are waiting for the first view to be set up before doing this... // Note: this is only used when konqueror is started from command line..... if (m_bNeedApplyKonqMainWindowSettings) { m_bNeedApplyKonqMainWindowSettings = false; // only once applyKonqMainWindowSettings(); } return; } // An error happened in KonqRun - stop wheel etc. if (childView) { childView->setLoading(false); if (childView == m_currentView) { stopAnimation(); // Revert to working URL - unless the URL was typed manually if (run->typedUrl().isEmpty() && childView->currentHistoryEntry()) { // not typed childView->setLocationBarURL(childView->currentHistoryEntry()->locationBarURL); } } } else { // No view, e.g. starting up empty stopAnimation(); } } void KonqMainWindow::applyKonqMainWindowSettings() { const QStringList toggableViewsShown = KonqSettings::toggableViewsShown(); QStringList::ConstIterator togIt = toggableViewsShown.begin(); QStringList::ConstIterator togEnd = toggableViewsShown.end(); for (; togIt != togEnd; ++togIt) { // Find the action by name // QAction * act = m_toggleViewGUIClient->actionCollection()->action( (*togIt).toLatin1() ); QAction *act = m_toggleViewGUIClient->action(*togIt); if (act) { act->trigger(); } else { qWarning() << "Unknown toggable view in ToggableViewsShown " << *togIt; } } } void KonqMainWindow::slotSetStatusBarText(const QString &) { // Reimplemented to disable KParts::MainWindow default behaviour // Does nothing here, see KonqFrame } void KonqMainWindow::slotViewCompleted(KonqView *view) { Q_ASSERT(view); // Need to update the current working directory // of the completion object every time the user // changes the directory!! (DA) if (m_pURLCompletion) { m_pURLCompletion->setDir(QUrl::fromUserInput(view->locationBarURL())); } } void KonqMainWindow::slotPartActivated(KParts::Part *part) { qDebug() << part << (part ? part->componentData().componentName() : QLatin1String("")); KonqView *newView = 0; KonqView *oldView = m_currentView; if (part) { newView = m_mapViews.value(static_cast(part)); Q_ASSERT(newView); if (newView->isPassiveMode()) { // Passive view. Don't connect anything, don't change m_currentView // Another view will become the current view very soon //qDebug() << "Passive mode - return"; return; } } KParts::BrowserExtension *ext = 0; if (oldView) { ext = oldView->browserExtension(); if (ext) { //qDebug() << "Disconnecting extension for view" << oldView; disconnectExtension(ext); } } qDebug() << "New current view" << newView; m_currentView = newView; if (newView) { m_paShowStatusBar->setChecked(newView->frame()->statusbar()->isVisible()); } if (!part) { //qDebug() << "No part activated - returning"; unplugViewModeActions(); createGUI(0); KParts::MainWindow::setCaption(QString()); return; } ext = m_currentView->browserExtension(); if (ext) { connectExtension(ext); } else { qDebug() << "No Browser Extension for the new part"; // Disable all browser-extension actions KParts::BrowserExtension::ActionSlotMap *actionSlotMap = KParts::BrowserExtension::actionSlotMapPtr(); KParts::BrowserExtension::ActionSlotMap::ConstIterator it = actionSlotMap->constBegin(); const KParts::BrowserExtension::ActionSlotMap::ConstIterator itEnd = actionSlotMap->constEnd(); for (; it != itEnd; ++it) { QAction *act = actionCollection()->action(QString::fromLatin1(it.key())); Q_ASSERT(act); if (act) { act->setEnabled(false); } } if (m_paCopyFiles) { m_paCopyFiles->setEnabled(false); } if (m_paMoveFiles) { m_paMoveFiles->setEnabled(false); } } createGUI(part); // View-dependent GUI KParts::MainWindow::setCaption(KStringHandler::csqueeze(m_currentView->caption(), 128)); // This line causes #170470 when removing the current tab, because QTabBar // emits currentChanged before calling tabRemoved, so KTabWidget gets confused. // I don't see a need for it anyway... //m_currentView->frame()->setTitle(m_currentView->caption(), 0); updateOpenWithActions(); updateViewActions(); // undo, lock, link and other view-dependent actions updateViewModeActions(); bool viewShowsDir = m_currentView->showsDirectory(); bool buttonShowsFolder = m_paHomePopup->text() == i18n("Home Folder"); if (m_paHomePopup->text() == i18n("Home") || viewShowsDir != buttonShowsFolder) { QAction *actHomeFolder = new QAction(this); QAction *actHomePage = new QAction(this); actHomeFolder->setIcon(QIcon::fromTheme(QStringLiteral("user-home"))); actHomeFolder->setText(i18n("Home Folder")); actHomeFolder->setStatusTip(i18n("Navigate to your 'Home Folder'")); actHomeFolder->setWhatsThis(i18n("Navigate to your local 'Home Folder'")); actHomeFolder->setData(QUrl::fromLocalFile(QDir::homePath())); actHomePage->setIcon(QIcon::fromTheme(QStringLiteral("go-home"))); actHomePage->setText(i18n("Home Page")); actHomePage->setStatusTip(i18n("Navigate to your 'Home Page'")); actHomePage->setWhatsThis(i18n("Navigate to your 'Home Page'

" "You can configure the location where this button takes you " "under Settings -> Configure Konqueror -> General.")); actHomePage->setData(KonqSettings::homeURL()); m_paHome->setIcon(viewShowsDir ? actHomeFolder->icon() : actHomePage->icon()); m_paHome->setText(viewShowsDir ? actHomeFolder->text() : actHomePage->text()); m_paHome->setStatusTip(viewShowsDir ? actHomeFolder->statusTip() : actHomePage->statusTip()); m_paHome->setWhatsThis(viewShowsDir ? actHomeFolder->whatsThis() : actHomePage->whatsThis()); m_paHomePopup->setIcon(viewShowsDir ? actHomeFolder->icon() : actHomePage->icon()); m_paHomePopup->setText(viewShowsDir ? actHomeFolder->text() : actHomePage->text()); m_paHomePopup->setStatusTip(viewShowsDir ? actHomeFolder->statusTip() : actHomePage->statusTip()); m_paHomePopup->setWhatsThis(viewShowsDir ? actHomeFolder->whatsThis() : actHomePage->whatsThis()); m_paHomePopup->setData(viewShowsDir ? actHomeFolder->data() : actHomePage->data()); m_paHomePopup->menu()->clear(); if (viewShowsDir) { m_paHomePopup->menu()->addAction(actHomePage); delete actHomeFolder; } else { m_paHomePopup->menu()->addAction(actHomeFolder); delete actHomePage; } } m_currentView->frame()->statusbar()->updateActiveStatus(); if (oldView && oldView->frame()) { oldView->frame()->statusbar()->updateActiveStatus(); } //qDebug() << "setting location bar url to" // << m_currentView->locationBarURL() << "m_currentView=" << m_currentView; // Make sure the location bar gets updated when the view(tab) is changed. if (oldView != newView && m_combo) { m_combo->lineEdit()->setModified(false); } m_currentView->setLocationBarURL(m_currentView->locationBarURL()); updateToolBarActions(); m_currentView->setActiveComponent(); } void KonqMainWindow::insertChildView(KonqView *childView) { //qDebug() << childView; m_mapViews.insert(childView->part(), childView); connect(childView, SIGNAL(viewCompleted(KonqView*)), this, SLOT(slotViewCompleted(KonqView*))); emit viewAdded(childView); } // Called by KonqViewManager, internal void KonqMainWindow::removeChildView(KonqView *childView) { //qDebug() << childView; disconnect(childView, SIGNAL(viewCompleted(KonqView*)), this, SLOT(slotViewCompleted(KonqView*))); #ifndef NDEBUG //dumpViewList(); #endif MapViews::Iterator it = m_mapViews.begin(); const MapViews::Iterator end = m_mapViews.end(); // find it in the map - can't use the key since childView->part() might be 0 //qDebug() << "Searching map"; while (it != end && it.value() != childView) { ++it; } //qDebug() << "Verifying search results"; if (it == m_mapViews.end()) { qWarning() << "KonqMainWindow::removeChildView childView " << childView << " not in map !"; return; } //qDebug() << "Removing view" << childView; m_mapViews.erase(it); emit viewRemoved(childView); #ifndef NDEBUG //dumpViewList(); #endif // KonqViewManager takes care of m_currentView } void KonqMainWindow::linkableViewCountChanged() { const QList linkableViews = KonqLinkableViewsCollector::collect(this); const int lvc = linkableViews.count(); m_paLinkView->setEnabled(lvc > 1); // Only one view -> unlink it if (lvc == 1) { linkableViews.at(0)->setLinkedView(false); } m_pViewManager->viewCountChanged(); } void KonqMainWindow::viewCountChanged() { // This is called (by the view manager) when the number of views changes. linkableViewCountChanged(); viewsChanged(); } void KonqMainWindow::viewsChanged() { // This is called when the number of views changes OR when // the type of some view changes. updateViewActions(); // undo, lock, link and other view-dependent actions } KonqView *KonqMainWindow::childView(KParts::ReadOnlyPart *view) { return m_mapViews.value(view); } KonqView *KonqMainWindow::childView(KParts::ReadOnlyPart *callingPart, const QString &name, KParts::BrowserHostExtension *&hostExtension, KParts::ReadOnlyPart **part) { //qDebug() << "this=" << this << "looking for" << name; QList views = m_mapViews.values(); KonqView *callingView = m_mapViews.value(callingPart); if (callingView) { // Move the callingView in front of the list, in case of duplicate frame names (#133967) if (views.removeAll(callingView)) { views.prepend(callingView); } } Q_FOREACH (KonqView *view, views) { QString viewName = view->viewName(); //qDebug() << " - viewName=" << viewName // << "frame names:" << view->frameNames(); // First look for a hostextension containing this frame name KParts::BrowserHostExtension *ext = KParts::BrowserHostExtension::childObject(view->part()); if (ext) { ext = ext->findFrameParent(callingPart, name); qDebug() << "BrowserHostExtension found part" << ext; if (!ext) { continue; // Don't use this window } } if (!viewName.isEmpty() && viewName == name) { qDebug() << "found existing view by name:" << view; hostExtension = 0; if (part) { *part = view->part(); } return view; } // KParts::BrowserHostExtension* ext = KonqView::hostExtension( view->part(), name ); if (ext) { const QList frames = ext->frames(); QListIterator frameIt(frames); while (frameIt.hasNext()) { KParts::ReadOnlyPart *item = frameIt.next(); if (item->objectName() == name) { qDebug() << "found a frame of name" << name << ":" << item; hostExtension = ext; if (part) { *part = item; } return view; } } } } return 0; } int KonqMainWindow::activeViewsNotLockedCount() const { int res = 0; MapViews::ConstIterator end = m_mapViews.constEnd(); for (MapViews::ConstIterator it = m_mapViews.constBegin(); it != end; ++it) { if (!it.value()->isPassiveMode() && !it.value()->isLockedLocation()) { ++res; } } return res; } int KonqMainWindow::linkableViewsCount() const { return KonqLinkableViewsCollector::collect(const_cast(this)).count(); } int KonqMainWindow::mainViewsCount() const { int res = 0; MapViews::ConstIterator it = m_mapViews.constBegin(); const MapViews::ConstIterator end = m_mapViews.constEnd(); for (; it != end; ++it) { if (!it.value()->isPassiveMode() && !it.value()->isToggleView()) { //qDebug() << res << it.value() << it.value()->part()->widget(); ++res; } } return res; } void KonqMainWindow::slotURLEntered(const QString &text, Qt::KeyboardModifiers modifiers) { if (m_bURLEnterLock || text.isEmpty()) { return; } m_bURLEnterLock = true; if ((modifiers & Qt::ControlModifier) || (modifiers & Qt::AltModifier)) { m_combo->setURL(m_currentView ? m_currentView->url().toDisplayString() : QString()); const bool inNewTab = !m_isPopupWithProxyWindow; // do not open a new tab in popup window. openFilteredUrl(text.trimmed(), inNewTab); } else { openFilteredUrl(text.trimmed()); } m_bURLEnterLock = false; } void KonqMainWindow::slotSplitViewHorizontal() { if (!m_currentView) { return; } KonqView *oldView = m_currentView; KonqView *newView = m_pViewManager->splitView(m_currentView, Qt::Horizontal); if (newView == 0) { return; } KonqOpenURLRequest req; req.forceAutoEmbed = true; openView(oldView->serviceType(), oldView->url(), newView, req); } void KonqMainWindow::slotSplitViewVertical() { if (!m_currentView) { return; } KonqView *oldView = m_currentView; KonqView *newView = m_pViewManager->splitView(m_currentView, Qt::Vertical); if (newView == 0) { return; } KonqOpenURLRequest req; req.forceAutoEmbed = true; openView(oldView->serviceType(), oldView->url(), newView, req); } void KonqMainWindow::slotAddTab() { // we can hardcode text/html because this is what about:blank will use anyway KonqView *newView = m_pViewManager->addTab(QStringLiteral("text/html"), QString(), false, KonqSettings::openAfterCurrentPage()); if (!newView) { return; } openUrl(newView, QUrl(QStringLiteral("about:blank")), QString()); //HACK!! QTabBar likes to steal focus when changing widgets. This can result //in a flicker since we don't want it to get focus we want the combo to get //or keep focus... // TODO: retest, and replace with the smaller hack from KTabWidget::moveTab QWidget *widget = newView->frame() && newView->frame()->part() ? newView->frame()->part()->widget() : 0; QWidget *origFocusProxy = widget ? widget->focusProxy() : 0; if (widget) { widget->setFocusProxy(m_combo); } m_pViewManager->showTab(newView); if (widget) { widget->setFocusProxy(origFocusProxy); } m_workingTab = 0; } void KonqMainWindow::slotDuplicateTab() { m_pViewManager->duplicateTab(m_pViewManager->tabContainer()->currentIndex(), KonqSettings::openAfterCurrentPage()); } void KonqMainWindow::slotDuplicateTabPopup() { m_pViewManager->duplicateTab(m_workingTab, KonqSettings::openAfterCurrentPage()); } void KonqMainWindow::slotBreakOffTab() { breakOffTab(m_pViewManager->tabContainer()->currentIndex()); } void KonqMainWindow::slotBreakOffTabPopup() { // Delay the call since it might delete the tabbar QMetaObject::invokeMethod(this, "breakOffTab", Qt::QueuedConnection, Q_ARG(int, m_workingTab)); } void KonqMainWindow::breakOffTab(int tabIndex) { KonqFrameBase *tab = m_pViewManager->tabContainer()->tabAt(tabIndex); if (!tab) { return; } const int originalTabIndex = m_pViewManager->tabContainer()->currentIndex(); // TODO: Why do we warn about breaking off a modified tab, since it seems to show the unsubmitted form data just fine? if (!KonqModifiedViewsCollector::collect(tab).isEmpty()) { m_pViewManager->showTab(tabIndex); if (KMessageBox::warningContinueCancel( this, i18n("This tab contains changes that have not been submitted.\nDetaching the tab will discard these changes."), i18nc("@title:window", "Discard Changes?"), KGuiItem(i18n("&Discard Changes"), QStringLiteral("tab-detach")), KStandardGuiItem::cancel(), QStringLiteral("discardchangesdetach")) != KMessageBox::Continue) { m_pViewManager->showTab(originalTabIndex); return; } } m_pViewManager->showTab(originalTabIndex); m_pViewManager->breakOffTab(tabIndex, size()); updateViewActions(); } void KonqMainWindow::slotPopupNewWindow() { KFileItemList::const_iterator it = m_popupItems.constBegin(); const KFileItemList::const_iterator end = m_popupItems.constEnd(); KonqOpenURLRequest req; req.args = m_popupUrlArgs; req.browserArgs = m_popupUrlBrowserArgs; for (; it != end; ++it) { KonqMainWindow *mw = KonqMainWindowFactory::createNewWindow((*it).targetUrl(), req); mw->show(); } } void KonqMainWindow::slotPopupThisWindow() { openUrl(0, m_popupItems.first().url()); } void KonqMainWindow::slotPopupNewTab() { if (m_isPopupWithProxyWindow && !m_popupProxyWindow) { slotPopupNewWindow(); return; } bool openAfterCurrentPage = KonqSettings::openAfterCurrentPage(); bool newTabsInFront = KonqSettings::newTabsInFront(); if (QApplication::keyboardModifiers() & Qt::ShiftModifier) { newTabsInFront = !newTabsInFront; } popupNewTab(newTabsInFront, openAfterCurrentPage); } void KonqMainWindow::popupNewTab(bool infront, bool openAfterCurrentPage) { KonqOpenURLRequest req; req.newTabInFront = false; req.forceAutoEmbed = true; req.openAfterCurrentPage = openAfterCurrentPage; req.args = m_popupUrlArgs; req.browserArgs = m_popupUrlBrowserArgs; req.browserArgs.setNewTab(true); KonqMainWindow *mainWindow = (m_popupProxyWindow ? m_popupProxyWindow.data() : this); for (int i = 0; i < m_popupItems.count(); ++i) { if (infront && i == m_popupItems.count() - 1) { req.newTabInFront = true; } mainWindow->openUrl(0, m_popupItems[i].targetUrl(), QString(), req); } // Raise this window if the request to create the tab came from a popup window. if (m_isPopupWithProxyWindow) { raiseWindow(mainWindow); } } void KonqMainWindow::openMultiURL(const QList &url) { QList::ConstIterator it = url.constBegin(); const QList::ConstIterator end = url.constEnd(); for (; it != end; ++it) { KonqView *newView = m_pViewManager->addTab(QStringLiteral("text/html")); Q_ASSERT(newView); if (newView == 0) { continue; } openUrl(newView, *it, QString()); m_pViewManager->showTab(newView); } } void KonqMainWindow::slotRemoveView() { if (!m_currentView) { return; } if (m_currentView->isModified()) { if (KMessageBox::warningContinueCancel(this, i18n("This view contains changes that have not been submitted.\nClosing the view will discard these changes."), i18nc("@title:window", "Discard Changes?"), KGuiItem(i18n("&Discard Changes"), QStringLiteral("view-close")), KStandardGuiItem::cancel(), QStringLiteral("discardchangesclose")) != KMessageBox::Continue) { return; } } // takes care of choosing the new active view m_pViewManager->removeView(m_currentView); } void KonqMainWindow::slotRemoveTab() { removeTab(m_pViewManager->tabContainer()->currentIndex()); } void KonqMainWindow::slotRemoveTabPopup() { // Can't do immediately - may kill the tabbar, and we're in an event path down from it QMetaObject::invokeMethod(this, "removeTab", Qt::QueuedConnection, Q_ARG(int, m_workingTab)); } void KonqMainWindow::removeTab(int tabIndex) { KonqFrameBase *tab = m_pViewManager->tabContainer()->tabAt(tabIndex); if (!tab) { return; } const int originalTabIndex = m_pViewManager->tabContainer()->currentIndex(); if (!KonqModifiedViewsCollector::collect(tab).isEmpty()) { m_pViewManager->showTab(tabIndex); if (KMessageBox::warningContinueCancel( this, i18n("This tab contains changes that have not been submitted.\nClosing the tab will discard these changes."), i18nc("@title:window", "Discard Changes?"), KGuiItem(i18n("&Discard Changes"), QStringLiteral("tab-close")), KStandardGuiItem::cancel(), QStringLiteral("discardchangesclose")) != KMessageBox::Continue) { m_pViewManager->showTab(originalTabIndex); return; } } m_pViewManager->showTab(originalTabIndex); m_pViewManager->removeTab(tab); updateViewActions(); } void KonqMainWindow::slotRemoveOtherTabs() { removeOtherTabs(m_pViewManager->tabContainer()->currentIndex()); } void KonqMainWindow::slotRemoveOtherTabsPopup() { // Can't do immediately - kills the tabbar, and we're in an event path down from it QMetaObject::invokeMethod(this, "removeOtherTabs", Qt::QueuedConnection, Q_ARG(int, m_workingTab)); } void KonqMainWindow::removeOtherTabs(int tabToKeep) { if (KMessageBox::warningContinueCancel( this, i18n("Do you really want to close all other tabs?"), i18nc("@title:window", "Close Other Tabs Confirmation"), KGuiItem(i18n("Close &Other Tabs"), QStringLiteral("tab-close-other")), KStandardGuiItem::cancel(), QStringLiteral("CloseOtherTabConfirm")) != KMessageBox::Continue) { return; } KonqFrameTabs *tabContainer = m_pViewManager->tabContainer(); const int originalTabIndex = tabContainer->currentIndex(); for (int tabIndex = 0; tabIndex < tabContainer->count(); ++tabIndex) { if (tabIndex == tabToKeep) { continue; } KonqFrameBase *tab = tabContainer->tabAt(tabIndex); if (!KonqModifiedViewsCollector::collect(tab).isEmpty()) { m_pViewManager->showTab(tabIndex); if (KMessageBox::warningContinueCancel( this, i18n("This tab contains changes that have not been submitted.\nClosing other tabs will discard these changes."), i18nc("@title:window", "Discard Changes?"), KGuiItem(i18n("&Discard Changes"), QStringLiteral("tab-close")), KStandardGuiItem::cancel(), QStringLiteral("discardchangescloseother")) != KMessageBox::Continue) { m_pViewManager->showTab(originalTabIndex); return; } } } m_pViewManager->showTab(originalTabIndex); m_pViewManager->removeOtherTabs(tabToKeep); updateViewActions(); } void KonqMainWindow::slotReloadAllTabs() { KonqFrameTabs *tabContainer = m_pViewManager->tabContainer(); const int originalTabIndex = tabContainer->currentIndex(); for (int tabIndex = 0; tabIndex < tabContainer->count(); ++tabIndex) { KonqFrameBase *tab = tabContainer->tabAt(tabIndex); if (!KonqModifiedViewsCollector::collect(tab).isEmpty()) { m_pViewManager->showTab(tabIndex); if (KMessageBox::warningContinueCancel(this, i18n("This tab contains changes that have not been submitted.\nReloading all tabs will discard these changes."), i18nc("@title:window", "Discard Changes?"), KGuiItem(i18n("&Discard Changes"), QStringLiteral("view-refresh")), KStandardGuiItem::cancel(), QStringLiteral("discardchangesreload")) != KMessageBox::Continue) { m_pViewManager->showTab(originalTabIndex); return; } } } m_pViewManager->showTab(originalTabIndex); m_pViewManager->reloadAllTabs(); updateViewActions(); } void KonqMainWindow::slotActivateNextTab() { m_pViewManager->activateNextTab(); } void KonqMainWindow::slotActivatePrevTab() { m_pViewManager->activatePrevTab(); } void KonqMainWindow::slotActivateTab() { m_pViewManager->activateTab(sender()->objectName().rightRef(2).toInt() - 1); } void KonqMainWindow::slotDumpDebugInfo() { #ifndef NDEBUG dumpViewList(); m_pViewManager->printFullHierarchy(); #endif } bool KonqMainWindow::askForTarget(const KLocalizedString &text, QUrl &url) { const QUrl initialUrl = (viewCount() == 2) ? otherView(m_currentView)->url() : m_currentView->url(); QString label = text.subs(m_currentView->url().toDisplayString(QUrl::PreferLocalFile)).toString(); KUrlRequesterDialog dlg(initialUrl, label, this); dlg.setWindowTitle(i18nc("@title:window", "Enter Target")); dlg.urlRequester()->setMode(KFile::File | KFile::ExistingOnly | KFile::Directory); if (dlg.exec()) { url = dlg.selectedUrl(); if (url.isValid()) { return true; } else { KMessageBox::error(this, i18n("%1 is not valid", url.url())); return false; } } return false; } void KonqMainWindow::slotCopyFiles() { QUrl dest; if (!askForTarget(ki18n("Copy selected files from %1 to:"), dest)) { return; } KIO::CopyJob *job = KIO::copy(currentURLs(), dest); KIO::FileUndoManager::self()->recordCopyJob(job); KJobWidgets::setWindow(job, this); job->uiDelegate()->setAutoErrorHandlingEnabled(true); } void KonqMainWindow::slotMoveFiles() { QUrl dest; if (!askForTarget(ki18n("Move selected files from %1 to:"), dest)) { return; } KIO::CopyJob *job = KIO::move(currentURLs(), dest); KIO::FileUndoManager::self()->recordCopyJob(job); KJobWidgets::setWindow(job, this); job->uiDelegate()->setAutoErrorHandlingEnabled(true); } QList KonqMainWindow::currentURLs() const { QList urls; if (m_currentView) { urls.append(m_currentView->url()); if (!m_currentView->selectedItems().isEmpty()) { // Return list of selected items only if we have a selection urls = m_currentView->selectedItems().urlList(); } } return urls; } // Only valid if there are one or two views KonqView *KonqMainWindow::otherView(KonqView *view) const { Q_ASSERT(viewCount() <= 2); MapViews::ConstIterator it = m_mapViews.constBegin(); if ((*it) == view) { ++it; } if (it != m_mapViews.constEnd()) { return (*it); } return 0; } void KonqMainWindow::slotUpAboutToShow() { if (!m_currentView) { return; } QMenu *popup = m_paUp->menu(); popup->clear(); int i = 0; // Use the location bar URL, because in case we display a index.html // we want to go up from the dir, not from the index.html QUrl u(QUrl::fromUserInput(m_currentView->locationBarURL())); u = KIO::upUrl(u); while (!u.path().isEmpty()) { QAction *action = new QAction(QIcon::fromTheme(KonqPixmapProvider::self()->iconNameFor(u)), u.toDisplayString(QUrl::PreferLocalFile), popup); action->setData(u); popup->addAction(action); if (u.path() == QLatin1String("/") || ++i > 10) { break; } u = KIO::upUrl(u); } } void KonqMainWindow::slotUp() { if (!m_currentView) { return; } Qt::MouseButtons goMouseState = QApplication::mouseButtons(); Qt::KeyboardModifiers goKeyboardState = QApplication::keyboardModifiers(); KonqOpenURLRequest req; req.browserArgs.setNewTab(true); req.forceAutoEmbed = true; req.openAfterCurrentPage = KonqSettings::openAfterCurrentPage(); req.newTabInFront = KonqSettings::newTabsInFront(); if (goKeyboardState & Qt::ShiftModifier) { req.newTabInFront = !req.newTabInFront; } const QUrl &url = m_currentView->upUrl(); if (goKeyboardState & Qt::ControlModifier) { openFilteredUrl(url.url(), req); } else if (goMouseState & Qt::MidButton) { if (KonqSettings::mmbOpensTab()) { openFilteredUrl(url.url(), req); } else { KonqMainWindow *mw = KonqMainWindowFactory::createNewWindow(url); mw->show(); } } else { openFilteredUrl(url.url(), false); } } void KonqMainWindow::slotUpActivated(QAction *action) { openUrl(0, action->data().value()); } void KonqMainWindow::slotGoHistoryActivated(int steps) { if (!m_goBuffer) { // Only start 1 timer. m_goBuffer = steps; m_goMouseState = QApplication::mouseButtons(); m_goKeyboardState = QApplication::keyboardModifiers(); QTimer::singleShot(0, this, SLOT(slotGoHistoryDelayed())); } } void KonqMainWindow::slotGoHistoryDelayed() { if (!m_currentView) { return; } bool openAfterCurrentPage = KonqSettings::openAfterCurrentPage(); bool mmbOpensTab = KonqSettings::mmbOpensTab(); bool inFront = KonqSettings::newTabsInFront(); if (m_goKeyboardState & Qt::ShiftModifier) { inFront = !inFront; } if (m_goKeyboardState & Qt::ControlModifier) { KonqView *newView = m_pViewManager->addTabFromHistory(m_currentView, m_goBuffer, openAfterCurrentPage); if (newView && inFront) { m_pViewManager->showTab(newView); } } else if (m_goMouseState & Qt::MidButton) { if (mmbOpensTab) { KonqView *newView = m_pViewManager->addTabFromHistory(m_currentView, m_goBuffer, openAfterCurrentPage); if (newView && inFront) { m_pViewManager->showTab(newView); } } else { KonqMisc::newWindowFromHistory(this->currentView(), m_goBuffer); } } else { m_currentView->go(m_goBuffer); makeViewsFollow(m_currentView->url(), KParts::OpenUrlArguments(), KParts::BrowserArguments(), m_currentView->serviceType(), m_currentView); } m_goBuffer = 0; m_goMouseState = Qt::LeftButton; m_goKeyboardState = Qt::NoModifier; } void KonqMainWindow::slotBackAboutToShow() { m_paBack->menu()->clear(); if (m_currentView) { KonqActions::fillHistoryPopup(m_currentView->history(), m_currentView->historyIndex(), m_paBack->menu(), true, false); } } /** * Fill the closed tabs action menu before it's shown */ void KonqMainWindow::slotClosedItemsListAboutToShow() { QMenu *popup = m_paClosedItems->menu(); // Clear the menu and fill it with a maximum of s_closedItemsListLength number of urls popup->clear(); QAction *clearAction = popup->addAction(i18nc("This menu entry empties the closed items history", "Empty Closed Items History")); connect(clearAction, &QAction::triggered, m_pUndoManager, &KonqUndoManager::clearClosedItemsList); popup->insertSeparator(static_cast(0)); QList::ConstIterator it = m_pUndoManager->closedItemsList().constBegin(); const QList::ConstIterator end = m_pUndoManager->closedItemsList().constEnd(); for (int i = 0; it != end && i < s_closedItemsListLength; ++it, ++i) { const QString text = QString::number(i) + ' ' + (*it)->title(); QAction *action = popup->addAction((*it)->icon(), text); action->setActionGroup(m_closedItemsGroup); action->setData(i); } KAcceleratorManager::manage(popup); } /** * Fill the sessions list action menu before it's shown */ void KonqMainWindow::slotSessionsListAboutToShow() { QMenu *popup = m_paSessions->menu(); // Clear the menu and fill it with a maximum of s_closedItemsListLength number of urls popup->clear(); QAction *saveSessionAction = popup->addAction(QIcon::fromTheme(QStringLiteral("document-save")), i18n("Save As...")); connect(saveSessionAction, &QAction::triggered, this, &KonqMainWindow::saveCurrentSession); QAction *manageSessionsAction = popup->addAction(QIcon::fromTheme(QStringLiteral("view-choose")), i18n("Manage...")); connect(manageSessionsAction, &QAction::triggered, this, &KonqMainWindow::manageSessions); popup->addSeparator(); QString dir = QStandardPaths::writableLocation(QStandardPaths::DataLocation) + QLatin1Char('/') + "sessions/"; QDirIterator it(dir, QDir::Readable | QDir::NoDotAndDotDot | QDir::Dirs); while (it.hasNext()) { QFileInfo fileInfo(it.next()); QAction *action = popup->addAction(KIO::decodeFileName(fileInfo.baseName())); action->setActionGroup(m_sessionsGroup); action->setData(fileInfo.filePath()); } KAcceleratorManager::manage(popup); } void KonqMainWindow::saveCurrentSession() { KonqNewSessionDlg dlg(this, this); dlg.exec(); } void KonqMainWindow::manageSessions() { KonqSessionDlg dlg(m_pViewManager, this); dlg.exec(); } void KonqMainWindow::slotSessionActivated(QAction *action) { QString dirpath = action->data().toString(); KonqSessionManager::self()->restoreSessions(dirpath); } void KonqMainWindow::updateClosedItemsAction() { bool available = m_pUndoManager->undoAvailable(); m_paClosedItems->setEnabled(available); m_paUndo->setText(m_pUndoManager->undoText()); } void KonqMainWindow::slotBack() { slotGoHistoryActivated(-1); } void KonqMainWindow::slotBackActivated(QAction *action) { slotGoHistoryActivated(action->data().toInt()); } void KonqMainWindow::slotForwardAboutToShow() { m_paForward->menu()->clear(); if (m_currentView) { KonqActions::fillHistoryPopup(m_currentView->history(), m_currentView->historyIndex(), m_paForward->menu(), false, true); } } void KonqMainWindow::slotForward() { slotGoHistoryActivated(1); } void KonqMainWindow::slotForwardActivated(QAction *action) { slotGoHistoryActivated(action->data().toInt()); } void KonqMainWindow::checkDisableClearButton() { // if the location toolbar already has the clear_location action, // disable the combobox's embedded clear icon. KToolBar *ltb = toolBar(QStringLiteral("locationToolBar")); QAction *clearAction = action("clear_location"); bool enable = true; foreach (QToolButton *atb, qFindChildren(ltb)) { if (atb->defaultAction() == clearAction) { enable = false; break; } } KLineEdit *lineEdit = qobject_cast(comboEdit()); if (lineEdit) { lineEdit->setClearButtonShown(enable); } } void KonqMainWindow::initCombo() { m_combo = new KonqCombo(0); m_combo->init(s_pCompletion); connect(m_combo, SIGNAL(activated(QString,Qt::KeyboardModifiers)), this, SLOT(slotURLEntered(QString,Qt::KeyboardModifiers))); connect(m_combo, SIGNAL(showPageSecurity()), this, SLOT(showPageSecurity())); m_pURLCompletion = new KUrlCompletion(); m_pURLCompletion->setCompletionMode(s_pCompletion->completionMode()); // This only turns completion off. ~ is still there in the result // We do want completion of user names, right? //m_pURLCompletion->setReplaceHome( false ); // Leave ~ alone! Will be taken care of by filters!! connect(m_combo, SIGNAL(completionModeChanged(KCompletion::CompletionMode)), SLOT(slotCompletionModeChanged(KCompletion::CompletionMode))); connect(m_combo, SIGNAL(completion(QString)), SLOT(slotMakeCompletion(QString))); connect(m_combo, SIGNAL(substringCompletion(QString)), SLOT(slotSubstringcompletion(QString))); connect(m_combo, SIGNAL(textRotation(KCompletionBase::KeyBindingType)), SLOT(slotRotation(KCompletionBase::KeyBindingType))); connect(m_combo, SIGNAL(cleared()), SLOT(slotClearHistory())); connect(m_pURLCompletion, SIGNAL(match(QString)), SLOT(slotMatch(QString))); m_combo->installEventFilter(this); static bool bookmarkCompletionInitialized = false; if (!bookmarkCompletionInitialized) { bookmarkCompletionInitialized = true; DelayedInitializer *initializer = new DelayedInitializer(QEvent::KeyPress, m_combo); connect(initializer, &DelayedInitializer::initialize, this, &KonqMainWindow::bookmarksIntoCompletion); } } void KonqMainWindow::bookmarksIntoCompletion() { // add all bookmarks to the completion list for easy access addBookmarksIntoCompletion(s_bookmarkManager->root()); } // the user changed the completion mode in the combo void KonqMainWindow::slotCompletionModeChanged(KCompletion::CompletionMode m) { s_pCompletion->setCompletionMode(m); KonqSettings::setSettingsCompletionMode(int(m_combo->completionMode())); KonqSettings::self()->save(); // tell the other windows too (only this instance currently) foreach (KonqMainWindow *window, *s_lstMainWindows) { if (window && window->m_combo) { window->m_combo->setCompletionMode(m); window->m_pURLCompletion->setCompletionMode(m); } } } // at first, try to find a completion in the current view, then use the global // completion (history) void KonqMainWindow::slotMakeCompletion(const QString &text) { if (m_pURLCompletion) { m_urlCompletionStarted = true; // flag for slotMatch() // qDebug() << "Local Completion object found!"; QString completion = m_pURLCompletion->makeCompletion(text); m_currentDir.clear(); if (completion.isNull() && !m_pURLCompletion->isRunning()) { // No match() signal will come from m_pURLCompletion // ask the global one // tell the static completion object about the current completion mode completion = s_pCompletion->makeCompletion(text); // some special handling necessary for CompletionPopup if (m_combo->completionMode() == KCompletion::CompletionPopup || m_combo->completionMode() == KCompletion::CompletionPopupAuto) { m_combo->setCompletedItems(historyPopupCompletionItems(text)); } else if (!completion.isNull()) { m_combo->setCompletedText(completion); } } else { // To be continued in slotMatch()... if (!m_pURLCompletion->dir().isEmpty()) { m_currentDir = m_pURLCompletion->dir(); } } } // qDebug() << "Current dir:" << m_currentDir << "Current text:" << text; } void KonqMainWindow::slotSubstringcompletion(const QString &text) { if (!m_currentView) { return; } QString currentURL = m_currentView->url().toDisplayString(); bool filesFirst = currentURL.startsWith('/') || currentURL.startsWith(QLatin1String("file:/")); QStringList items; if (filesFirst && m_pURLCompletion) { items = m_pURLCompletion->substringCompletion(text); } items += s_pCompletion->substringCompletion(text); if (!filesFirst && m_pURLCompletion) { items += m_pURLCompletion->substringCompletion(text); } m_combo->setCompletedItems(items); } void KonqMainWindow::slotRotation(KCompletionBase::KeyBindingType type) { // Tell slotMatch() to do nothing m_urlCompletionStarted = false; bool prev = (type == KCompletionBase::PrevCompletionMatch); if (prev || type == KCompletionBase::NextCompletionMatch) { QString completion = prev ? m_pURLCompletion->previousMatch() : m_pURLCompletion->nextMatch(); if (completion.isNull()) { // try the history KCompletion object completion = prev ? s_pCompletion->previousMatch() : s_pCompletion->nextMatch(); } if (completion.isEmpty() || completion == m_combo->currentText()) { return; } m_combo->setCompletedText(completion); } } // Handle match() from m_pURLCompletion void KonqMainWindow::slotMatch(const QString &match) { if (match.isEmpty() || !m_combo) { return; } // Check flag to avoid match() raised by rotation if (m_urlCompletionStarted) { m_urlCompletionStarted = false; // some special handling necessary for CompletionPopup if (m_combo->completionMode() == KCompletion::CompletionPopup || m_combo->completionMode() == KCompletion::CompletionPopupAuto) { QStringList items = m_pURLCompletion->allMatches(); items += historyPopupCompletionItems(m_combo->currentText()); items.removeDuplicates(); // when items from completion are also in history // items.sort(); // should we? m_combo->setCompletedItems(items); } else if (!match.isNull()) { m_combo->setCompletedText(match); } } } void KonqMainWindow::slotCtrlTabPressed() { KonqView *view = m_pViewManager->chooseNextView(m_currentView); //qDebug() << m_currentView->url() << "->" << view->url(); if (view) { m_pViewManager->setActivePart(view->part()); KonqFrameTabs *tabs = m_pViewManager->tabContainer(); m_pViewManager->showTab(tabs->tabIndexContaining(view->frame())); } } void KonqMainWindow::slotClearHistory() { KonqHistoryManager::kself()->emitClear(); } void KonqMainWindow::slotClearComboHistory() { if (m_combo && m_combo->count()) { m_combo->clearHistory(); } } bool KonqMainWindow::eventFilter(QObject *obj, QEvent *ev) { if ((ev->type() == QEvent::FocusIn || ev->type() == QEvent::FocusOut) && m_combo && m_combo->lineEdit() && m_combo == obj) { //qDebug() << obj << obj->metaObject()->className() << obj->name(); QFocusEvent *focusEv = static_cast(ev); if (focusEv->reason() == Qt::PopupFocusReason) { return KParts::MainWindow::eventFilter(obj, ev); } KParts::BrowserExtension *ext = 0; if (m_currentView) { ext = m_currentView->browserExtension(); } if (ev->type() == QEvent::FocusIn) { //qDebug() << "ComboBox got the focus..."; if (m_bLocationBarConnected) { //qDebug() << "Was already connected..."; return KParts::MainWindow::eventFilter(obj, ev); } m_bLocationBarConnected = true; // Workaround for Qt issue: usually, QLineEdit reacts on Ctrl-D, // but the duplicatecurrenttab action also has Ctrl-D as accel and // prevents the lineedit from getting this event. IMHO the accel // should be disabled in favor of the focus-widget. // TODO: decide if the delete-character behaviour of QLineEdit // really is useful enough to warrant this workaround QAction *duplicate = actionCollection()->action(QStringLiteral("duplicatecurrenttab")); if (duplicate->shortcuts().contains(QKeySequence(Qt::CTRL + Qt::Key_D))) { duplicate->setEnabled(false); } connect(m_paCut, SIGNAL(triggered()), m_combo->lineEdit(), SLOT(cut())); connect(m_paCopy, SIGNAL(triggered()), m_combo->lineEdit(), SLOT(copy())); connect(m_paPaste, SIGNAL(triggered()), m_combo->lineEdit(), SLOT(paste())); connect(QApplication::clipboard(), SIGNAL(dataChanged()), this, SLOT(slotClipboardDataChanged())); connect(m_combo->lineEdit(), SIGNAL(textChanged(QString)), this, SLOT(slotCheckComboSelection())); connect(m_combo->lineEdit(), SIGNAL(selectionChanged()), this, SLOT(slotCheckComboSelection())); slotClipboardDataChanged(); } else if (ev->type() == QEvent::FocusOut) { //qDebug() << "ComboBox lost focus..."; if (!m_bLocationBarConnected) { //qDebug() << "Was already disconnected..."; return KParts::MainWindow::eventFilter(obj, ev); } m_bLocationBarConnected = false; // see above in FocusIn for explanation // action is reenabled if a view exists QAction *duplicate = actionCollection()->action(QStringLiteral("duplicatecurrenttab")); if (duplicate->shortcuts().contains(QKeySequence(Qt::CTRL + Qt::Key_D))) { duplicate->setEnabled(currentView() && currentView()->frame()); } disconnect(m_paCut, SIGNAL(triggered()), m_combo->lineEdit(), SLOT(cut())); disconnect(m_paCopy, SIGNAL(triggered()), m_combo->lineEdit(), SLOT(copy())); disconnect(m_paPaste, SIGNAL(triggered()), m_combo->lineEdit(), SLOT(paste())); disconnect(QApplication::clipboard(), SIGNAL(dataChanged()), this, SLOT(slotClipboardDataChanged())); disconnect(m_combo->lineEdit(), SIGNAL(textChanged(QString)), this, SLOT(slotCheckComboSelection())); disconnect(m_combo->lineEdit(), SIGNAL(selectionChanged()), this, SLOT(slotCheckComboSelection())); if (ext) { m_paCut->setEnabled(ext->isActionEnabled("cut")); m_paCopy->setEnabled(ext->isActionEnabled("copy")); m_paPaste->setEnabled(ext->isActionEnabled("paste")); } else { m_paCut->setEnabled(false); m_paCopy->setEnabled(false); m_paPaste->setEnabled(false); } } } else if (ev->type() == QEvent::KeyPress) { QKeyEvent *keyEv = static_cast(ev); if ((keyEv->key() == Qt::Key_Tab) && (keyEv->modifiers() == Qt::ControlModifier)) { slotCtrlTabPressed(); return true; // don't let QTabWidget see the event } else if (obj == m_combo && m_currentView && keyEv->key() == Qt::Key_Escape) { // reset url to current view's actual url on ESC m_combo->setURL(m_currentView->url().QUrl::toDisplayString(QUrl::PreferLocalFile)); m_combo->lineEdit()->setModified(false); return true; } } return KParts::MainWindow::eventFilter(obj, ev); } // Only called when m_bLocationBarConnected, i.e. when the combobox has focus. // The rest of the time, the part handles the cut/copy/paste actions. void KonqMainWindow::slotClipboardDataChanged() { const QMimeData *data = QApplication::clipboard()->mimeData(); m_paPaste->setEnabled(data->hasText()); slotCheckComboSelection(); } void KonqMainWindow::slotCheckComboSelection() { QLineEdit *edit = comboEdit(); if (edit) { const bool hasSelection = edit->hasSelectedText(); //qDebug() << "m_combo->lineEdit()->hasMarkedText():" << hasSelection; m_paCopy->setEnabled(hasSelection); m_paCut->setEnabled(hasSelection); } } void KonqMainWindow::slotClearLocationBar() { slotStop(); if (m_combo) { m_combo->clearTemporary(); } focusLocationBar(); } void KonqMainWindow::slotForceSaveMainWindowSettings() { if (autoSaveSettings()) { // don't do it on e.g. JS window.open windows with no toolbars! saveAutoSaveSettings(); } } void KonqMainWindow::slotShowMenuBar() { menuBar()->setVisible(!menuBar()->isVisible()); slotForceSaveMainWindowSettings(); } void KonqMainWindow::slotShowStatusBar() { if (m_currentView) { m_currentView->frame()->statusbar()->setVisible(m_paShowStatusBar->isChecked()); } // An alternative: this will change simultaneously all of the status bars on // all of the current views. //MapViews::const_iterator end = m_mapViews.constEnd(); //for (MapViews::const_iterator it = m_mapViews.constBegin(); it != end; ++it) { // KonqView* view = it.value(); // view->frame()->statusbar()->setVisible(on); //} slotForceSaveMainWindowSettings(); } void KonqMainWindow::slotUpdateFullScreen(bool set) { KToggleFullScreenAction::setFullScreen(this, set); if (set) { // Create toolbar button for exiting from full-screen mode // ...but only if there isn't one already... bool haveFullScreenButton = false; //Walk over the toolbars and check whether there is a show fullscreen button in any of them foreach (KToolBar *bar, findChildren()) { //Are we plugged here, in a visible toolbar? if (bar->isVisible() && action("fullscreen")->associatedWidgets().contains(bar)) { haveFullScreenButton = true; break; } } if (!haveFullScreenButton) { QList lst; lst.append(m_ptaFullScreen); plugActionList(QStringLiteral("fullscreen"), lst); } m_prevMenuBarVisible = menuBar()->isVisible(); menuBar()->hide(); m_paShowMenuBar->setChecked(false); } else { unplugActionList(QStringLiteral("fullscreen")); if (m_prevMenuBarVisible) { menuBar()->show(); m_paShowMenuBar->setChecked(true); } } } void KonqMainWindow::setLocationBarURL(const QUrl &url) { setLocationBarURL(url.toString()); } void KonqMainWindow::setLocationBarURL(const QString &url) { // Don't set the location bar URL if it hasn't changed // or if the user had time to edit the url since the last call to openUrl (#64868) QLineEdit *edit = comboEdit(); if (edit && url != edit->text() && !edit->isModified()) { //qDebug() << "url=" << url; m_combo->setURL(url); updateWindowIcon(); } } void KonqMainWindow::setPageSecurity(PageSecurity pageSecurity) { if (m_combo) { m_combo->setPageSecurity(pageSecurity); } } void KonqMainWindow::showPageSecurity() { if (m_currentView && m_currentView->part()) { QAction *act = m_currentView->part()->action("security"); if (act) { act->trigger(); } } } // Called via DBUS from KonquerorApplication void KonqMainWindow::comboAction(int action, const QString &url, const QString &senderId) { if (!s_lstMainWindows) { // this happens in "konqueror --silent" return; } KonqCombo *combo = 0; foreach (KonqMainWindow *window, *s_lstMainWindows) { if (window && window->m_combo) { combo = window->m_combo; switch (action) { case ComboAdd: combo->insertPermanent(url); break; case ComboClear: combo->clearHistory(); break; case ComboRemove: combo->removeURL(url); break; default: break; } } } // only one instance should save... if (combo && senderId == QDBusConnection::sessionBus().baseService()) { combo->saveItems(); } } QString KonqMainWindow::locationBarURL() const { return (m_combo ? m_combo->currentText() : QString()); } void KonqMainWindow::focusLocationBar() { if (m_combo && (m_combo->isVisible() || !isVisible())) { m_combo->setFocus(); } } void KonqMainWindow::startAnimation() { m_paAnimatedLogo->start(); m_paStop->setEnabled(true); } void KonqMainWindow::stopAnimation() { m_paAnimatedLogo->stop(); m_paStop->setEnabled(false); } void KonqMainWindow::setUpEnabled(const QUrl &url) { bool bHasUpURL = ((!url.path().isEmpty() && url.path() != QLatin1String("/") && url.path()[0] == '/') || !url.query().isEmpty() /*e.g. lists.kde.org*/); m_paUp->setEnabled(bHasUpURL); } void KonqMainWindow::initActions() { // Note about this method : don't call setEnabled() on any of the actions. // They are all disabled then re-enabled with enableAllActions // If any one needs to be initially disabled, put that code in enableAllActions // For the popup menu only. m_pMenuNew = new KNewFileMenu(actionCollection(), QStringLiteral("new_menu"), this); // File menu QAction *action = actionCollection()->addAction(QStringLiteral("new_window")); action->setIcon(QIcon::fromTheme(QStringLiteral("window-new"))); action->setText(i18n("New &Window")); connect(action, &QAction::triggered, this, &KonqMainWindow::slotNewWindow); actionCollection()->setDefaultShortcuts(action, KStandardShortcut::shortcut(KStandardShortcut::New)); action = actionCollection()->addAction(QStringLiteral("duplicate_window")); action->setIcon(QIcon::fromTheme(QStringLiteral("window-duplicate"))); action->setText(i18n("&Duplicate Window")); connect(action, &QAction::triggered, this, &KonqMainWindow::slotDuplicateWindow); actionCollection()->setDefaultShortcut(action, Qt::CTRL+Qt::SHIFT+Qt::Key_D); action = actionCollection()->addAction(QStringLiteral("sendURL")); action->setIcon(QIcon::fromTheme(QStringLiteral("mail-message-new"))); action->setText(i18n("Send &Link Address...")); connect(action, &QAction::triggered, this, &KonqMainWindow::slotSendURL); action = actionCollection()->addAction(QStringLiteral("sendPage")); action->setIcon(QIcon::fromTheme(QStringLiteral("mail-message-new"))); action->setText(i18n("S&end File...")); connect(action, &QAction::triggered, this, &KonqMainWindow::slotSendFile); action = actionCollection()->addAction(QStringLiteral("open_location")); action->setIcon(QIcon::fromTheme(QStringLiteral("document-open-remote"))); action->setText(i18n("&Open Location")); actionCollection()->setDefaultShortcut(action, Qt::ALT+Qt::Key_O); connect(action, &QAction::triggered, this, &KonqMainWindow::slotOpenLocation); action = actionCollection()->addAction(QStringLiteral("open_file")); action->setIcon(QIcon::fromTheme(QStringLiteral("document-open"))); action->setText(i18n("&Open File...")); connect(action, &QAction::triggered, this, &KonqMainWindow::slotOpenFile); actionCollection()->setDefaultShortcuts(action, KStandardShortcut::shortcut(KStandardShortcut::Open)); #if 0 m_paFindFiles = new KToggleAction(QIcon::fromTheme("edit-find"), i18n("&Find File..."), this); actionCollection()->addAction("findfile", m_paFindFiles); connect(m_paFindFiles, &KToggleAction::triggered, this, &KonqMainWindow::slotToolFind); actionCollection()->setDefaultShortcuts(m_paFindFiles, KStandardShortcut::shortcut(KStandardShortcut::Find)); #endif m_paPrint = actionCollection()->addAction(KStandardAction::Print, QStringLiteral("print"), 0, 0); actionCollection()->addAction(KStandardAction::Quit, QStringLiteral("quit"), this, SLOT(close())); m_paLockView = new KToggleAction(i18n("Lock to Current Location"), this); actionCollection()->addAction(QStringLiteral("lock"), m_paLockView); connect(m_paLockView, &KToggleAction::triggered, this, &KonqMainWindow::slotLockView); m_paLinkView = new KToggleAction(i18nc("This option links konqueror views", "Lin&k View"), this); actionCollection()->addAction(QStringLiteral("link"), m_paLinkView); connect(m_paLinkView, &KToggleAction::triggered, this, &KonqMainWindow::slotLinkView); // Go menu m_paUp = new KToolBarPopupAction(QIcon::fromTheme(QStringLiteral("go-up")), i18n("&Up"), this); actionCollection()->addAction(QStringLiteral("go_up"), m_paUp); actionCollection()->setDefaultShortcuts(m_paUp, KStandardShortcut::shortcut(KStandardShortcut::Up)); connect(m_paUp, SIGNAL(triggered()), this, SLOT(slotUp())); connect(m_paUp->menu(), SIGNAL(aboutToShow()), this, SLOT(slotUpAboutToShow())); connect(m_paUp->menu(), SIGNAL(triggered(QAction*)), this, SLOT(slotUpActivated(QAction*))); QPair< KGuiItem, KGuiItem > backForward = KStandardGuiItem::backAndForward(); // Trash bin of closed tabs m_paClosedItems = new KToolBarPopupAction(QIcon::fromTheme(QStringLiteral("edit-undo-closed-tabs")), i18n("Closed Items"), this); actionCollection()->addAction(QStringLiteral("closeditems"), m_paClosedItems); m_closedItemsGroup = new QActionGroup(m_paClosedItems->menu()); // set the closed tabs list shown connect(m_paClosedItems, &KToolBarPopupAction::triggered, m_pUndoManager, &KonqUndoManager::undoLastClosedItem); connect(m_paClosedItems->menu(), SIGNAL(aboutToShow()), this, SLOT(slotClosedItemsListAboutToShow())); connect(m_closedItemsGroup, &QActionGroup::triggered, m_pUndoManager, &KonqUndoManager::slotClosedItemsActivated); connect(m_pViewManager, &KonqViewManager::aboutToRemoveTab, this, &KonqMainWindow::slotAddClosedUrl); connect(m_pUndoManager, &KonqUndoManager::openClosedTab, m_pViewManager, &KonqViewManager::openClosedTab); connect(m_pUndoManager, &KonqUndoManager::openClosedWindow, m_pViewManager, &KonqViewManager::openClosedWindow); connect(m_pUndoManager, &KonqUndoManager::closedItemsListChanged, this, &KonqMainWindow::updateClosedItemsAction); m_paSessions = new KActionMenu(i18n("Sessions"), this); actionCollection()->addAction(QStringLiteral("sessions"), m_paSessions); m_sessionsGroup = new QActionGroup(m_paSessions->menu()); connect(m_paSessions->menu(), SIGNAL(aboutToShow()), this, SLOT(slotSessionsListAboutToShow())); connect(m_sessionsGroup, &QActionGroup::triggered, this, &KonqMainWindow::slotSessionActivated); m_paBack = new KToolBarPopupAction(QIcon::fromTheme(backForward.first.iconName()), backForward.first.text(), this); actionCollection()->addAction(QStringLiteral("go_back"), m_paBack); actionCollection()->setDefaultShortcuts(m_paBack, KStandardShortcut::shortcut(KStandardShortcut::Back)); connect(m_paBack, SIGNAL(triggered()), this, SLOT(slotBack())); connect(m_paBack->menu(), SIGNAL(aboutToShow()), this, SLOT(slotBackAboutToShow())); connect(m_paBack->menu(), SIGNAL(triggered(QAction*)), this, SLOT(slotBackActivated(QAction*))); m_paForward = new KToolBarPopupAction(QIcon::fromTheme(backForward.second.iconName()), backForward.second.text(), this); actionCollection()->addAction(QStringLiteral("go_forward"), m_paForward); actionCollection()->setDefaultShortcuts(m_paForward, KStandardShortcut::shortcut(KStandardShortcut::Forward)); connect(m_paForward, SIGNAL(triggered()), this, SLOT(slotForward())); connect(m_paForward->menu(), SIGNAL(aboutToShow()), this, SLOT(slotForwardAboutToShow())); connect(m_paForward->menu(), SIGNAL(triggered(QAction*)), this, SLOT(slotForwardActivated(QAction*))); m_paHome = actionCollection()->addAction(KStandardAction::Home); connect(m_paHome, SIGNAL(triggered(bool)), this, SLOT(slotHome())); m_paHomePopup = new KToolBarPopupAction (QIcon::fromTheme(QStringLiteral("go-home")), i18n("Home"), this); actionCollection()->addAction(QStringLiteral("go_home_popup"), m_paHomePopup); connect(m_paHomePopup, SIGNAL(triggered()), this, SLOT(slotHome())); connect(m_paHomePopup->menu(), SIGNAL(triggered(QAction*)), this, SLOT(slotHomePopupActivated(QAction*))); KonqMostOftenURLSAction *mostOften = new KonqMostOftenURLSAction(i18nc("@action:inmenu Go", "Most Often Visited"), this); actionCollection()->addAction(QStringLiteral("go_most_often"), mostOften); connect(mostOften, &KonqMostOftenURLSAction::activated, this, &KonqMainWindow::slotOpenURL); KonqHistoryAction *historyAction = new KonqHistoryAction(i18nc("@action:inmenu Go", "Recently Visited"), this); actionCollection()->addAction(QStringLiteral("history"), historyAction); connect(historyAction, &KonqHistoryAction::activated, this, &KonqMainWindow::slotOpenURL); action = actionCollection()->addAction(QStringLiteral("go_history")); action->setIcon(QIcon::fromTheme(QStringLiteral("view-history"))); // Ctrl+Shift+H, shortcut from firefox // TODO: and Ctrl+H should open the sidebar history module actionCollection()->setDefaultShortcut(action, Qt::CTRL+Qt::SHIFT+Qt::Key_H); action->setText(i18nc("@action:inmenu Go", "Show History")); connect(action, &QAction::triggered, this, &KonqMainWindow::slotGoHistory); // Settings menu // This list is just for the call to authorizeControlModule; see slotConfigure for the real code QStringList configureModules; configureModules << QStringLiteral("khtml_general") << QStringLiteral("bookmarks") << QStringLiteral("filebehavior") << QStringLiteral("filetypes") << QStringLiteral("kcmtrash") << QStringLiteral("khtml_appearance") << QStringLiteral("khtml_behavior") << QStringLiteral("khtml_java_js") << QStringLiteral("khtml_filter") << QStringLiteral("webshortcuts") << QStringLiteral("kcmhistory") << QStringLiteral("cookies") << QStringLiteral("cache") << QStringLiteral("proxy") << QStringLiteral("useragent") << QStringLiteral("khtml_plugins") << QStringLiteral("kcmkonqyperformance"); if (!KAuthorized::authorizeControlModules(configureModules).isEmpty()) { actionCollection()->addAction(KStandardAction::Preferences, this, SLOT(slotConfigure())); } actionCollection()->addAction(KStandardAction::KeyBindings, guiFactory(), SLOT(configureShortcuts())); actionCollection()->addAction(KStandardAction::ConfigureToolbars, this, SLOT(slotConfigureToolbars())); m_paConfigureExtensions = actionCollection()->addAction(QStringLiteral("options_configure_extensions")); m_paConfigureExtensions->setText(i18n("Configure Extensions...")); connect(m_paConfigureExtensions, &QAction::triggered, this, &KonqMainWindow::slotConfigureExtensions); m_paConfigureSpellChecking = actionCollection()->addAction(QStringLiteral("configurespellcheck")); m_paConfigureSpellChecking->setIcon(QIcon::fromTheme(QStringLiteral("tools-check-spelling"))); m_paConfigureSpellChecking->setText(i18n("Configure Spell Checking...")); connect(m_paConfigureSpellChecking, &QAction::triggered, this, &KonqMainWindow::slotConfigureSpellChecking); // Window menu m_paSplitViewHor = actionCollection()->addAction(QStringLiteral("splitviewh")); m_paSplitViewHor->setIcon(QIcon::fromTheme(QStringLiteral("view-split-left-right"))); m_paSplitViewHor->setText(i18n("Split View &Left/Right")); connect(m_paSplitViewHor, &QAction::triggered, this, &KonqMainWindow::slotSplitViewHorizontal); actionCollection()->setDefaultShortcut(m_paSplitViewHor, Qt::CTRL+Qt::SHIFT+Qt::Key_L); m_paSplitViewVer = actionCollection()->addAction(QStringLiteral("splitviewv")); m_paSplitViewVer->setIcon(QIcon::fromTheme(QStringLiteral("view-split-top-bottom"))); m_paSplitViewVer->setText(i18n("Split View &Top/Bottom")); connect(m_paSplitViewVer, &QAction::triggered, this, &KonqMainWindow::slotSplitViewVertical); actionCollection()->setDefaultShortcut(m_paSplitViewVer, Qt::CTRL+Qt::SHIFT+Qt::Key_T); m_paAddTab = actionCollection()->addAction(QStringLiteral("newtab")); m_paAddTab->setIcon(QIcon::fromTheme(QStringLiteral("tab-new"))); m_paAddTab->setText(i18n("&New Tab")); connect(m_paAddTab, &QAction::triggered, this, &KonqMainWindow::slotAddTab); QList addTabShortcuts; addTabShortcuts.append(QKeySequence(Qt::CTRL+Qt::Key_T)); addTabShortcuts.append(QKeySequence(Qt::CTRL+Qt::SHIFT+Qt::Key_N)); actionCollection()->setDefaultShortcuts(m_paAddTab, addTabShortcuts); m_paDuplicateTab = actionCollection()->addAction(QStringLiteral("duplicatecurrenttab")); m_paDuplicateTab->setIcon(QIcon::fromTheme(QStringLiteral("tab-duplicate"))); m_paDuplicateTab->setText(i18n("&Duplicate Current Tab")); connect(m_paDuplicateTab, &QAction::triggered, this, &KonqMainWindow::slotDuplicateTab); actionCollection()->setDefaultShortcut(m_paDuplicateTab, Qt::CTRL+Qt::Key_D); m_paBreakOffTab = actionCollection()->addAction(QStringLiteral("breakoffcurrenttab")); m_paBreakOffTab->setIcon(QIcon::fromTheme(QStringLiteral("tab-detach"))); m_paBreakOffTab->setText(i18n("Detach Current Tab")); connect(m_paBreakOffTab, &QAction::triggered, this, &KonqMainWindow::slotBreakOffTab); actionCollection()->setDefaultShortcut(m_paBreakOffTab, Qt::CTRL+Qt::SHIFT+Qt::Key_B); m_paRemoveView = actionCollection()->addAction(QStringLiteral("removeview")); m_paRemoveView->setIcon(QIcon::fromTheme(QStringLiteral("view-close"))); m_paRemoveView->setText(i18n("&Close Active View")); connect(m_paRemoveView, &QAction::triggered, this, &KonqMainWindow::slotRemoveView); actionCollection()->setDefaultShortcut(m_paRemoveView, Qt::CTRL+Qt::SHIFT+Qt::Key_W); m_paRemoveTab = actionCollection()->addAction(QStringLiteral("removecurrenttab")); m_paRemoveTab->setIcon(QIcon::fromTheme(QStringLiteral("tab-close"))); m_paRemoveTab->setText(i18n("Close Current Tab")); connect(m_paRemoveTab, &QAction::triggered, this, &KonqMainWindow::slotRemoveTab, Qt::QueuedConnection /* exit Ctrl+W handler before deleting */); actionCollection()->setDefaultShortcut(m_paRemoveTab, Qt::CTRL+Qt::Key_W); m_paRemoveTab->setAutoRepeat(false); m_paRemoveOtherTabs = actionCollection()->addAction(QStringLiteral("removeothertabs")); m_paRemoveOtherTabs->setIcon(QIcon::fromTheme(QStringLiteral("tab-close-other"))); m_paRemoveOtherTabs->setText(i18n("Close &Other Tabs")); connect(m_paRemoveOtherTabs, &QAction::triggered, this, &KonqMainWindow::slotRemoveOtherTabs); m_paActivateNextTab = actionCollection()->addAction(QStringLiteral("activatenexttab")); m_paActivateNextTab->setText(i18n("Activate Next Tab")); connect(m_paActivateNextTab, &QAction::triggered, this, &KonqMainWindow::slotActivateNextTab); actionCollection()->setDefaultShortcuts(m_paActivateNextTab, QApplication::isRightToLeft() ? KStandardShortcut::tabPrev() : KStandardShortcut::tabNext()); m_paActivatePrevTab = actionCollection()->addAction(QStringLiteral("activateprevtab")); m_paActivatePrevTab->setText(i18n("Activate Previous Tab")); connect(m_paActivatePrevTab, &QAction::triggered, this, &KonqMainWindow::slotActivatePrevTab); actionCollection()->setDefaultShortcuts(m_paActivatePrevTab, QApplication::isRightToLeft() ? KStandardShortcut::tabNext() : KStandardShortcut::tabPrev()); QString actionname; for (int i = 1; i < 13; i++) { actionname.sprintf("activate_tab_%02d", i); QAction *action = actionCollection()->addAction(actionname); action->setText(i18n("Activate Tab %1", i)); connect(action, &QAction::triggered, this, &KonqMainWindow::slotActivateTab); } m_paMoveTabLeft = actionCollection()->addAction(QStringLiteral("tab_move_left")); m_paMoveTabLeft->setText(i18n("Move Tab Left")); m_paMoveTabLeft->setIcon(QIcon::fromTheme(QStringLiteral("arrow-left"))); connect(m_paMoveTabLeft, &QAction::triggered, this, &KonqMainWindow::slotMoveTabLeft); actionCollection()->setDefaultShortcut(m_paMoveTabLeft, Qt::CTRL+Qt::SHIFT+Qt::Key_Left); m_paMoveTabRight = actionCollection()->addAction(QStringLiteral("tab_move_right")); m_paMoveTabRight->setText(i18n("Move Tab Right")); m_paMoveTabRight->setIcon(QIcon::fromTheme(QStringLiteral("arrow-right"))); connect(m_paMoveTabRight, &QAction::triggered, this, &KonqMainWindow::slotMoveTabRight); actionCollection()->setDefaultShortcut(m_paMoveTabRight, Qt::CTRL+Qt::SHIFT+Qt::Key_Right); #ifndef NDEBUG action = actionCollection()->addAction(QStringLiteral("dumpdebuginfo")); action->setIcon(QIcon::fromTheme(QStringLiteral("view-dump-debug-info"))); action->setText(i18n("Dump Debug Info")); connect(action, &QAction::triggered, this, &KonqMainWindow::slotDumpDebugInfo); #endif m_ptaFullScreen = KStandardAction::fullScreen(0, 0, this, this); actionCollection()->addAction(m_ptaFullScreen->objectName(), m_ptaFullScreen); QList fullScreenShortcut = m_ptaFullScreen->shortcuts(); fullScreenShortcut.append(Qt::Key_F11); actionCollection()->setDefaultShortcuts(m_ptaFullScreen, fullScreenShortcut); connect(m_ptaFullScreen, &KToggleFullScreenAction::toggled, this, &KonqMainWindow::slotUpdateFullScreen); QList reloadShortcut = KStandardShortcut::shortcut(KStandardShortcut::Reload); QKeySequence reloadAlternate(Qt::CTRL + Qt::Key_R); if (!reloadShortcut.contains(reloadAlternate)) { reloadShortcut.append(reloadAlternate); } m_paReload = actionCollection()->addAction(QStringLiteral("reload")); m_paReload->setIcon(QIcon::fromTheme(QStringLiteral("view-refresh"))); m_paReload->setText(i18n("&Reload")); connect(m_paReload, SIGNAL(triggered()), SLOT(slotReload())); actionCollection()->setDefaultShortcuts(m_paReload, reloadShortcut); m_paReloadAllTabs = actionCollection()->addAction(QStringLiteral("reload_all_tabs")); m_paReloadAllTabs->setIcon(QIcon::fromTheme(QStringLiteral("view-refresh-all"))); m_paReloadAllTabs->setText(i18n("&Reload All Tabs")); connect(m_paReloadAllTabs, &QAction::triggered, this, &KonqMainWindow::slotReloadAllTabs); actionCollection()->setDefaultShortcut(m_paReloadAllTabs, Qt::SHIFT+Qt::Key_F5); // "Forced"/ "Hard" reload action - re-downloads all e.g. images even if a cached // version already exists. m_paForceReload = actionCollection()->addAction(QStringLiteral("hard_reload")); // TODO - request new icon? (view-refresh will do for the time being) m_paForceReload->setIcon(QIcon::fromTheme(QStringLiteral("view-refresh"))); m_paForceReload->setText(i18n("&Force Reload")); connect(m_paForceReload, &QAction::triggered, this, &KonqMainWindow::slotForceReload); QList forceReloadShortcuts; forceReloadShortcuts.append(QKeySequence(Qt::CTRL+Qt::Key_F5)); forceReloadShortcuts.append(QKeySequence(Qt::CTRL+Qt::SHIFT+Qt::Key_R)); actionCollection()->setDefaultShortcuts(m_paForceReload, forceReloadShortcuts); m_paUndo = KStandardAction::undo(m_pUndoManager, SLOT(undo()), this); actionCollection()->addAction(QStringLiteral("undo"), m_paUndo); connect(m_pUndoManager, SIGNAL(undoTextChanged(QString)), this, SLOT(slotUndoTextChanged(QString))); // Those are connected to the browserextension directly m_paCut = KStandardAction::cut(0, 0, this); actionCollection()->addAction(QStringLiteral("cut"), m_paCut); QList cutShortcuts(m_paCut->shortcuts()); cutShortcuts.removeAll(QKeySequence(Qt::SHIFT+Qt::Key_Delete)); // used for deleting files actionCollection()->setDefaultShortcuts(m_paCut, cutShortcuts); m_paCopy = KStandardAction::copy(0, 0, this); actionCollection()->addAction(QStringLiteral("copy"), m_paCopy); m_paPaste = KStandardAction::paste(0, 0, this); actionCollection()->addAction(QStringLiteral("paste"), m_paPaste); m_paStop = actionCollection()->addAction(QStringLiteral("stop")); m_paStop->setIcon(QIcon::fromTheme(QStringLiteral("process-stop"))); m_paStop->setText(i18n("&Stop")); connect(m_paStop, &QAction::triggered, this, &KonqMainWindow::slotStop); actionCollection()->setDefaultShortcut(m_paStop, Qt::Key_Escape); m_paAnimatedLogo = new KonqAnimatedLogo; QWidgetAction *logoAction = new QWidgetAction(this); actionCollection()->addAction(QStringLiteral("konq_logo"), logoAction); logoAction->setDefaultWidget(m_paAnimatedLogo); // Set icon and text so that it's easier to figure out what the action is in the toolbar editor logoAction->setText(i18n("Throbber")); logoAction->setIcon(QIcon::fromTheme(QStringLiteral("kde"))); // Location bar m_locationLabel = new KonqDraggableLabel(this, i18n("L&ocation: ")); QWidgetAction *locationAction = new QWidgetAction(this); actionCollection()->addAction(QStringLiteral("location_label"), locationAction); locationAction->setText(i18n("L&ocation: ")); connect(locationAction, &QWidgetAction::triggered, this, &KonqMainWindow::slotLocationLabelActivated); locationAction->setDefaultWidget(m_locationLabel); m_locationLabel->setBuddy(m_combo); QWidgetAction *comboAction = new QWidgetAction(this); actionCollection()->addAction(QStringLiteral("toolbar_url_combo"), comboAction); comboAction->setText(i18n("Location Bar")); actionCollection()->setDefaultShortcut(comboAction, Qt::Key_F6); connect(comboAction, &QWidgetAction::triggered, this, &KonqMainWindow::slotLocationLabelActivated); comboAction->setDefaultWidget(m_combo); actionCollection()->setShortcutsConfigurable(comboAction, false); m_combo->setWhatsThis(i18n("Location Bar

Enter a web address or search term.")); QAction *clearLocation = actionCollection()->addAction(QStringLiteral("clear_location")); clearLocation->setIcon(QIcon::fromTheme(QApplication::isRightToLeft() ? "edit-clear-locationbar-rtl" : "edit-clear-locationbar-ltr")); clearLocation->setText(i18n("Clear Location Bar")); actionCollection()->setDefaultShortcut(clearLocation, Qt::CTRL+Qt::Key_L); connect(clearLocation, SIGNAL(triggered()), SLOT(slotClearLocationBar())); clearLocation->setWhatsThis(i18n("Clear Location bar

" "Clears the contents of the location bar.")); // Bookmarks menu m_pamBookmarks = new KBookmarkActionMenu(s_bookmarkManager->root(), i18n("&Bookmarks"), this); actionCollection()->addAction(QStringLiteral("bookmarks"), m_pamBookmarks); m_pamBookmarks->setDelayed(false); // The actual menu needs a different action collection, so that the bookmarks // don't appear in kedittoolbar m_bookmarksActionCollection = new KActionCollection(static_cast(this)); m_pBookmarkMenu = new KonqBookmarkMenu(s_bookmarkManager, m_pBookmarksOwner, m_pamBookmarks, m_bookmarksActionCollection); QAction *addBookmark = m_bookmarksActionCollection->action(QStringLiteral("add_bookmark")); if (addBookmark) { // Keep the "Add bookmark" action visible though (#153835) // -> We should think of a way to mark actions as "not configurable in toolbars" and // "should not appear in shortcut dialog (!= isShortcutConfigurable)" instead, and use // a single actionCollection. actionCollection()->addAction(QStringLiteral("add_bookmark"), m_bookmarksActionCollection->takeAction(addBookmark)); } else { qDebug() << "Action add_bookmark not found!"; } m_paShowMenuBar = KStandardAction::showMenubar(this, SLOT(slotShowMenuBar()), this); actionCollection()->addAction(KStandardAction::name(KStandardAction::ShowMenubar), m_paShowMenuBar); m_paShowStatusBar = KStandardAction::showStatusbar(this, SLOT(slotShowStatusBar()), this); actionCollection()->addAction(KStandardAction::name(KStandardAction::ShowStatusbar), m_paShowStatusBar); action = actionCollection()->addAction(QStringLiteral("konqintro")); action->setText(i18n("Kon&queror Introduction")); connect(action, &QAction::triggered, this, &KonqMainWindow::slotIntro); QAction *goUrl = actionCollection()->addAction(QStringLiteral("go_url")); goUrl->setIcon(QIcon::fromTheme(QStringLiteral("go-jump-locationbar"))); goUrl->setText(i18n("Go")); connect(goUrl, &QAction::triggered, this, &KonqMainWindow::goURL); goUrl->setWhatsThis(i18n("Go

" "Goes to the page that has been entered into the location bar.")); enableAllActions(false); // help stuff m_paUp->setWhatsThis(i18n("Enter the parent folder

" "For instance, if the current location is file:/home/%1 clicking this " "button will take you to file:/home.", KUser().loginName())); m_paUp->setStatusTip(i18n("Enter the parent folder")); m_paBack->setWhatsThis(i18n("Move backwards one step in the browsing history")); m_paBack->setStatusTip(i18n("Move backwards one step in the browsing history")); m_paForward->setWhatsThis(i18n("Move forward one step in the browsing history")); m_paForward->setStatusTip(i18n("Move forward one step in the browsing history")); m_paClosedItems->setWhatsThis(i18n("Move backwards one step in the closed tabs history")); m_paClosedItems->setStatusTip(i18n("Move backwards one step in the closed tabs history")); m_paReload->setWhatsThis(i18n("Reload the currently displayed document

" "This may, for example, be needed to refresh web pages that have been " "modified since they were loaded, in order to make the changes visible.")); m_paReload->setStatusTip(i18n("Reload the currently displayed document")); m_paReloadAllTabs->setWhatsThis(i18n("Reload all currently displayed documents in tabs

" "This may, for example, be needed to refresh web pages that have been " "modified since they were loaded, in order to make the changes visible.")); m_paReloadAllTabs->setStatusTip(i18n("Reload all currently displayed document in tabs")); m_paStop->setWhatsThis(i18n("Stop loading the document

" "All network transfers will be stopped and Konqueror will display the content " "that has been received so far.")); m_paForceReload->setWhatsThis(i18n("Reload the currently displayed document

" "This may, for example, be needed to refresh web pages that have been " "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.")); m_paForceReload->setStatusTip(i18n("Force a reload of the currently displayed document and any contained images")); m_paStop->setStatusTip(i18n("Stop loading the document")); m_paCut->setWhatsThis(i18n("Cut the currently selected text or item(s) and move it " "to the system clipboard

" "This makes it available to the Paste command in Konqueror " "and other KDE applications.")); m_paCut->setStatusTip(i18n("Move the selected text or item(s) to the clipboard")); m_paCopy->setWhatsThis(i18n("Copy the currently selected text or item(s) to the " "system clipboard

" "This makes it available to the Paste command in Konqueror " "and other KDE applications.")); m_paCopy->setStatusTip(i18n("Copy the selected text or item(s) to the clipboard")); m_paPaste->setWhatsThis(i18n("Paste the previously cut or copied clipboard " "contents

" "This also works for text copied or cut from other KDE applications.")); m_paPaste->setStatusTip(i18n("Paste the clipboard contents")); m_paPrint->setWhatsThis(i18n("Print the currently displayed document

" "You will be presented with a dialog where you can set various " "options, such as the number of copies to print and which printer " "to use.

" "This dialog also provides access to special KDE printing " "services such as creating a PDF file from the current document.")); m_paPrint->setStatusTip(i18n("Print the current document")); m_paLockView->setStatusTip(i18n("A locked view cannot change folders. Use in combination with 'link view' to explore many files from one folder")); m_paLinkView->setStatusTip(i18n("Sets the view as 'linked'. A linked view follows folder changes made in other linked views.")); } void KonqExtendedBookmarkOwner::openBookmark(const KBookmark &bm, Qt::MouseButtons mb, Qt::KeyboardModifiers km) { qDebug() << bm.url() << km << mb; const QString url = bm.url().url(); KonqOpenURLRequest req; req.browserArgs.setNewTab(true); req.newTabInFront = KonqSettings::newTabsInFront(); req.forceAutoEmbed = true; if (km & Qt::ShiftModifier) { req.newTabInFront = !req.newTabInFront; } if (km & Qt::ControlModifier) { // Ctrl Left/MMB m_pKonqMainWindow->openFilteredUrl(url, req); } else if (mb & Qt::MidButton) { if (KonqSettings::mmbOpensTab()) { m_pKonqMainWindow->openFilteredUrl(url, req); } else { const QUrl finalURL = KonqMisc::konqFilteredURL(m_pKonqMainWindow, url); KonqMainWindow *mw = KonqMainWindowFactory::createNewWindow(finalURL); mw->show(); } } else { m_pKonqMainWindow->openFilteredUrl(url, false); } } void KonqMainWindow::slotMoveTabLeft() { if (QApplication::isRightToLeft()) { m_pViewManager->moveTabForward(); } else { m_pViewManager->moveTabBackward(); } updateViewActions(); } void KonqMainWindow::slotMoveTabRight() { if (QApplication::isRightToLeft()) { m_pViewManager->moveTabBackward(); } else { m_pViewManager->moveTabForward(); } updateViewActions(); } void KonqMainWindow::updateHistoryActions() { if (m_currentView) { m_paBack->setEnabled(m_currentView->canGoBack()); m_paForward->setEnabled(m_currentView->canGoForward()); } } bool KonqMainWindow::isPreloaded() const { return !isVisible() && m_mapViews.count() == 1 && m_currentView->url().toString() == "about:blank"; } void KonqMainWindow::updateToolBarActions(bool pendingAction /*=false*/) { if (!m_currentView) { return; } // Enables/disables actions that depend on the current view & url (mostly toolbar) // Up, back, forward, the edit extension, stop button, wheel setUpEnabled(m_currentView->url()); m_paBack->setEnabled(m_currentView->canGoBack()); m_paForward->setEnabled(m_currentView->canGoForward()); if (m_currentView->isLoading()) { startAnimation(); // takes care of m_paStop } else { m_paAnimatedLogo->stop(); m_paStop->setEnabled(pendingAction); //enable/disable based on any pending actions... } } void KonqMainWindow::updateViewActions() { // Update actions that depend on the current view and its mode, or on the number of views etc. // Don't do things in this method that depend on m_currentView->url(). // When going 'back' in history this will be called before opening the url. // Use updateToolBarActions instead. bool enable = false; if (m_currentView && m_currentView->part()) { // Avoid qWarning from QObject::property if it doesn't exist if (m_currentView->part()->metaObject()->indexOfProperty("supportsUndo") != -1) { QVariant prop = m_currentView->part()->property("supportsUndo"); if (prop.isValid() && prop.toBool()) { enable = true; } } } m_pUndoManager->updateSupportsFileUndo(enable); // slotUndoAvailable( m_pUndoManager->undoAvailable() ); m_paLockView->setEnabled(true); m_paLockView->setChecked(m_currentView && m_currentView->isLockedLocation()); // Can remove view if we'll still have a main view after that m_paRemoveView->setEnabled(mainViewsCount() > 1 || (m_currentView && m_currentView->isToggleView())); if (!currentView() || !currentView()->frame()) { m_paAddTab->setEnabled(false); m_paDuplicateTab->setEnabled(false); m_paRemoveOtherTabs->setEnabled(false); m_paBreakOffTab->setEnabled(false); m_paActivateNextTab->setEnabled(false); m_paActivatePrevTab->setEnabled(false); m_paMoveTabLeft->setEnabled(false); m_paMoveTabRight->setEnabled(false); } else { m_paAddTab->setEnabled(true); m_paDuplicateTab->setEnabled(true); KonqFrameTabs *tabContainer = m_pViewManager->tabContainer(); bool state = (tabContainer->count() > 1); m_paRemoveOtherTabs->setEnabled(state); m_paBreakOffTab->setEnabled(state); m_paActivateNextTab->setEnabled(state); m_paActivatePrevTab->setEnabled(state); QList childFrameList = tabContainer->childFrameList(); Q_ASSERT(!childFrameList.isEmpty()); m_paMoveTabLeft->setEnabled(currentView() ? currentView()->frame() != (QApplication::isRightToLeft() ? childFrameList.last() : childFrameList.first()) : false); m_paMoveTabRight->setEnabled(currentView() ? currentView()->frame() != (QApplication::isRightToLeft() ? childFrameList.first() : childFrameList.last()) : false); } // Can split a view if it's not a toggle view (because a toggle view can be here only once) bool isNotToggle = m_currentView && !m_currentView->isToggleView(); m_paSplitViewHor->setEnabled(isNotToggle); m_paSplitViewVer->setEnabled(isNotToggle); m_paLinkView->setChecked(m_currentView && m_currentView->isLinkedView()); #if 0 if (m_currentView && m_currentView->part() && ::qobject_cast(m_currentView->part())) { KonqDirPart *dirPart = static_cast(m_currentView->part()); m_paFindFiles->setEnabled(dirPart->findPart() == 0); // Create the copy/move options if not already done // TODO: move that stuff to dolphin(part) if (!m_paCopyFiles) { // F5 is the default key binding for Reload.... a la Windows. // mc users want F5 for Copy and F6 for move, but I can't make that default. m_paCopyFiles = actionCollection()->addAction("copyfiles"); m_paCopyFiles->setText(i18n("Copy &Files...")); connect(m_paCopyFiles, &QAction::triggered, this, &KonqMainWindow::slotCopyFiles); m_paCopyFiles->setShortcut(Qt::Key_F7); m_paMoveFiles = actionCollection()->addAction("movefiles"); m_paMoveFiles->setText(i18n("M&ove Files...")); connect(m_paMoveFiles, &QAction::triggered, this, &KonqMainWindow::slotMoveFiles); m_paMoveFiles->setShortcut(Qt::Key_F8); QList lst; lst.append(m_paCopyFiles); lst.append(m_paMoveFiles); m_paCopyFiles->setEnabled(false); m_paMoveFiles->setEnabled(false); plugActionList("operations", lst); } } else { m_paFindFiles->setEnabled(false); if (m_paCopyFiles) { unplugActionList("operations"); delete m_paCopyFiles; m_paCopyFiles = 0; delete m_paMoveFiles; m_paMoveFiles = 0; } } #endif } QString KonqMainWindow::findIndexFile(const QString &dir) { QDir d(dir); QString f = d.filePath(QStringLiteral("index.html")); if (QFile::exists(f)) { return f; } f = d.filePath(QStringLiteral("index.htm")); if (QFile::exists(f)) { return f; } f = d.filePath(QStringLiteral("index.HTML")); if (QFile::exists(f)) { return f; } return QString(); } void KonqMainWindow::connectExtension(KParts::BrowserExtension *ext) { KParts::BrowserExtension::ActionSlotMap *actionSlotMap = KParts::BrowserExtension::actionSlotMapPtr(); KParts::BrowserExtension::ActionSlotMap::ConstIterator it = actionSlotMap->constBegin(); KParts::BrowserExtension::ActionSlotMap::ConstIterator itEnd = actionSlotMap->constEnd(); for (; it != itEnd; ++it) { QAction *act = actionCollection()->action(it.key().data()); //qDebug() << it.key(); if (act) { // Does the extension have a slot with the name of this action ? if (ext->metaObject()->indexOfSlot(it.key() + "()") != -1) { connect(act, SIGNAL(triggered()), ext, it.value() /* SLOT(slot name) */); act->setEnabled(ext->isActionEnabled(it.key())); const QString text = ext->actionText(it.key()); if (!text.isEmpty()) { act->setText(text); } // TODO how to re-set the original action text, when switching to a part that didn't call setAction? // Can't test with Paste... } else { act->setEnabled(false); } } else { qWarning() << "Error in BrowserExtension::actionSlotMap(), unknown action : " << it.key(); } } } void KonqMainWindow::disconnectExtension(KParts::BrowserExtension *ext) { KParts::BrowserExtension::ActionSlotMap *actionSlotMap = KParts::BrowserExtension::actionSlotMapPtr(); KParts::BrowserExtension::ActionSlotMap::ConstIterator it = actionSlotMap->constBegin(); KParts::BrowserExtension::ActionSlotMap::ConstIterator itEnd = actionSlotMap->constEnd(); for (; it != itEnd; ++it) { QAction *act = actionCollection()->action(it.key().data()); //qDebug() << it.key(); if (act && ext->metaObject()->indexOfSlot(it.key() + "()") != -1) { //qDebug() << act << act->name(); act->disconnect(ext); } } } void KonqMainWindow::enableAction(const char *name, bool enabled) { QAction *act = actionCollection()->action(name); if (!act) { qWarning() << "Unknown action " << name << " - can't enable"; } else { if (m_bLocationBarConnected && ( act == m_paCopy || act == m_paCut || act == m_paPaste)) // Don't change action state while the location bar has focus. { return; } //qDebug() << name << enabled; act->setEnabled(enabled); } // Update "copy files" and "move files" accordingly if (m_paCopyFiles && !strcmp(name, "copy")) { m_paCopyFiles->setEnabled(enabled); } else if (m_paMoveFiles && !strcmp(name, "cut")) { m_paMoveFiles->setEnabled(enabled); } } void KonqMainWindow::setActionText(const char *name, const QString &text) { QAction *act = actionCollection()->action(name); if (!act) { qWarning() << "Unknown action " << name << "- can't enable"; } else { //qDebug() << name << " text=" << text; act->setText(text); } } void KonqMainWindow::enableAllActions(bool enable) { //qDebug() << enable; KParts::BrowserExtension::ActionSlotMap *actionSlotMap = KParts::BrowserExtension::actionSlotMapPtr(); const QList actions = actionCollection()->actions(); QList::ConstIterator it = actions.constBegin(); QList::ConstIterator end = actions.constEnd(); for (; it != end; ++it) { QAction *act = *it; if (!act->objectName().startsWith(QLatin1String("options_configure")) /* do not touch the configureblah actions */ && (!enable || !actionSlotMap->contains(act->objectName().toLatin1()))) { /* don't enable BE actions */ act->setEnabled(enable); } } // This method is called with enable=false on startup, and // then only once with enable=true when the first view is setup. // So the code below is where actions that should initially be disabled are disabled. if (enable) { setUpEnabled(m_currentView ? m_currentView->url() : QUrl()); // we surely don't have any history buffers at this time m_paBack->setEnabled(false); m_paForward->setEnabled(false); updateViewActions(); // undo, lock, link and other view-dependent actions updateClosedItemsAction(); m_paStop->setEnabled(m_currentView && m_currentView->isLoading()); if (m_toggleViewGUIClient) { QList actions = m_toggleViewGUIClient->actions(); for (int i = 0; i < actions.size(); ++i) { actions.at(i)->setEnabled(true); } } } actionCollection()->action(QStringLiteral("quit"))->setEnabled(true); actionCollection()->action(QStringLiteral("link"))->setEnabled(false); } void KonqMainWindow::disableActionsNoView() { // No view -> there are some things we can't do m_paUp->setEnabled(false); m_paReload->setEnabled(false); m_paReloadAllTabs->setEnabled(false); m_paBack->setEnabled(false); m_paForward->setEnabled(false); m_paLockView->setEnabled(false); m_paLockView->setChecked(false); m_paSplitViewVer->setEnabled(false); m_paSplitViewHor->setEnabled(false); m_paRemoveView->setEnabled(false); m_paLinkView->setEnabled(false); if (m_toggleViewGUIClient) { QList actions = m_toggleViewGUIClient->actions(); for (int i = 0; i < actions.size(); ++i) { actions.at(i)->setEnabled(false); } } // There are things we can do, though : bookmarks, view profile, location bar, new window, // settings, etc. static const char *const s_enActions[] = { "new_window", "duplicate_window", "open_location", "toolbar_url_combo", "clear_location", "animated_logo", "konqintro", "go_most_often", "go_applications", "go_trash", "go_settings", "go_network_folders", "go_autostart", "go_url", "go_media", "go_history", "options_configure_extensions", 0 }; for (int i = 0; s_enActions[i]; ++i) { QAction *act = action(s_enActions[i]); if (act) { act->setEnabled(true); } } m_combo->clearTemporary(); } void KonqMainWindow::setCaption(const QString &caption) { // KParts sends us empty captions when activating a brand new part // We can't change it there (in case of apps removing all parts altogether) // but here we never do that. if (!caption.isEmpty() && m_currentView) { if (caption.startsWith("data:text/html")) return; // Keep an unmodified copy of the caption (before squeezing and KComponentData::makeStdCaption are applied) m_currentView->setCaption(caption); KParts::MainWindow::setCaption(KStringHandler::csqueeze(m_currentView->caption(), 128)); } } void KonqMainWindow::showEvent(QShowEvent *event) { //qDebug() << QTime::currentTime(); // We need to check if our toolbars are shown/hidden here, and set // our menu items accordingly. We can't do it in the constructor because // view profiles store toolbar info, and that info is read after // construct time. m_paShowMenuBar->setChecked(!menuBar()->isHidden()); if (m_currentView) { m_paShowStatusBar->setChecked(m_currentView->frame()->statusbar()->isVisible()); } updateBookmarkBar(); // hide if empty // Call parent method KParts::MainWindow::showEvent(event); } QUrl KonqExtendedBookmarkOwner::currentUrl() const { const KonqView *view = m_pKonqMainWindow->currentView(); return view ? view->url() : QUrl(); } QString KonqMainWindow::currentURL() const { if (!m_currentView) { return QString(); } QString url = m_currentView->url().toDisplayString(); #if 0 // do we want this? // Add the name filter (*.txt) at the end of the URL again if (m_currentView->part()) { const QString nameFilter = m_currentView->nameFilter(); if (!nameFilter.isEmpty()) { if (!url.endsWith('/')) { url += '/'; } url += nameFilter; } } #endif return url; } bool KonqExtendedBookmarkOwner::supportsTabs() const { return true; } QList KonqExtendedBookmarkOwner::currentBookmarkList() const { QList list; KonqFrameTabs *tabContainer = m_pKonqMainWindow->viewManager()->tabContainer(); foreach (KonqFrameBase *frame, tabContainer->childFrameList()) { if (!frame || !frame->activeChildView()) { continue; } KonqView *view = frame->activeChildView(); if (view->locationBarURL().isEmpty()) { continue; } list << KBookmarkOwner::FutureBookmark(view->caption(), view->url(), KIO::iconNameForUrl(view->url())); } return list; } QString KonqExtendedBookmarkOwner::currentTitle() const { return m_pKonqMainWindow->currentTitle(); } void KonqExtendedBookmarkOwner::openInNewTab(const KBookmark &bm) { bool newTabsInFront = KonqSettings::newTabsInFront(); if (QApplication::keyboardModifiers() & Qt::ShiftModifier) { newTabsInFront = !newTabsInFront; } KonqOpenURLRequest req; req.browserArgs.setNewTab(true); req.newTabInFront = newTabsInFront; req.openAfterCurrentPage = false; req.forceAutoEmbed = true; m_pKonqMainWindow->openFilteredUrl(bm.url().url(), req); } void KonqExtendedBookmarkOwner::openFolderinTabs(const KBookmarkGroup &grp) { bool newTabsInFront = KonqSettings::newTabsInFront(); if (QApplication::keyboardModifiers() & Qt::ShiftModifier) { newTabsInFront = !newTabsInFront; } KonqOpenURLRequest req; req.browserArgs.setNewTab(true); req.newTabInFront = false; req.openAfterCurrentPage = false; req.forceAutoEmbed = true; const QList list = grp.groupUrlList(); if (list.isEmpty()) { return; } if (list.size() > 20) { if (KMessageBox::questionYesNo(m_pKonqMainWindow, i18n("You have requested to open more than 20 bookmarks in tabs. " "This might take a while. Continue?"), i18nc("@title:window", "Open bookmarks folder in new tabs")) != KMessageBox::Yes) { return; } } QList::ConstIterator it = list.constBegin(); QList::ConstIterator end = list.constEnd(); --end; for (; it != end; ++it) { m_pKonqMainWindow->openFilteredUrl((*it).toString(), req); } if (newTabsInFront) { req.newTabInFront = true; } m_pKonqMainWindow->openFilteredUrl((*end).toString(), req); } void KonqExtendedBookmarkOwner::openInNewWindow(const KBookmark &bm) { const QUrl finalURL(KonqMisc::konqFilteredURL(m_pKonqMainWindow, bm.url().url())); KonqMainWindow *mw = KonqMainWindowFactory::createNewWindow(finalURL); mw->show(); } QString KonqMainWindow::currentTitle() const { return m_currentView ? m_currentView->caption() : QString(); } // Convert between deprecated string-based KParts::BrowserExtension::ActionGroupMap // to newer enum-based KonqPopupMenu::ActionGroupMap static KonqPopupMenu::ActionGroupMap convertActionGroups(const KParts::BrowserExtension::ActionGroupMap &input) { KonqPopupMenu::ActionGroupMap agm; agm.insert(KonqPopupMenu::TopActions, input.value(QStringLiteral("topactions"))); agm.insert(KonqPopupMenu::TabHandlingActions, input.value(QStringLiteral("tabhandling"))); agm.insert(KonqPopupMenu::EditActions, input.value(QStringLiteral("editactions"))); agm.insert(KonqPopupMenu::PreviewActions, input.value(QStringLiteral("preview"))); agm.insert(KonqPopupMenu::CustomActions, input.value(QStringLiteral("partactions"))); agm.insert(KonqPopupMenu::LinkActions, input.value(QStringLiteral("linkactions"))); return agm; } void KonqMainWindow::slotPopupMenu(const QPoint &global, const QUrl &url, mode_t mode, const KParts::OpenUrlArguments &args, const KParts::BrowserArguments &browserArgs, KParts::BrowserExtension::PopupFlags flags, const KParts::BrowserExtension::ActionGroupMap &actionGroups) { KFileItem item(url, args.mimeType(), mode); KFileItemList items; items.append(item); slotPopupMenu(global, items, args, browserArgs, flags, actionGroups); } void KonqMainWindow::slotPopupMenu(const QPoint &global, const KFileItemList &items, const KParts::OpenUrlArguments &args, const KParts::BrowserArguments &browserArgs, KParts::BrowserExtension::PopupFlags itemFlags, const KParts::BrowserExtension::ActionGroupMap &actionGroups) { KonqView *m_oldView = m_currentView; KonqView *currentView = childView(static_cast(sender()->parent())); //qDebug() << "m_oldView=" << m_oldView << "new currentView=" << currentView << "passive:" << currentView->isPassiveMode(); if ((m_oldView != currentView) && currentView->isPassiveMode()) { // Make this view active only temporarily (because it's passive) m_currentView = currentView; if (m_oldView && m_oldView->browserExtension()) { disconnectExtension(m_oldView->browserExtension()); } if (m_currentView->browserExtension()) { connectExtension(m_currentView->browserExtension()); } } // Note that if m_oldView!=currentView and currentView isn't passive, // then the KParts mechanism has already noticed the click in it, // but KonqViewManager delays the GUI-rebuilding with a single-shot timer. // Right after the popup shows up, currentView _will_ be m_currentView. //qDebug() << "current view=" << m_currentView << m_currentView->part()->metaObject()->className(); // This action collection is used to pass actions to KonqPopupMenu. // It has to be a KActionCollection instead of a QList because we need // the actionStatusText signal... KActionCollection popupMenuCollection(static_cast(0)); popupMenuCollection.addAction(QStringLiteral("closeditems"), m_paClosedItems); #if 0 popupMenuCollection.addAction("find", m_paFindFiles); #endif popupMenuCollection.addAction(QStringLiteral("undo"), m_paUndo); popupMenuCollection.addAction(QStringLiteral("cut"), m_paCut); popupMenuCollection.addAction(QStringLiteral("copy"), m_paCopy); popupMenuCollection.addAction(QStringLiteral("paste"), m_paPaste); // The pasteto action is used when clicking on a dir, to paste into it. QAction *actPaste = KStandardAction::paste(this, SLOT(slotPopupPasteTo()), this); actPaste->setEnabled(m_paPaste->isEnabled()); popupMenuCollection.addAction(QStringLiteral("pasteto"), actPaste); prepareForPopupMenu(items, args, browserArgs); bool sReading = false; if (!m_popupUrl.isEmpty()) { sReading = KProtocolManager::supportsReading(m_popupUrl); } QUrl viewURL = currentView->url(); qDebug() << "viewURL=" << viewURL; bool openedForViewURL = false; //bool dirsSelected = false; bool devicesFile = false; if (items.count() == 1) { const QUrl firstURL = items.first().url(); if (!viewURL.isEmpty()) { //firstURL.cleanPath(); openedForViewURL = firstURL.matches(viewURL, QUrl::StripTrailingSlash); } devicesFile = firstURL.scheme().indexOf(QLatin1String("device"), 0, Qt::CaseInsensitive) == 0; //dirsSelected = S_ISDIR( items.first()->mode() ); } //qDebug() << "viewURL=" << viewURL; QUrl url = viewURL; bool isIntoTrash = url.scheme() == QLatin1String("trash") || url.url().startsWith(QLatin1String("system:/trash")); const bool doTabHandling = !openedForViewURL && !isIntoTrash && sReading; const bool showEmbeddingServices = items.count() == 1 && !m_popupMimeType.isEmpty() && !isIntoTrash && !devicesFile && (itemFlags & KParts::BrowserExtension::ShowTextSelectionItems) == 0; KService::List embeddingServices; if (showEmbeddingServices) { const QString currentServiceName = currentView->service()->desktopEntryName(); // List of services for the "Preview In" submenu. embeddingServices = KMimeTypeTrader::self()->query( m_popupMimeType, QStringLiteral("KParts/ReadOnlyPart"), // Obey "HideFromMenus". It defaults to false so we want "absent or true" // (wow, testing for 'true' if absent doesn't work, so order matters) "(not exist [X-KDE-BrowserView-HideFromMenus] or not [X-KDE-BrowserView-HideFromMenus]) " "and DesktopEntryName != '" +currentServiceName + "' " // I had an old local dirtree.desktop without lib, no need for invalid entries "and exist [Library]"); } // TODO: get rid of KParts::BrowserExtension::PopupFlags KonqPopupMenu::Flags popupFlags = static_cast(static_cast(itemFlags)); KonqPopupMenu::ActionGroupMap popupActionGroups = convertActionGroups(actionGroups); PopupMenuGUIClient *konqyMenuClient = new PopupMenuGUIClient(embeddingServices, popupActionGroups, !menuBar()->isVisible() ? m_paShowMenuBar : 0, fullScreenMode() ? m_ptaFullScreen : 0 ); qRegisterMetaType("KService::Ptr"); connect(konqyMenuClient, SIGNAL(openEmbedded(KService::Ptr)), this, SLOT(slotOpenEmbedded(KService::Ptr)), Qt::QueuedConnection); // Those actions go into the PopupMenuGUIClient, since that's the one defining them. QList tabHandlingActions; if (doTabHandling) { if (browserArgs.forcesNewWindow()) { QAction *act = konqyMenuClient->actionCollection()->addAction(QStringLiteral("sameview")); act->setText(i18n("Open in T&his Window")); act->setStatusTip(i18n("Open the document in current window")); connect(act, &QAction::triggered, this, &KonqMainWindow::slotPopupThisWindow); tabHandlingActions.append(act); } QAction *actNewWindow = konqyMenuClient->actionCollection()->addAction(QStringLiteral("newview")); actNewWindow->setIcon(QIcon::fromTheme(QStringLiteral("window-new"))); actNewWindow->setText(i18n("Open in New &Window")); actNewWindow->setStatusTip(i18n("Open the document in a new window")); connect(actNewWindow, &QAction::triggered, this, &KonqMainWindow::slotPopupNewWindow); tabHandlingActions.append(actNewWindow); QAction *actNewTab = konqyMenuClient->actionCollection()->addAction(QStringLiteral("openintab")); actNewTab->setIcon(QIcon::fromTheme(QStringLiteral("tab-new"))); actNewTab->setText(i18n("Open in &New Tab")); connect(actNewTab, &QAction::triggered, this, &KonqMainWindow::slotPopupNewTab); actNewTab->setStatusTip(i18n("Open the document in a new tab")); tabHandlingActions.append(actNewTab); QAction *separator = new QAction(konqyMenuClient->actionCollection()); separator->setSeparator(true); tabHandlingActions.append(separator); } if (doTabHandling) { popupActionGroups.insert(KonqPopupMenu::TabHandlingActions, tabHandlingActions); } QPointer pPopupMenu = new KonqPopupMenu( items, viewURL, popupMenuCollection, popupFlags, // This parent ensures that if the part destroys itself (e.g. KHTML redirection), // it will close the popupmenu currentView->part()->widget()); pPopupMenu->setNewFileMenu(m_pMenuNew); pPopupMenu->setBookmarkManager(s_bookmarkManager); pPopupMenu->setActionGroups(popupActionGroups); if (openedForViewURL && !viewURL.isLocalFile()) { pPopupMenu->setURLTitle(currentView->caption()); } QPointer be = ::qobject_cast(sender()); if (be) { QObject::connect(this, &KonqMainWindow::popupItemsDisturbed, pPopupMenu.data(), &KonqPopupMenu::close); QObject::connect(be, SIGNAL(itemsRemoved(KFileItemList)), this, SLOT(slotItemsRemoved(KFileItemList))); } QPointer guard(this); // #149736, window could be deleted inside popupmenu event loop pPopupMenu->exec(global); delete pPopupMenu; // We're sort of misusing KActionCollection here, but we need it for the actionStatusText signal... // Anyway. If the action belonged to the view, and the view got deleted, we don't want ~KActionCollection // to iterate over those deleted actions /*KActionPtrList lst = popupMenuCollection.actions(); KActionPtrList::iterator it = lst.begin(); for ( ; it != lst.end() ; ++it ) popupMenuCollection.take( *it );*/ if (guard.isNull()) { // the placement of this test is very important, double-check #149736 if moving stuff around return; } if (be) { QObject::disconnect(be, SIGNAL(itemsRemoved(KFileItemList)), this, SLOT(slotItemsRemoved(KFileItemList))); } delete konqyMenuClient; m_popupItems.clear(); // Deleted by konqyMenuClient's actioncollection //delete actNewTab; //delete actNewWindow; delete actPaste; // Restore current view if current is passive if ((m_oldView != currentView) && (currentView == m_currentView) && currentView->isPassiveMode()) { //qDebug() << "restoring active view" << m_oldView; if (m_currentView->browserExtension()) { disconnectExtension(m_currentView->browserExtension()); } if (m_oldView) { if (m_oldView->browserExtension()) { connectExtension(m_oldView->browserExtension()); m_currentView = m_oldView; } // Special case: RMB + renaming in sidebar; setFocus would abort editing. QWidget *fw = focusWidget(); if (!fw || !::qobject_cast(fw)) { m_oldView->part()->widget()->setFocus(); m_pViewManager->setActivePart(m_oldView->part()); } } } } void KonqMainWindow::prepareForPopupMenu(const KFileItemList &items, const KParts::OpenUrlArguments &args, const KParts::BrowserArguments &browserArgs) { if (!items.isEmpty()) { m_popupUrl = items.first().url(); m_popupMimeType = items.first().mimetype(); } else { m_popupUrl = QUrl(); m_popupMimeType.clear(); } // We will need these if we call the newTab slot m_popupItems = items; m_popupUrlArgs = args; m_popupUrlArgs.setMimeType(QString()); // Reset so that Open in New Window/Tab does mimetype detection m_popupUrlBrowserArgs = browserArgs; } void KonqMainWindow::slotItemsRemoved(const KFileItemList &items) { QListIterator it(items); while (it.hasNext()) { if (m_popupItems.contains(it.next())) { emit popupItemsDisturbed(); return; } } } void KonqMainWindow::slotOpenEmbedded(KService::Ptr service) { if (!m_currentView) { return; } m_currentView->stop(); m_currentView->setLocationBarURL(m_popupUrl); m_currentView->setTypedURL(QString()); if (m_currentView->changePart(m_popupMimeType, service->desktopEntryName(), true)) { m_currentView->openUrl(m_popupUrl, m_popupUrl.toDisplayString(QUrl::PreferLocalFile)); } } void KonqMainWindow::slotPopupPasteTo() { if (!m_currentView || m_popupUrl.isEmpty()) { return; } m_currentView->callExtensionURLMethod("pasteTo", m_popupUrl); } void KonqMainWindow::slotReconfigure() { reparseConfiguration(); } void KonqMainWindow::reparseConfiguration() { qDebug(); KonqSettings::self()->load(); m_pViewManager->applyConfiguration(); KonqMouseEventFilter::self()->reparseConfiguration(); if (m_combo) { m_combo->setFont(QFontDatabase::systemFont(QFontDatabase::GeneralFont)); } MapViews::ConstIterator it = m_mapViews.constBegin(); MapViews::ConstIterator end = m_mapViews.constEnd(); for (; it != end; ++it) { (*it)->reparseConfiguration(); } } void KonqMainWindow::saveProperties(KConfigGroup &config) { // Ensure no crash if the sessionmanager timer fires before the ctor is done // This can happen via ToggleViewGUIClient -> KServiceTypeTrader::query // -> KSycoca running kbuildsycoca -> nested event loop. if (m_fullyConstructed) { KonqFrameBase::Options flags = KonqFrameBase::saveHistoryItems; m_pViewManager->saveViewConfigToGroup(config, flags); } } void KonqMainWindow::readProperties(const KConfigGroup &configGroup) { m_pViewManager->loadViewConfigFromGroup(configGroup, QString() /*no profile name*/); // read window settings applyMainWindowSettings(configGroup); } void KonqMainWindow::setInitialFrameName(const QString &name) { m_initialFrameName = name; } void KonqMainWindow::updateOpenWithActions() { unplugActionList(QStringLiteral("openwithbase")); unplugActionList(QStringLiteral("openwith")); qDeleteAll(m_openWithActions); m_openWithActions.clear(); delete m_openWithMenu; m_openWithMenu = 0; if (!KAuthorized::authorizeAction(QStringLiteral("openwith"))) { return; } m_openWithMenu = new KActionMenu(i18n("&Open With"), this); const KService::List &services = m_currentView->appServiceOffers(); KService::List::ConstIterator it = services.constBegin(); const KService::List::ConstIterator end = services.constEnd(); const int baseOpenWithItems = qMax(KonqSettings::openWithItems(), 0); int idxService = 0; for (; it != end; ++it, ++idxService) { QAction *action; if (idxService < baseOpenWithItems) { action = new QAction(i18n("Open with %1", (*it)->name()), this); } else { action = new QAction((*it)->name(), this); } action->setIcon(QIcon::fromTheme((*it)->icon())); connect(action, SIGNAL(triggered()), this, SLOT(slotOpenWith())); actionCollection()->addAction((*it)->desktopEntryName(), action); if (idxService < baseOpenWithItems) { m_openWithActions.append(action); } else { m_openWithMenu->addAction(action); } } if (services.count() > 0) { plugActionList(QStringLiteral("openwithbase"), m_openWithActions); QList openWithActionsMenu; if (idxService > baseOpenWithItems) { openWithActionsMenu.append(m_openWithMenu); } QAction *sep = new QAction(this); sep->setSeparator(true); openWithActionsMenu.append(sep); plugActionList(QStringLiteral("openwith"), openWithActionsMenu); } } void KonqMainWindow::updateViewModeActions() { unplugViewModeActions(); Q_FOREACH (QAction *action, m_viewModesGroup->actions()) { Q_FOREACH (QWidget *w, action->associatedWidgets()) { w->removeAction(action); } delete action; } delete m_viewModeMenu; m_viewModeMenu = 0; const KService::List services = m_currentView->partServiceOffers(); if (services.count() <= 1) { return; } m_viewModeMenu = new KActionMenu(i18nc("@action:inmenu View", "&View Mode"), this); //actionCollection()->addAction( "viewModeMenu", m_viewModeMenu ); KService::List::ConstIterator it = services.constBegin(); const KService::List::ConstIterator end = services.constEnd(); for (; it != end; ++it) { const KService::Ptr service = *it; const QString desktopEntryName = service->desktopEntryName(); bool bIsCurrentView = desktopEntryName == m_currentView->service()->desktopEntryName(); const QList actions = service->actions(); if (!actions.isEmpty()) { // The service provides several view modes, like DolphinPart // -> create one action per view mode Q_FOREACH (const KServiceAction &serviceAction, actions) { // Create a KToggleAction for each view mode, and plug it into the menu KToggleAction *action = new KToggleAction(QIcon::fromTheme(serviceAction.icon()), serviceAction.text(), this); //actionCollection()->addAction(desktopEntryName /*not unique!*/, action); action->setObjectName(desktopEntryName + QLatin1String("-viewmode")); action->setData(QVariant(serviceAction.name())); action->setActionGroup(m_viewModesGroup); m_viewModeMenu->menu()->addAction(action); if (bIsCurrentView && m_currentView->internalViewMode() == serviceAction.name()) { action->setChecked(true); } } } else { // The service only provides one view mode (common case) QString serviceText = service->genericName(); if (serviceText.isEmpty()) { serviceText = service->name(); } // Create a KToggleAction for this view mode, and plug it into the menu KToggleAction *action = new KToggleAction(QIcon::fromTheme(service->icon()), serviceText, this); // NOTE: "-viewmode" is appended to desktopEntryName to avoid overwritting existing // action, e.g. konsolepart added through ToggleViewGUIClient in the ctor will be // overwritten by the view mode konsolepart action added here. #266517. actionCollection()->addAction(desktopEntryName + QLatin1String("-viewmode"), action); action->setActionGroup(m_viewModesGroup); m_viewModeMenu->menu()->addAction(action); action->setChecked(bIsCurrentView); } } // No view mode for actions toggable views // (The other way would be to enforce a better servicetype for them, than Browser/View) if (!m_currentView->isToggleView() /* already tested: && services.count() > 1 */ && m_viewModeMenu) { plugViewModeActions(); } } void KonqMainWindow::slotInternalViewModeChanged() { KParts::ReadOnlyPart *part = static_cast(sender()); KonqView *view = m_mapViews.value(part); if (view) { const QString actionName = view->service()->desktopEntryName(); const QString actionData = view->internalViewMode(); Q_FOREACH (QAction *action, m_viewModesGroup->actions()) { if (action->objectName() == actionName + QLatin1String("-viewmode") && action->data().toString() == actionData) { action->setChecked(true); break; } } } } void KonqMainWindow::plugViewModeActions() { QList lst; if (m_viewModeMenu) { lst.append(m_viewModeMenu); } plugActionList(QStringLiteral("viewmode"), lst); } void KonqMainWindow::unplugViewModeActions() { unplugActionList(QStringLiteral("viewmode")); } void KonqMainWindow::updateBookmarkBar() { KToolBar *bar = qFindChild(this, QStringLiteral("bookmarkToolBar")); if (!bar) { return; } if (m_paBookmarkBar && bar->actions().isEmpty()) { bar->hide(); } } void KonqMainWindow::closeEvent(QCloseEvent *e) { // This breaks session management (the window is withdrawn in kwin) // so let's do this only when closed by the user. if (!qApp->isSavingSession()) { KonqFrameTabs *tabContainer = m_pViewManager->tabContainer(); if (tabContainer->count() > 1) { KSharedConfig::Ptr config = KSharedConfig::openConfig(); KConfigGroup cs(config, QStringLiteral("Notification Messages")); if (!cs.hasKey("MultipleTabConfirm")) { switch ( KMessageBox::warningYesNoCancel( this, i18n("You have multiple tabs open in this window, " "are you sure you want to quit?"), i18nc("@title:window", "Confirmation"), KStandardGuiItem::closeWindow(), KGuiItem(i18n("C&lose Current Tab"), QStringLiteral("tab-close")), KStandardGuiItem::cancel(), QStringLiteral("MultipleTabConfirm") ) ) { case KMessageBox::Yes : break; case KMessageBox::No : e->ignore(); slotRemoveTab(); return; case KMessageBox::Cancel : e->ignore(); return; default: Q_UNREACHABLE(); } } } const int originalTabIndex = tabContainer->currentIndex(); for (int tabIndex = 0; tabIndex < tabContainer->count(); ++tabIndex) { KonqFrameBase *tab = tabContainer->tabAt(tabIndex); if (!KonqModifiedViewsCollector::collect(tab).isEmpty()) { m_pViewManager->showTab(tabIndex); const QString question = m_pViewManager->isTabBarVisible() ? i18n("This tab contains changes that have not been submitted.\nClosing the window will discard these changes.") : i18n("This page contains changes that have not been submitted.\nClosing the window will discard these changes."); if (KMessageBox::warningContinueCancel( this, question, i18nc("@title:window", "Discard Changes?"), KGuiItem(i18n("&Discard Changes"), QStringLiteral("application-exit")), KStandardGuiItem::cancel(), QStringLiteral("discardchangesclose")) != KMessageBox::Continue) { e->ignore(); m_pViewManager->showTab(originalTabIndex); return; } } } if (settingsDirty() && autoSaveSettings()) { saveAutoSaveSettings(); } addClosedWindowToUndoList(); } // We're going to close - tell the parts MapViews::ConstIterator it = m_mapViews.constBegin(); MapViews::ConstIterator end = m_mapViews.constEnd(); for (; it != end; ++it) { if ((*it)->part() && (*it)->part()->widget()) { QApplication::sendEvent((*it)->part()->widget(), e); } } KParts::MainWindow::closeEvent(e); } void KonqMainWindow::addClosedWindowToUndoList() { qDebug(); // 1. We get the current title int numTabs = m_pViewManager->tabContainer()->childFrameList().count(); QString title(i18n("no name")); if (m_currentView) { title = m_currentView->caption(); } // 2. Create the KonqClosedWindowItem and save its config KonqClosedWindowItem *closedWindowItem = new KonqClosedWindowItem(title, m_pUndoManager->newCommandSerialNumber(), numTabs); saveProperties(closedWindowItem->configGroup()); // 3. Add the KonqClosedWindowItem to the undo list m_paClosedItems->setEnabled(true); m_pUndoManager->addClosedWindowItem(closedWindowItem); qDebug() << "done"; } void KonqMainWindow::updateWindowIcon() { const QString url = m_combo->currentText(); const QPixmap pix = KonqPixmapProvider::self()->pixmapFor(url, KIconLoader::SizeSmall); KParts::MainWindow::setWindowIcon(pix); QPixmap big = pix; if (!url.isEmpty()) { big = KonqPixmapProvider::self()->pixmapFor(url, KIconLoader::SizeMedium); } KWindowSystem::setIcons(winId(), big, pix); } void KonqMainWindow::slotIntro() { - openUrl(0, QUrl(QStringLiteral("about:"))); + openUrl(0, QUrl(KonqAboutPage::aboutProtocol() + QChar(':'))); } void KonqMainWindow::goURL() { QLineEdit *lineEdit = comboEdit(); if (!lineEdit) { return; } QKeyEvent event(QEvent::KeyPress, Qt::Key_Return, Qt::NoModifier, QChar('\n')); QApplication::sendEvent(lineEdit, &event); } /** * Adds the URL of a KonqView to the closed tabs list. * This slot gets called each time a View is closed. */ void KonqMainWindow::slotAddClosedUrl(KonqFrameBase *tab) { qDebug(); QString title(i18n("no name")), url(QStringLiteral("about:blank")); // Did the tab contain a single frame, or a splitter? KonqFrame *frame = dynamic_cast(tab); if (!frame) { KonqFrameContainer *frameContainer = dynamic_cast(tab); if (frameContainer->activeChildView()) { frame = frameContainer->activeChildView()->frame(); } } KParts::ReadOnlyPart *part = frame ? frame->part() : 0; if (part) { url = part->url().url(); } if (frame) { title = frame->title().trimmed(); } if (title.isEmpty()) { title = url; } title = KStringHandler::csqueeze(title, 50); // Now we get the position of the tab const int index = m_pViewManager->tabContainer()->childFrameList().indexOf(tab); KonqClosedTabItem *closedTabItem = new KonqClosedTabItem(url, title, index, m_pUndoManager->newCommandSerialNumber()); QString prefix = KonqFrameBase::frameTypeToString(tab->frameType()) + QString::number(0); closedTabItem->configGroup().writeEntry("RootItem", prefix); prefix.append(QLatin1Char('_')); KonqFrameBase::Options flags = KonqFrameBase::saveHistoryItems; tab->saveConfig(closedTabItem->configGroup(), prefix, flags, 0L, 0, 1); m_paClosedItems->setEnabled(true); m_pUndoManager->addClosedTabItem(closedTabItem); qDebug() << "done"; } void KonqMainWindow::slotLocationLabelActivated() { focusLocationBar(); QLineEdit *edit = comboEdit(); if (edit) { edit->selectAll(); } } void KonqMainWindow::slotOpenURL(const QUrl &url) { openUrl(0, url); } bool KonqMainWindow::sidebarVisible() const { QAction *a = m_toggleViewGUIClient->action(QStringLiteral("konq_sidebartng")); return (a && static_cast(a)->isChecked()); } bool KonqMainWindow::fullScreenMode() const { return m_ptaFullScreen->isChecked(); } void KonqMainWindow::slotAddWebSideBar(const QUrl &url, const QString &name) { if (url.isEmpty() && name.isEmpty()) { return; } qDebug() << "Requested to add URL" << url << " [" << name << "] to the sidebar!"; QAction *a = m_toggleViewGUIClient->action(QStringLiteral("konq_sidebartng")); if (!a) { KMessageBox::sorry(0, i18n("Your sidebar is not functional or unavailable. A new entry cannot be added."), i18nc("@title:window", "Web Sidebar")); return; } int rc = KMessageBox::questionYesNo(0, i18n("Add new web extension \"%1\" to your sidebar?", name.isEmpty() ? name : url.toDisplayString()), i18nc("@title:window", "Web Sidebar"), KGuiItem(i18n("Add")), KGuiItem(i18n("Do Not Add"))); if (rc == KMessageBox::Yes) { // Show the sidebar if (!static_cast(a)->isChecked()) { a->trigger(); } // Tell it to add a new panel MapViews::ConstIterator it; for (it = viewMap().constBegin(); it != viewMap().constEnd(); ++it) { KonqView *view = it.value(); if (view) { KService::Ptr svc = view->service(); if (svc->desktopEntryName() == QLatin1String("konq_sidebartng")) { emit view->browserExtension()->addWebSideBar(url, name); break; } } } } } void KonqMainWindow::addBookmarksIntoCompletion(const KBookmarkGroup &group) { const QString http = QStringLiteral("http"); const QString ftp = QStringLiteral("ftp"); if (group.isNull()) { return; } for (KBookmark bm = group.first(); !bm.isNull(); bm = group.next(bm)) { if (bm.isGroup()) { addBookmarksIntoCompletion(bm.toGroup()); continue; } QUrl url = bm.url(); if (!url.isValid()) { continue; } QString u = url.toDisplayString(); s_pCompletion->addItem(u); if (url.isLocalFile()) { s_pCompletion->addItem(url.toLocalFile()); } else if (url.scheme() == http) { s_pCompletion->addItem(u.mid(7)); } else if (url.scheme() == ftp && url.host().startsWith(ftp)) { s_pCompletion->addItem(u.mid(6)); } } } // // the smart popup completion code , // // prepend http://www. or http:// if there's no protocol in 's' // This is used only when there are no completion matches static QString hp_tryPrepend(const QString &s) { if (s.isEmpty() || s[0] == QLatin1Char('/') || s[0] == QLatin1Char('~')) { return QString(); } bool containsSpace = false; for (int pos = 0; pos < s.length() - 2; // 4 = ://x ++pos) { if (s[ pos ] == ':' && s[ pos + 1 ] == '/' && s[ pos + 2 ] == '/') { return QString(); } if (!s[ pos ].isLetter()) { break; } if (s[pos].isSpace()) { containsSpace = true; break; } } if (containsSpace || s.at(s.length() - 1).isSpace()) { return QString(); } return (s.startsWith(QLatin1String("www.")) ? "http://" : "http://www.") + s; } static void hp_removeDupe(KCompletionMatches &l, const QString &dupe, KCompletionMatches::Iterator it_orig) { KCompletionMatches::Iterator it = it_orig + 1; while (it != l.end()) { if ((*it).value() == dupe) { (*it_orig).first = qMax((*it_orig).first, (*it).key()); it = l.erase(it); continue; } ++it; } } // remove duplicates like 'http://www.kde.org' and 'http://www.kde.org/' // (i.e. the trailing slash) // some duplicates are also created by prepending protocols static void hp_removeDuplicates(KCompletionMatches &l) { QString http = QStringLiteral("http://"); QString ftp = QStringLiteral("ftp://ftp."); QString file = QStringLiteral("file:"); QString file2 = QStringLiteral("file://"); l.removeDuplicates(); for (KCompletionMatches::Iterator it = l.begin(); it != l.end(); ++it) { QString str = (*it).value(); if (str.startsWith(http)) { if (str.indexOf('/', 7) < 0) { // http://something hp_removeDupe(l, str + '/', it); hp_removeDupe(l, str.mid(7) + '/', it); } else if (str[ str.length() - 1 ] == '/') { hp_removeDupe(l, str.left(str.length() - 1), it); hp_removeDupe(l, str.left(str.length() - 1).mid(7), it); } hp_removeDupe(l, str.mid(7), it); } else if (str.startsWith(ftp)) { // ftp://ftp. hp_removeDupe(l, str.mid(6), it); // remove dupes without ftp:// } else if (str.startsWith(file2)) { hp_removeDupe(l, str.mid(7), it); // remove dupes without file:// } else if (str.startsWith(file)) { hp_removeDupe(l, str.mid(5), it); // remove dupes without file: } } } static void hp_removeCommonPrefix(KCompletionMatches &l, const QString &prefix) { for (KCompletionMatches::Iterator it = l.begin(); it != l.end(); ) { if ((*it).value().startsWith(prefix)) { it = l.erase(it); continue; } ++it; } } // don't include common prefixes like 'http://', i.e. when s == 'h', include // http://hotmail.com but don't include everything just starting with 'http://' static void hp_checkCommonPrefixes(KCompletionMatches &matches, const QString &s) { static const char *const prefixes[] = { "http://", "https://", "www.", "ftp://", "http://www.", "https://www.", "ftp://ftp.", "file:", "file://", NULL }; for (const char *const *pos = prefixes; *pos != NULL; ++pos) { QString prefix = *pos; if (prefix.startsWith(s)) { hp_removeCommonPrefix(matches, prefix); } } } QStringList KonqMainWindow::historyPopupCompletionItems(const QString &s) { const QString http = QStringLiteral("http://"); const QString https = QStringLiteral("https://"); const QString www = QStringLiteral("http://www."); const QString wwws = QStringLiteral("https://www."); const QString ftp = QStringLiteral("ftp://"); const QString ftpftp = QStringLiteral("ftp://ftp."); const QString file = QStringLiteral("file:"); // without /, because people enter /usr etc. const QString file2 = QStringLiteral("file://"); if (s.isEmpty()) { return QStringList(); } KCompletionMatches matches = s_pCompletion->allWeightedMatches(s); hp_checkCommonPrefixes(matches, s); bool checkDuplicates = false; if (!s.startsWith(ftp)) { matches += s_pCompletion->allWeightedMatches(ftp + s); if (QStringLiteral("ftp.").startsWith(s)) { hp_removeCommonPrefix(matches, ftpftp); } checkDuplicates = true; } if (!s.startsWith(https)) { matches += s_pCompletion->allWeightedMatches(https + s); if (QStringLiteral("www.").startsWith(s)) { hp_removeCommonPrefix(matches, wwws); } checkDuplicates = true; } if (!s.startsWith(http)) { matches += s_pCompletion->allWeightedMatches(http + s); if (QStringLiteral("www.").startsWith(s)) { hp_removeCommonPrefix(matches, www); } checkDuplicates = true; } if (!s.startsWith(www)) { matches += s_pCompletion->allWeightedMatches(www + s); checkDuplicates = true; } if (!s.startsWith(wwws)) { matches += s_pCompletion->allWeightedMatches(wwws + s); checkDuplicates = true; } if (!s.startsWith(ftpftp)) { matches += s_pCompletion->allWeightedMatches(ftpftp + s); checkDuplicates = true; } if (!s.startsWith(file)) { matches += s_pCompletion->allWeightedMatches(file + s); checkDuplicates = true; } if (!s.startsWith(file2)) { matches += s_pCompletion->allWeightedMatches(file2 + s); checkDuplicates = true; } if (checkDuplicates) { hp_removeDuplicates(matches); } QStringList items = matches.list(); if (items.count() == 0 && !s.contains(':') && !s.isEmpty() && s[ 0 ] != '/') { QString pre = hp_tryPrepend(s); if (!pre.isNull()) { items += pre; } } return items; } #ifndef NDEBUG void KonqMainWindow::dumpViewList() { qDebug() << m_mapViews.count() << "views:"; MapViews::Iterator end = m_mapViews.end(); for (MapViews::Iterator it = m_mapViews.begin(); it != end; ++it) { KonqView *view = it.value(); qDebug() << view << view->part(); } } #endif void KonqMainWindow::insertChildFrame(KonqFrameBase *frame, int /*index*/) { m_pChildFrame = frame; m_pActiveChild = frame; frame->setParentContainer(this); if (centralWidget() && centralWidget() != frame->asQWidget()) { centralWidget()->setParent(0); // workaround Qt-4.1.2 crash (reported) setCentralWidget(0); } setCentralWidget(frame->asQWidget()); } void KonqMainWindow::childFrameRemoved(KonqFrameBase *frame) { Q_ASSERT(frame == m_pChildFrame); Q_UNUSED(frame) m_pChildFrame = 0; m_pActiveChild = 0; } void KonqMainWindow::saveConfig(KConfigGroup &config, const QString &prefix, const KonqFrameBase::Options &options, KonqFrameBase *docContainer, int id, int depth) { if (m_pChildFrame) { m_pChildFrame->saveConfig(config, prefix, options, docContainer, id, depth); } } void KonqMainWindow::copyHistory(KonqFrameBase *other) { if (m_pChildFrame) { m_pChildFrame->copyHistory(other); } } void KonqMainWindow::setTitle(const QString &/*title*/, QWidget * /*sender*/) { } void KonqMainWindow::setTabIcon(const QUrl &/*url*/, QWidget * /*sender*/) { } QWidget *KonqMainWindow::asQWidget() { return this; } KonqFrameBase::FrameType KonqMainWindow::frameType() const { return KonqFrameBase::MainWindow; } KonqFrameBase *KonqMainWindow::childFrame()const { return m_pChildFrame; } void KonqMainWindow::setActiveChild(KonqFrameBase * /*activeChild*/) { } void KonqMainWindow::setWorkingTab(int index) { m_workingTab = index; } bool KonqMainWindow::isMimeTypeAssociatedWithSelf(const QString &mimeType) { return isMimeTypeAssociatedWithSelf(mimeType, KMimeTypeTrader::self()->preferredService(mimeType, QStringLiteral("Application"))); } bool KonqMainWindow::isMimeTypeAssociatedWithSelf(const QString &/*mimeType*/, const KService::Ptr &offer) { // Prevention against user stupidity : if the associated app for this mimetype // is konqueror/kfmclient, then we'll loop forever. So we have to // 1) force embedding first, if that works we're ok // 2) check what KRun is going to do before calling it. return (offer && (offer->desktopEntryName() == QLatin1String("konqueror") || offer->exec().trimmed().startsWith(QLatin1String("kfmclient")))); } bool KonqMainWindow::refuseExecutingKonqueror(const QString &mimeType) { if (activeViewsNotLockedCount() > 0) { // if I lock the only view, then there's no error: open links in a new window 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)); return true; // we refuse indeed } return false; // no error } bool KonqMainWindow::event(QEvent *e) { if (e->type() == QEvent::StatusTip) { if (m_currentView && m_currentView->frame()->statusbar()) { KonqFrameStatusBar *statusBar = m_currentView->frame()->statusbar(); statusBar->message(static_cast(e)->tip()); } } if (KonqFileSelectionEvent::test(e) || KonqFileMouseOverEvent::test(e)) { // Forward the event to all views MapViews::ConstIterator it = m_mapViews.constBegin(); MapViews::ConstIterator end = m_mapViews.constEnd(); for (; it != end; ++it) { QApplication::sendEvent((*it)->part(), e); } return true; } if (KParts::OpenUrlEvent::test(e)) { KParts::OpenUrlEvent *ev = static_cast(e); // Forward the event to all views MapViews::ConstIterator it = m_mapViews.constBegin(); MapViews::ConstIterator end = m_mapViews.constEnd(); for (; it != end; ++it) { // Don't resend to sender if (it.key() != ev->part()) { //qDebug() << "Sending event to view" << it.key()->metaObject()->className(); QApplication::sendEvent(it.key(), e); } } } return KParts::MainWindow::event(e); } void KonqMainWindow::slotUndoTextChanged(const QString &newText) { m_paUndo->setText(newText); } KonqView *KonqMainWindow::currentView() const { return m_currentView; } bool KonqMainWindow::accept(KonqFrameVisitor *visitor) { return visitor->visit(this) && (!m_pChildFrame || m_pChildFrame->accept(visitor)) && visitor->endVisit(this); } QLineEdit *KonqMainWindow::comboEdit() { return m_combo ? m_combo->lineEdit() : 0; } diff --git a/src/konqmisc.cpp b/src/konqmisc.cpp index b726d4c26..ef4024bfc 100644 --- a/src/konqmisc.cpp +++ b/src/konqmisc.cpp @@ -1,117 +1,113 @@ /* This file is part of the KDE project Copyright (C) 1998, 1999, 2010 David Faure This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "konqmisc.h" #include #include "konqsettingsxt.h" #include "konqmainwindow.h" #include "konqviewmanager.h" #include "konqview.h" #include "konqmainwindowfactory.h" +#include "konqaboutpage.h" #include #include #include #include #include #include #include #include /********************************************** * * KonqMisc * **********************************************/ KonqMainWindow *KonqMisc::newWindowFromHistory(KonqView *view, int steps) { int oldPos = view->historyIndex(); int newPos = oldPos + steps; const HistoryEntry *he = view->historyAt(newPos); if (!he) { return Q_NULLPTR; } KonqMainWindow *mainwindow = KonqMainWindowFactory::createEmptyWindow(); if (!mainwindow) { return Q_NULLPTR; } KonqView *newView = mainwindow->currentView(); if (!newView) { return Q_NULLPTR; } newView->copyHistory(view); newView->setHistoryIndex(newPos); newView->restoreHistory(); mainwindow->show(); return mainwindow; } QUrl KonqMisc::konqFilteredURL(KonqMainWindow *parent, const QString &_url, const QUrl ¤tDirectory) { Q_UNUSED(parent); // Useful if we want to change the error handling again - if (!_url.startsWith(QLatin1String("about:"))) { // Don't filter "about:" URLs + if (!_url.startsWith(KonqAboutPage::aboutProtocol() + QLatin1Char(':'))) { // Don't filter "about:" URLs KUriFilterData data(_url); if (currentDirectory.isLocalFile()) { data.setAbsolutePath(currentDirectory.toLocalFile()); } // We do not want to the filter to check for executables // from the location bar. data.setCheckForExecutables(false); if (KUriFilter::self()->filterUri(data)) { if (data.uriType() == KUriFilterData::Error) { if (data.errorMsg().isEmpty()) { return KParts::BrowserRun::makeErrorUrl(KIO::ERR_MALFORMED_URL, _url, QUrl(_url)); } else { return KParts::BrowserRun::makeErrorUrl(KIO::ERR_SLAVE_DEFINED, data.errorMsg(), QUrl(_url)); } } else { return data.uri(); } } // NOTE: a valid URL like http://kde.org always passes the filtering test. // As such, this point could only be reached when _url is NOT a valid URL. return KParts::BrowserRun::makeErrorUrl(KIO::ERR_MALFORMED_URL, _url, QUrl(_url)); } - const bool isKnownAbout = (_url == QLatin1String("about:blank") - || _url == QLatin1String("about:plugins") - || _url.startsWith(QLatin1String("about:konqueror"))); - - return isKnownAbout ? QUrl(_url) : QUrl(QStringLiteral("about:")); + return QUrl(_url); } QString KonqMisc::encodeFilename(QString filename) { return filename.replace(':', '_'); } QString KonqMisc::decodeFilename(QString filename) { return filename.replace('_', ':'); } - diff --git a/src/konqueror.kcfg b/src/konqueror.kcfg index f2e8447df..d3aae3ec7 100644 --- a/src/konqueror.kcfg +++ b/src/konqueror.kcfg @@ -1,531 +1,532 @@ + konqaboutpage.h - about:konqueror + KonqAboutPage::aboutProtocol() + ":konqueror" This is the URL of the web page where Konqueror will start from. http://www.kde.org This is the URL of the web page where Konqueror will jump to when the \"Home\" button is pressed. 20 0 This sets the maximum number of closed items that will be stored in memory. This limit will not be surpassed. false If this option is checked, Konqueror will open a new window when you open a folder, rather than showing that folder's contents in the current window. true Here you can control if, when moving the mouse over a file, you want to see a small popup window with additional information about that file 6 true Here you can control if you want the popup window to contain a larger preview for the file, when moving the mouse over it true Check this if you want 'Delete' menu commands to be displayed on the desktop and in the file manager's menus and context menus. You can always delete files when hidden by holding the Shift key while calling 'Move to Trash'. true false false false true false false false false true true 30 3 2 Number of Open With items in the File menu QFont("Sans Serif") This is the font used to display text in Konqueror windows. 12 7 QString() true true false true true true 10 true true false 50 false true false true 60 #if defined(PATH_JAVA) PATH_JAVA #else "java" #endif true false false true false true false true KCompletion::CompletionPopup 10 true This option tells Konqueror whether to ask for a confirmation when you delete a file without using the trash folder. Warning, deleted files can not be recovered, so it is recommended to leave this confirmation enabled. true This option tells Konqueror whether to ask for a confirmation when you move the file to your trash folder, from where it can be recovered very easily. false If true, when opening a session from within the sessions dialog the tabs will be opened inside current window. 10 diff --git a/src/konqview.cpp b/src/konqview.cpp index 95318838a..de0079dfd 100644 --- a/src/konqview.cpp +++ b/src/konqview.cpp @@ -1,1482 +1,1482 @@ /* This file is part of the KDE project Copyright (C) 1998-2005 David Faure This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "konqaboutpage.h" #include "konqview.h" #include "KonqViewAdaptor.h" #include "konqsettingsxt.h" #include "konqframestatusbar.h" #include "konqrun.h" #include #include "konqviewmanager.h" #include "konqtabs.h" #include "konqbrowseriface.h" #include "konqhistorymanager.h" #include "konqpixmapprovider.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef KActivities_FOUND #endif #include #include #include #include #include #include #include #include #include #include #include //#define DEBUG_HISTORY KonqView::KonqView(KonqViewFactory &viewFactory, KonqFrame *viewFrame, KonqMainWindow *mainWindow, const KService::Ptr &service, const KService::List &partServiceOffers, const KService::List &appServiceOffers, const QString &serviceType, bool passiveMode ) { m_pKonqFrame = viewFrame; m_pKonqFrame->setView(this); m_sLocationBarURL = QLatin1String(""); m_pageSecurity = KonqMainWindow::NotCrypted; m_bLockHistory = false; m_doPost = false; m_pMainWindow = mainWindow; m_pRun = NULL; m_pPart = NULL; m_randID = KRandom::random(); m_service = service; m_partServiceOffers = partServiceOffers; m_appServiceOffers = appServiceOffers; m_serviceType = serviceType; m_lstHistoryIndex = -1; m_bLoading = false; m_bPendingRedirection = false; m_bPassiveMode = passiveMode; m_bLockedLocation = false; m_bLinkedView = false; m_bAborted = false; m_bToggleView = false; m_bDisableScrolling = false; m_bGotIconURL = false; m_bPopupMenuEnabled = true; m_browserIface = new KonqBrowserInterface(this); m_bFollowActive = false; m_bBuiltinView = false; m_bURLDropHandling = false; m_bErrorURL = false; #ifdef KActivities_FOUND m_activityResourceInstance = new KActivities::ResourceInstance(mainWindow->winId(), this); #endif switchView(viewFactory); } KonqView::~KonqView() { //qDebug() << "part=" << m_pPart; // We did so ourselves for passive views if (m_pPart != 0L) { finishedWithCurrentURL(); if (isPassiveMode()) { disconnect(m_pPart, SIGNAL(destroyed()), m_pMainWindow->viewManager(), SLOT(slotObjectDestroyed())); } if (m_pPart->manager()) { m_pPart->manager()->removePart(m_pPart); // ~Part does this, but we have to do it before (#213876, #207173) } delete m_pPart; } qDeleteAll(m_lstHistory); m_lstHistory.clear(); setRun(0L); //qDebug() << this << "done"; } void KonqView::openUrl(const QUrl &url, const QString &locationBarURL, const QString &nameFilter, bool tempFile) { qDebug() << "url=" << url << "locationBarURL=" << locationBarURL; setPartMimeType(); KParts::OpenUrlArguments args; if (m_pPart) { args = m_pPart->arguments(); } KParts::BrowserExtension *ext = browserExtension(); KParts::BrowserArguments browserArgs; if (ext) { browserArgs = ext->browserArguments(); } // Typing "Enter" again after the URL of an aborted view, triggers a reload. if (m_bAborted && m_pPart && m_pPart->url() == url && !browserArgs.doPost()) { if (!prepareReload(args, browserArgs, false /* not softReload */)) { return; } m_pPart->setArguments(args); } #ifdef DEBUG_HISTORY qDebug() << "m_bLockedLocation=" << m_bLockedLocation << "browserArgs.lockHistory()=" << browserArgs.lockHistory(); #endif if (browserArgs.lockHistory()) { lockHistory(); } if (!m_bLockHistory) { // Store this new URL in the history, removing any existing forward history. // We do this first so that everything is ready if a part calls completed(). createHistoryEntry(); } else { m_bLockHistory = false; } if (m_pPart) { m_pPart->setProperty("nameFilter", nameFilter); } if (m_bDisableScrolling) { callExtensionMethod("disableScrolling"); } // Set location-bar URL, except for error urls, where we know the browser component // will set back the url with the error anyway. if (url.scheme() != QLatin1String("error")) { setLocationBarURL(locationBarURL); } setPageSecurity(KonqMainWindow::NotCrypted); if (!args.reload()) { // Save the POST data that is necessary to open this URL // (so that reload can re-post it) m_doPost = browserArgs.doPost(); m_postContentType = browserArgs.contentType(); m_postData = browserArgs.postData; // Save the referrer m_pageReferrer = args.metaData()[QStringLiteral("referrer")]; } if (tempFile) { // Store the path to the tempfile. Yes, we could store a bool only, // but this would be more dangerous. If anything goes wrong in the code, // we might end up deleting a real file. if (url.isLocalFile()) { m_tempFile = url.toLocalFile(); } else { qWarning() << "Tempfile option is set, but URL is remote:" << url; } } aboutToOpenURL(url, args); doOpenUrl(url); updateHistoryEntry(false /* don't save location bar URL yet */); // add pending history entry KonqHistoryManager::kself()->addPending(url, locationBarURL, QString()); #ifdef DEBUG_HISTORY qDebug() << "Current position:" << historyIndex(); #endif #ifdef KActivities_FOUND m_activityResourceInstance->setUri(url); if (m_pPart->widget()->hasFocus()) { m_activityResourceInstance->notifyFocusedIn(); } #endif } void KonqView::switchView(KonqViewFactory &viewFactory) { //qDebug(); KParts::ReadOnlyPart *oldPart = m_pPart; KParts::ReadOnlyPart *part = m_pKonqFrame->attach(viewFactory); // creates the part if (!part) { return; } m_pPart = part; // Set the statusbar in the BE asap to avoid a KMainWindow statusbar being created. KParts::StatusBarExtension *sbext = statusBarExtension(); if (sbext) { sbext->setStatusBar(frame()->statusbar()); } // Activate the new part if (oldPart) { m_pPart->setObjectName(oldPart->objectName()); emit sigPartChanged(this, oldPart, m_pPart); delete oldPart; } connectPart(); QVariant prop; prop = m_service->property(QStringLiteral("X-KDE-BrowserView-FollowActive")); if (prop.isValid() && prop.toBool()) { //qDebug() << "X-KDE-BrowserView-FollowActive -> setFollowActive"; setFollowActive(true); } prop = m_service->property(QStringLiteral("X-KDE-BrowserView-Built-Into")); m_bBuiltinView = (prop.isValid() && prop.toString() == QLatin1String("konqueror")); if (!m_pMainWindow->viewManager()->isLoadingProfile()) { // Honor "non-removable passive mode" (like the dirtree) prop = m_service->property(QStringLiteral("X-KDE-BrowserView-PassiveMode")); if (prop.isValid() && prop.toBool()) { qDebug() << "X-KDE-BrowserView-PassiveMode -> setPassiveMode"; setPassiveMode(true); // set as passive } // Honor "linked view" prop = m_service->property(QStringLiteral("X-KDE-BrowserView-LinkedView")); if (prop.isValid() && prop.toBool()) { setLinkedView(true); // set as linked // Two views : link both if (m_pMainWindow->viewCount() <= 2) { // '1' can happen if this view is not yet in the map KonqView *otherView = m_pMainWindow->otherView(this); if (otherView) { otherView->setLinkedView(true); } } } } } bool KonqView::ensureViewSupports(const QString &mimeType, bool forceAutoEmbed) { if (supportsMimeType(mimeType)) { // could be more specific, let's store it so that OpenUrlArguments::mimeType is correct // testcase: http://acid3.acidtests.org/svg.xml should be opened as image/svg+xml m_serviceType = mimeType; return true; } return changePart(mimeType, QString(), forceAutoEmbed); } bool KonqView::changePart(const QString &mimeType, const QString &serviceName, bool forceAutoEmbed) { // Caller should call stop first. Q_ASSERT(!m_bLoading); //qDebug() << "mimeType=" << mimeType // << "requested serviceName=" << serviceName // << "current service name=" << m_service->desktopEntryName(); if (serviceName == m_service->desktopEntryName()) { m_serviceType = mimeType; return true; } if (isLockedViewMode()) { //qDebug() << "This view's mode is locked - can't change"; return false; // we can't do that if our view mode is locked } KService::List partServiceOffers, appServiceOffers; KService::Ptr service; KonqFactory konqFactory; KonqViewFactory viewFactory = konqFactory.createView(mimeType, serviceName, &service, &partServiceOffers, &appServiceOffers, forceAutoEmbed); if (viewFactory.isNull()) { return false; } m_serviceType = mimeType; m_partServiceOffers = partServiceOffers; m_appServiceOffers = appServiceOffers; // Check if that's already the kind of part we have -> no need to recreate it // Note: we should have an operator== for KService... if (m_service && m_service->entryPath() == service->entryPath()) { qDebug() << "Reusing service. Service type set to" << m_serviceType; if (m_pMainWindow->currentView() == this) { m_pMainWindow->updateViewModeActions(); } } else { m_service = service; switchView(viewFactory); } return true; } void KonqView::connectPart() { //qDebug(); connect(m_pPart, SIGNAL(started(KIO::Job*)), this, SLOT(slotStarted(KIO::Job*))); connect(m_pPart, SIGNAL(completed()), this, SLOT(slotCompleted())); connect(m_pPart, SIGNAL(completed(bool)), this, SLOT(slotCompleted(bool))); connect(m_pPart, SIGNAL(canceled(QString)), this, SLOT(slotCanceled(QString))); connect(m_pPart, SIGNAL(setWindowCaption(QString)), this, SLOT(setCaption(QString))); if (!internalViewMode().isEmpty()) { // Update checked action in "View Mode" menu when switching view mode in dolphin connect(m_pPart, SIGNAL(viewModeChanged()), m_pMainWindow, SLOT(slotInternalViewModeChanged())); } KParts::BrowserExtension *ext = browserExtension(); if (ext) { ext->setBrowserInterface(m_browserIface); connect(ext, SIGNAL(openUrlRequestDelayed(QUrl,KParts::OpenUrlArguments,KParts::BrowserArguments)), m_pMainWindow, SLOT(slotOpenURLRequest(QUrl,KParts::OpenUrlArguments,KParts::BrowserArguments))); if (m_bPopupMenuEnabled) { m_bPopupMenuEnabled = false; // force enablePopupMenu(true); } connect(ext, SIGNAL(setLocationBarUrl(QString)), this, SLOT(setLocationBarURL(QString))); connect(ext, SIGNAL(setIconUrl(QUrl)), this, SLOT(setIconURL(QUrl))); connect(ext, SIGNAL(setPageSecurity(int)), this, SLOT(setPageSecurity(int))); connect(ext, SIGNAL(createNewWindow(QUrl,KParts::OpenUrlArguments,KParts::BrowserArguments,KParts::WindowArgs,KParts::ReadOnlyPart**)), m_pMainWindow, SLOT(slotCreateNewWindow(QUrl,KParts::OpenUrlArguments,KParts::BrowserArguments,KParts::WindowArgs,KParts::ReadOnlyPart**))); connect(ext, SIGNAL(loadingProgress(int)), m_pKonqFrame->statusbar(), SLOT(slotLoadingProgress(int))); connect(ext, SIGNAL(speedProgress(int)), m_pKonqFrame->statusbar(), SLOT(slotSpeedProgress(int))); connect(ext, SIGNAL(selectionInfo(KFileItemList)), this, SLOT(slotSelectionInfo(KFileItemList))); connect(ext, SIGNAL(mouseOverInfo(KFileItem)), this, SLOT(slotMouseOverInfo(KFileItem))); connect(ext, SIGNAL(openUrlNotify()), this, SLOT(slotOpenURLNotify())); connect(ext, SIGNAL(enableAction(const char*,bool)), this, SLOT(slotEnableAction(const char*,bool))); connect(ext, SIGNAL(setActionText(const char*,QString)), this, SLOT(slotSetActionText(const char*,QString))); connect(ext, SIGNAL(moveTopLevelWidget(int,int)), this, SLOT(slotMoveTopLevelWidget(int,int))); connect(ext, SIGNAL(resizeTopLevelWidget(int,int)), this, SLOT(slotResizeTopLevelWidget(int,int))); connect(ext, SIGNAL(requestFocus(KParts::ReadOnlyPart*)), this, SLOT(slotRequestFocus(KParts::ReadOnlyPart*))); if (service()->desktopEntryName() != QLatin1String("konq_sidebartng")) { connect(ext, SIGNAL(infoMessage(QString)), m_pKonqFrame->statusbar(), SLOT(message(QString))); connect(ext, SIGNAL(addWebSideBar(QUrl,QString)), m_pMainWindow, SLOT(slotAddWebSideBar(QUrl,QString))); } } QVariant urlDropHandling; if (ext) { urlDropHandling = ext->property("urlDropHandling"); } else { urlDropHandling = QVariant(true); } // Handle url drops if // a) either the property says "ok" // or // b) the part is a plain krop (no BE) m_bURLDropHandling = (urlDropHandling.type() == QVariant::Bool && urlDropHandling.toBool()); if (m_bURLDropHandling) { m_pPart->widget()->setAcceptDrops(true); } m_pPart->widget()->installEventFilter(this); } void KonqView::slotEnableAction(const char *name, bool enabled) { if (m_pMainWindow->currentView() == this) { m_pMainWindow->enableAction(name, enabled); } // Otherwise, we don't have to do anything, the state of the action is // stored inside the browser-extension. } void KonqView::slotSetActionText(const char *name, const QString &text) { if (m_pMainWindow->currentView() == this) { m_pMainWindow->setActionText(name, text); } // Otherwise, we don't have to do anything, the state of the action is // stored inside the browser-extension. } void KonqView::slotMoveTopLevelWidget(int x, int y) { KonqFrameContainerBase *container = frame()->parentContainer(); // If tabs are shown, only accept to move the whole window if there's only one tab. if (container->frameType() != KonqFrameBase::Tabs || static_cast(container)->count() == 1) { m_pMainWindow->move(x, y); } } void KonqView::slotResizeTopLevelWidget(int w, int h) { KonqFrameContainerBase *container = frame()->parentContainer(); // If tabs are shown, only accept to resize the whole window if there's only one tab. // ### Maybe we could store the size requested by each tab and resize the window to the biggest one. if (container->frameType() != KonqFrameBase::Tabs || static_cast(container)->count() == 1) { m_pMainWindow->resize(w, h); } } void KonqView::slotStarted(KIO::Job *job) { //qDebug() << job; setLoading(true); if (job) { // Manage passwords properly... //qDebug() << "Window ID =" << m_pMainWindow->window()->winId(); KJobWidgets::setWindow(job, m_pMainWindow->window()); connect(job, SIGNAL(percent(KJob*,ulong)), this, SLOT(slotPercent(KJob*,ulong))); connect(job, SIGNAL(speed(KJob*,ulong)), this, SLOT(slotSpeed(KJob*,ulong))); connect(job, SIGNAL(infoMessage(KJob*,QString,QString)), this, SLOT(slotInfoMessage(KJob*,QString))); } } void KonqView::slotRequestFocus(KParts::ReadOnlyPart *) { m_pMainWindow->viewManager()->showTab(this); } void KonqView::setLoading(bool loading, bool hasPending /*= false*/) { //qDebug() << "loading=" << loading << "hasPending=" << hasPending; m_bLoading = loading; m_bPendingRedirection = hasPending; if (m_pMainWindow->currentView() == this) { m_pMainWindow->updateToolBarActions(hasPending); // Make sure the focus is restored on the part's widget and not the combo // box if it starts loading a request. See #304933. if (loading) { QWidget *partWidget = (m_pPart ? m_pPart->widget() : 0); if (partWidget && !partWidget->hasFocus()) { //qDebug() << "SET FOCUS on the widget"; partWidget->setFocus(); } } } m_pMainWindow->viewManager()->setLoading(this, loading || hasPending); } void KonqView::slotPercent(KJob *, unsigned long percent) { m_pKonqFrame->statusbar()->slotLoadingProgress(percent); } void KonqView::slotSpeed(KJob *, unsigned long bytesPerSecond) { m_pKonqFrame->statusbar()->slotSpeedProgress(bytesPerSecond); } void KonqView::slotInfoMessage(KJob *, const QString &msg) { m_pKonqFrame->statusbar()->message(msg); } void KonqView::slotCompleted() { slotCompleted(false); } void KonqView::slotCompleted(bool hasPending) { //qDebug() << "hasPending=" << hasPending; m_pKonqFrame->statusbar()->slotLoadingProgress(-1); if (! m_bLockHistory) { // Success... update history entry, including location bar URL updateHistoryEntry(true); if (m_bAborted) { // remove the pending entry on error KonqHistoryManager::kself()->removePending(url()); } else if (currentHistoryEntry()) // register as proper history entry KonqHistoryManager::kself()->confirmPending(url(), typedUrl(), currentHistoryEntry()->title); emit viewCompleted(this); } setLoading(false, hasPending); if (!m_bGotIconURL && !m_bAborted) { if (KonqSettings::enableFavicon() == true) { // Try to get /favicon.ico if (supportsMimeType(QStringLiteral("text/html")) && url().scheme().startsWith(QLatin1String("http"))) { KonqPixmapProvider::self()->downloadHostIcon(url()); } } } } void KonqView::slotCanceled(const QString &errorMsg) { //qDebug(); // The errorMsg comes from the ReadOnlyPart (usually from its kio job, but not necessarily). // It should probably be used in a KMessageBox // Let's use the statusbar for now m_pKonqFrame->statusbar()->setMessage(errorMsg, KonqStatusBarMessageLabel::Error); m_bAborted = true; slotCompleted(); } void KonqView::slotSelectionInfo(const KFileItemList &items) { m_selectedItems = items; KonqFileSelectionEvent ev(items, m_pPart); QApplication::sendEvent(m_pMainWindow, &ev); } void KonqView::slotMouseOverInfo(const KFileItem &item) { KonqFileMouseOverEvent ev(item, m_pPart); QApplication::sendEvent(m_pMainWindow, &ev); } void KonqView::setLocationBarURL(const QUrl &locationBarURL) { setLocationBarURL(locationBarURL.url(QUrl::PreferLocalFile)); } void KonqView::setLocationBarURL(const QString &locationBarURL) { //qDebug() << locationBarURL << "this=" << this; m_sLocationBarURL = locationBarURL; if (m_pMainWindow->currentView() == this) { //qDebug() << "is current view" << this; m_pMainWindow->setLocationBarURL(m_sLocationBarURL); m_pMainWindow->setPageSecurity(m_pageSecurity); } if (!m_bPassiveMode) { setTabIcon(QUrl::fromUserInput(m_sLocationBarURL)); } } void KonqView::setIconURL(const QUrl &iconURL) // This function sets the favIcon in konqui's window if enabled, // thus it is responsible for the icon in the taskbar. // It does not set the tab's favIcon. { if (KonqSettings::enableFavicon()) { KonqPixmapProvider::self()->setIconForUrl(QUrl(m_sLocationBarURL), iconURL); m_bGotIconURL = true; } } void KonqView::setPageSecurity(int pageSecurity) { m_pageSecurity = static_cast(pageSecurity); if (m_pMainWindow->currentView() == this) { m_pMainWindow->setPageSecurity(m_pageSecurity); } } void KonqView::setTabIcon(const QUrl &url) { if (!m_bPassiveMode && url.isValid()) { frame()->setTabIcon(url, 0L); } } void KonqView::setCaption(const QString &caption) { if (caption.isEmpty() || m_caption == caption) { return; } if (caption.startsWith("data:text/html")) return; QString adjustedCaption = caption; // For local URLs we prefer to use only the directory name if (url().isLocalFile()) { // Is the caption a URL? If so, is it local? If so, only display the filename! const QUrl captionUrl(QUrl::fromUserInput(caption)); if (captionUrl.isValid() && captionUrl.isLocalFile() && captionUrl.path() == url().path()) { adjustedCaption = captionUrl.adjusted(QUrl::StripTrailingSlash).fileName(); if (adjustedCaption.isEmpty()) { adjustedCaption = QLatin1Char('/'); } } } m_caption = adjustedCaption; if (!m_bPassiveMode) { frame()->setTitle(adjustedCaption, 0L); } } void KonqView::slotOpenURLNotify() { #ifdef DEBUG_HISTORY qDebug(); #endif updateHistoryEntry(true); createHistoryEntry(); if (m_pMainWindow->currentView() == this) { m_pMainWindow->updateToolBarActions(); } } void KonqView::createHistoryEntry() { // First, remove any forward history HistoryEntry *current = currentHistoryEntry(); if (current) { #ifdef DEBUG_HISTORY qDebug() << "Truncating history"; #endif while (current != m_lstHistory.last()) { delete m_lstHistory.takeLast(); } } // Append a new entry #ifdef DEBUG_HISTORY qDebug() << "Append a new entry"; #endif appendHistoryEntry(new HistoryEntry); setHistoryIndex(m_lstHistory.count() - 1); // made current #ifdef DEBUG_HISTORY qDebug() << "at=" << historyIndex() << "count=" << m_lstHistory.count(); #endif } void KonqView::appendHistoryEntry(HistoryEntry *historyEntry) { // If there are too many HistoryEntries remove old ones while (m_lstHistory.count() > 0 && m_lstHistory.count() >= KonqSettings::maximumHistoryEntriesPerView()) { delete m_lstHistory.takeFirst(); } m_lstHistory.append(historyEntry); } void KonqView::updateHistoryEntry(bool saveLocationBarURL) { Q_ASSERT(!m_bLockHistory); // should never happen HistoryEntry *current = currentHistoryEntry(); if (!current) { return; } current->reload = false; // We have a state for it now. if (browserExtension()) { current->buffer = QByteArray(); // Start with empty buffer. QDataStream stream(¤t->buffer, QIODevice::WriteOnly); browserExtension()->saveState(stream); } #ifdef DEBUG_HISTORY qDebug() << "Saving part URL:" << m_pPart->url() << "in history position" << historyIndex(); #endif current->url = m_pPart->url(); if (saveLocationBarURL) { #ifdef DEBUG_HISTORY qDebug() << "Saving location bar URL:" << m_sLocationBarURL << "in history position" << historyIndex(); #endif current->locationBarURL = m_sLocationBarURL; current->pageSecurity = m_pageSecurity; } #ifdef DEBUG_HISTORY qDebug() << "Saving title:" << m_caption << "in history position" << historyIndex(); #endif current->title = m_caption; current->strServiceType = m_serviceType; current->strServiceName = m_service->desktopEntryName(); current->doPost = m_doPost; current->postData = m_doPost ? m_postData : QByteArray(); current->postContentType = m_doPost ? m_postContentType : QString(); current->pageReferrer = m_pageReferrer; } void KonqView::goHistory(int steps) { // This is called by KonqBrowserInterface if (m_pMainWindow->currentView() == this) { m_pMainWindow->viewManager()->setActivePart(part()); } // Delay the go() call (we need to return to the caller first) m_pMainWindow->slotGoHistoryActivated(steps); } void KonqView::go(int steps) { if (!steps) { // [WildFox] i bet there are sites on the net with stupid devs who do that :) #ifdef DEBUG_HISTORY qDebug() << "go(0) -> reload"; #endif // [David] and you're right. And they expect that it reloads, apparently. // [George] I'm going to make nspluginviewer rely on this too. :-) m_pMainWindow->slotReload(); return; } int newPos = historyIndex() + steps; #ifdef DEBUG_HISTORY qDebug() << "steps=" << steps << "newPos=" << newPos << "m_lstHistory.count()=" << m_lstHistory.count(); #endif if (newPos < 0 || newPos >= m_lstHistory.count()) { return; } stop(); setHistoryIndex(newPos); // sets current item #ifdef DEBUG_HISTORY qDebug() << "New position" << historyIndex(); #endif restoreHistory(); } void KonqView::doOpenUrl(const QUrl &url) { qDebug() << url; - if (url.scheme() == QLatin1String("about")) { + if (url.scheme() == KonqAboutPage::aboutProtocol()) { KonqAboutPage about; - const QByteArray data = about.pageForUrl(url.toString()).toUtf8(); + const QByteArray data = about.pageContents(url.path()).toUtf8(); //QFile hack("/tmp/about.html"); hack.open(QIODevice::WriteOnly); hack.write(data); hack.close(); if (m_pPart->openStream("text/html", url)) { m_pPart->writeStream(data); m_pPart->closeStream(); } else { qWarning() << m_pPart->metaObject()->className() << "doesn't support openStream()!"; } } else { m_pPart->openUrl(url); } } void KonqView::restoreHistory() { HistoryEntry h(*currentHistoryEntry()); // make a copy of the current history entry, as the data // the pointer points to will change with the following calls #ifdef DEBUG_HISTORY qDebug() << "Restoring from history: servicetype" << h.strServiceType << "with service" << h.strServiceName << "url" << h.url << "locationBarURL:" << h.locationBarURL; #endif setLocationBarURL(h.locationBarURL); setPageSecurity(h.pageSecurity); m_sTypedURL.clear(); if (!changePart(h.strServiceType, h.strServiceName)) { qWarning() << "Couldn't change view mode to" << h.strServiceType << h.strServiceName; return /*false*/; } setPartMimeType(); aboutToOpenURL(h.url); - if (h.reload == false && browserExtension() && h.url.scheme() != "about") { + if (h.reload == false && browserExtension() && h.url.scheme() != KonqAboutPage::aboutProtocol()) { //qDebug() << "Restoring view from stream"; QDataStream stream(h.buffer); browserExtension()->restoreState(stream); m_doPost = h.doPost; m_postContentType = h.postContentType; m_postData = h.postData; m_pageReferrer = h.pageReferrer; } else { doOpenUrl(h.url); } if (m_pMainWindow->currentView() == this) { m_pMainWindow->updateToolBarActions(); } #ifdef DEBUG_HISTORY qDebug() << "New position (2)" << historyIndex(); #endif } const HistoryEntry *KonqView::historyAt(int pos) { return m_lstHistory.value(pos); } void KonqView::copyHistory(KonqView *other) { if (!other) { return; } qDeleteAll(m_lstHistory); m_lstHistory.clear(); foreach (HistoryEntry *he, other->m_lstHistory) { appendHistoryEntry(new HistoryEntry(*he)); } setHistoryIndex(other->historyIndex()); } QUrl KonqView::url() const { Q_ASSERT(m_pPart); return m_pPart->url(); } QUrl KonqView::upUrl() const { QUrl currentURL; if (m_pRun) { currentURL = m_pRun->url(); } else { currentURL = QUrl::fromUserInput(m_sLocationBarURL); } return KIO::upUrl(currentURL); } void KonqView::setRun(KonqRun *run) { if (m_pRun) { // Tell the KonqRun to abort, but don't delete it ourselves. // It could be showing a message box right now. It will delete itself anyway. m_pRun->abort(); // finish() will be emitted later (when back to event loop) // and we don't want it to call slotRunFinished (which stops the animation and stop button). m_pRun->disconnect(m_pMainWindow); if (!run) { frame()->unsetCursor(); } } else if (run) { frame()->setCursor(Qt::BusyCursor); } m_pRun = run; } void KonqView::stop() { //qDebug(); m_bAborted = false; finishedWithCurrentURL(); if (m_bLoading || m_bPendingRedirection) { // aborted -> confirm the pending url. We might as well remove it, but // we decided to keep it :) KonqHistoryManager::kself()->confirmPending(url(), m_sTypedURL); //qDebug() << "m_pPart->closeUrl()"; m_pPart->closeUrl(); m_bAborted = true; m_pKonqFrame->statusbar()->slotLoadingProgress(-1); setLoading(false, false); } if (m_pRun) { // Revert to working URL - unless the URL was typed manually // This is duplicated with KonqMainWindow::slotRunFinished, but we can't call it // since it relies on sender()... if (currentHistoryEntry() && m_pRun->typedUrl().isEmpty()) { // not typed setLocationBarURL(currentHistoryEntry()->locationBarURL); setPageSecurity(currentHistoryEntry()->pageSecurity); } setRun(0L); m_pKonqFrame->statusbar()->slotLoadingProgress(-1); } if (!m_bLockHistory && m_lstHistory.count() > 0) { updateHistoryEntry(true); } } void KonqView::finishedWithCurrentURL() { if (!m_tempFile.isEmpty()) { qDebug() << "######### Deleting tempfile after use:" << m_tempFile; QFile::remove(m_tempFile); m_tempFile.clear(); } } void KonqView::setPassiveMode(bool mode) { // In theory, if m_bPassiveMode is true and mode is false, // the part should be removed from the part manager, // and if the other way round, it should be readded to the part manager... m_bPassiveMode = mode; if (mode && m_pMainWindow->viewCount() > 1 && m_pMainWindow->currentView() == this) { KParts::Part *part = m_pMainWindow->viewManager()->chooseNextView(this)->part(); // switch active part m_pMainWindow->viewManager()->setActivePart(part); } // Update statusbar stuff m_pMainWindow->viewManager()->viewCountChanged(); } void KonqView::setLinkedView(bool mode) { m_bLinkedView = mode; if (m_pMainWindow->currentView() == this) { m_pMainWindow->linkViewAction()->setChecked(mode); } frame()->statusbar()->setLinkedView(mode); } void KonqView::setLockedLocation(bool b) { m_bLockedLocation = b; } void KonqView::aboutToOpenURL(const QUrl &url, const KParts::OpenUrlArguments &args) { m_bErrorURL = url.scheme() == QLatin1String("error"); KParts::OpenUrlEvent ev(m_pPart, url, args); QApplication::sendEvent(m_pMainWindow, &ev); m_bGotIconURL = false; m_bAborted = false; } void KonqView::setPartMimeType() { KParts::OpenUrlArguments args(m_pPart->arguments()); args.setMimeType(m_serviceType); m_pPart->setArguments(args); } QStringList KonqView::frameNames() const { return childFrameNames(m_pPart); } QStringList KonqView::childFrameNames(KParts::ReadOnlyPart *part) { QStringList res; KParts::BrowserHostExtension *hostExtension = KParts::BrowserHostExtension::childObject(part); if (!hostExtension) { return res; } res += hostExtension->frameNames(); const QList children = hostExtension->frames(); QListIterator i(children); while (i.hasNext()) { res += childFrameNames(i.next()); } return res; } KParts::BrowserHostExtension *KonqView::hostExtension(KParts::ReadOnlyPart *part, const QString &name) { KParts::BrowserHostExtension *ext = KParts::BrowserHostExtension::childObject(part); if (!ext) { return 0; } if (ext->frameNames().contains(name)) { return ext; } const QList children = ext->frames(); QListIterator i(children); while (i.hasNext()) { KParts::BrowserHostExtension *childHost = hostExtension(i.next(), name); if (childHost) { return childHost; } } return 0; } bool KonqView::callExtensionMethod(const char *methodName) { QObject *obj = KParts::BrowserExtension::childObject(m_pPart); if (!obj) { // not all views have a browser extension ! return false; } return QMetaObject::invokeMethod(obj, methodName, Qt::DirectConnection); } bool KonqView::callExtensionBoolMethod(const char *methodName, bool value) { QObject *obj = KParts::BrowserExtension::childObject(m_pPart); if (!obj) { // not all views have a browser extension ! return false; } return QMetaObject::invokeMethod(obj, methodName, Qt::DirectConnection, Q_ARG(bool, value)); } bool KonqView::callExtensionURLMethod(const char *methodName, const QUrl &value) { QObject *obj = KParts::BrowserExtension::childObject(m_pPart); if (!obj) { // not all views have a browser extension ! return false; } return QMetaObject::invokeMethod(obj, methodName, Qt::DirectConnection, Q_ARG(QUrl, value)); } void KonqView::setViewName(const QString &name) { //qDebug() << this << "name=" << name; if (m_pPart) { m_pPart->setObjectName(name); } } QString KonqView::viewName() const { return m_pPart ? m_pPart->objectName() : QString(); } void KonqView::enablePopupMenu(bool b) { Q_ASSERT(m_pMainWindow); KParts::BrowserExtension *ext = browserExtension(); if (!ext) { return; } if (m_bPopupMenuEnabled == b) { return; } // enable context popup if (b) { m_bPopupMenuEnabled = true; connect(ext, SIGNAL(popupMenu(QPoint,KFileItemList,KParts::OpenUrlArguments,KParts::BrowserArguments,KParts::BrowserExtension::PopupFlags,KParts::BrowserExtension::ActionGroupMap)), m_pMainWindow, SLOT(slotPopupMenu(QPoint,KFileItemList,KParts::OpenUrlArguments,KParts::BrowserArguments,KParts::BrowserExtension::PopupFlags,KParts::BrowserExtension::ActionGroupMap))); connect(ext, SIGNAL(popupMenu(QPoint,QUrl,mode_t,KParts::OpenUrlArguments,KParts::BrowserArguments,KParts::BrowserExtension::PopupFlags,KParts::BrowserExtension::ActionGroupMap)), m_pMainWindow, SLOT(slotPopupMenu(QPoint,QUrl,mode_t,KParts::OpenUrlArguments,KParts::BrowserArguments,KParts::BrowserExtension::PopupFlags,KParts::BrowserExtension::ActionGroupMap))); } else { // disable context popup m_bPopupMenuEnabled = false; disconnect(ext, SIGNAL(popupMenu(QPoint,KFileItemList,KParts::OpenUrlArguments,KParts::BrowserArguments,KParts::BrowserExtension::PopupFlags,KParts::BrowserExtension::ActionGroupMap)), m_pMainWindow, SLOT(slotPopupMenu(QPoint,KFileItemList,KParts::OpenUrlArguments,KParts::BrowserArguments,KParts::BrowserExtension::PopupFlags,KParts::BrowserExtension::ActionGroupMap))); disconnect(ext, SIGNAL(popupMenu(QPoint,QUrl,mode_t,KParts::OpenUrlArguments,KParts::BrowserArguments,KParts::BrowserExtension::PopupFlags,KParts::BrowserExtension::ActionGroupMap)), m_pMainWindow, SLOT(slotPopupMenu(QPoint,QUrl,mode_t,KParts::OpenUrlArguments,KParts::BrowserArguments,KParts::BrowserExtension::PopupFlags,KParts::BrowserExtension::ActionGroupMap))); } } void KonqView::reparseConfiguration() { callExtensionMethod("reparseConfiguration"); } void KonqView::disableScrolling() { m_bDisableScrolling = true; callExtensionMethod("disableScrolling"); } QString KonqView::dbusObjectPath() { // TODO maybe this can be improved? // E.g. using the part's name, but we'd have to update the name in setViewName maybe? // And to make sure it's a valid dbus object path like in kmainwindow... static int s_viewNumber = 0; if (m_dbusObjectPath.isEmpty()) { m_dbusObjectPath = m_pMainWindow->dbusName() + '/' + QString::number(++s_viewNumber); new KonqViewAdaptor(this); QDBusConnection::sessionBus().registerObject(m_dbusObjectPath, this); } return m_dbusObjectPath; } QString KonqView::partObjectPath() { if (!m_pPart) { return QString(); } const QVariant dcopProperty = m_pPart->property("dbusObjectPath"); return dcopProperty.toString(); } bool KonqView::eventFilter(QObject *obj, QEvent *e) { if (!m_pPart) { return false; } // qDebug() << "--" << obj->className() << "--" << e->type() << "--" ; if (e->type() == QEvent::DragEnter && m_bURLDropHandling && obj == m_pPart->widget()) { QDragEnterEvent *ev = static_cast(e); const QMimeData *mimeData = ev->mimeData(); if (mimeData->hasUrls()) { QList lstDragURLs = KUrlMimeData::urlsFromMimeData(mimeData); QList children = qFindChildren(m_pPart->widget()); // ### slow, better write a isChildOf with a loop... if (!lstDragURLs.isEmpty() && !lstDragURLs.first().url().startsWith(QLatin1String("javascript:"), Qt::CaseInsensitive) && // ### this looks like a hack to me ev->source() != m_pPart->widget() && !children.contains(ev->source())) { ev->acceptProposedAction(); } } } else if (e->type() == QEvent::Drop && m_bURLDropHandling && obj == m_pPart->widget()) { QDropEvent *ev = static_cast(e); const QMimeData *mimeData = ev->mimeData(); QList lstDragURLs = KUrlMimeData::urlsFromMimeData(mimeData); KParts::BrowserExtension *ext = browserExtension(); if (!lstDragURLs.isEmpty() && ext && lstDragURLs.first().isValid()) { emit ext->openUrlRequest(lstDragURLs.first()); // this will call m_pMainWindow::slotOpenURLRequest delayed } } if (e->type() == QEvent::FocusIn) { setActiveComponent(); } #ifdef KActivities_FOUND if (e->type() == QEvent::FocusOut) { m_activityResourceInstance->notifyFocusedOut(); } #endif return false; } void KonqView::setActiveComponent() { #if 0 // Removed with the port to KF5. The concept no longer exists, the about dialog and bug report // dialog just use the application information rather than the one of the current part. if (m_bBuiltinView) { KComponentData::setActiveComponent(KGlobal::mainComponent()); } else { KComponentData::setActiveComponent(KComponentData(m_pPart->componentData())); } #endif #ifdef KActivities_FOUND m_activityResourceInstance->notifyFocusedIn(); #endif } bool KonqView::prepareReload(KParts::OpenUrlArguments &args, KParts::BrowserArguments &browserArgs, bool softReload) { args.setReload(true); if (softReload) { browserArgs.softReload = true; } // Repost form data if this URL is the result of a POST HTML form. if (m_doPost && !browserArgs.redirectedRequest()) { if (KMessageBox::warningContinueCancel(0, i18n( "The page you are trying to view is the result of posted form data. " "If you resend the data, any action the form carried out (such as search or online purchase) will be repeated. "), i18nc("@title:window", "Warning"), KGuiItem(i18n("Resend"))) == KMessageBox::Continue) { browserArgs.setDoPost(true); browserArgs.setContentType(m_postContentType); browserArgs.postData = m_postData; } else { return false; } } // Re-set referrer args.metaData()[QStringLiteral("referrer")] = m_pageReferrer; return true; } KParts::BrowserExtension *KonqView::browserExtension() const { return KParts::BrowserExtension::childObject(m_pPart); } KParts::StatusBarExtension *KonqView::statusBarExtension() const { return KParts::StatusBarExtension::childObject(m_pPart); } KMimeType::Ptr KonqView::mimeType() const { return KMimeType::mimeType(serviceType()); // can be null } bool KonqView::supportsMimeType(const QString &mimeType) const { KMimeType::Ptr mime = KMimeType::mimeType(mimeType, KMimeType::ResolveAliases); if (!mime) { return false; } const QStringList lst = serviceTypes(); for (QStringList::ConstIterator it = lst.begin(); it != lst.end(); ++it) { if (mime->is(*it)) { // same as mime == *it, but also respect inheritance, mimeType can be a subclass return true; } } return false; } void HistoryEntry::saveConfig(KConfigGroup &config, const QString &prefix, const KonqFrameBase::Options &options) { if (options & KonqFrameBase::saveURLs) { config.writeEntry(QStringLiteral("Url").prepend(prefix), url.url()); config.writeEntry(QStringLiteral("LocationBarURL").prepend(prefix), locationBarURL); config.writeEntry(QStringLiteral("Title").prepend(prefix), title); config.writeEntry(QStringLiteral("StrServiceType").prepend(prefix), strServiceType); config.writeEntry(QStringLiteral("StrServiceName").prepend(prefix), strServiceName); } else if (options & KonqFrameBase::saveHistoryItems) { config.writeEntry(QStringLiteral("Url").prepend(prefix), url.url()); config.writeEntry(QStringLiteral("LocationBarURL").prepend(prefix), locationBarURL); config.writeEntry(QStringLiteral("Title").prepend(prefix), title); config.writeEntry(QStringLiteral("Buffer").prepend(prefix), buffer); config.writeEntry(QStringLiteral("StrServiceType").prepend(prefix), strServiceType); config.writeEntry(QStringLiteral("StrServiceName").prepend(prefix), strServiceName); config.writeEntry(QStringLiteral("PostData").prepend(prefix), postData); config.writeEntry(QStringLiteral("PostContentType").prepend(prefix), postContentType); config.writeEntry(QStringLiteral("DoPost").prepend(prefix), doPost); config.writeEntry(QStringLiteral("PageReferrer").prepend(prefix), pageReferrer); config.writeEntry(QStringLiteral("PageSecurity").prepend(prefix), static_cast(pageSecurity)); } } void HistoryEntry::loadItem(const KConfigGroup &config, const QString &prefix, const KonqFrameBase::Options &options) { if (options & KonqFrameBase::saveURLs) { url = QUrl(config.readEntry(QStringLiteral("Url").prepend(prefix), "")); locationBarURL = config.readEntry(QStringLiteral("LocationBarURL").prepend(prefix), ""); title = config.readEntry(QStringLiteral("Title").prepend(prefix), ""); strServiceType = config.readEntry(QStringLiteral("StrServiceType").prepend(prefix), ""); strServiceName = config.readEntry(QStringLiteral("StrServiceName").prepend(prefix), ""); reload = true; } else if (options & KonqFrameBase::saveHistoryItems) { url = QUrl(config.readEntry(QStringLiteral("Url").prepend(prefix), "")); locationBarURL = config.readEntry(QStringLiteral("LocationBarURL").prepend(prefix), ""); title = config.readEntry(QStringLiteral("Title").prepend(prefix), ""); buffer = config.readEntry(QStringLiteral("Buffer").prepend(prefix), QByteArray()); strServiceType = config.readEntry(QStringLiteral("StrServiceType").prepend(prefix), ""); strServiceName = config.readEntry(QStringLiteral("StrServiceName").prepend(prefix), ""); postData = config.readEntry(QStringLiteral("PostData").prepend(prefix), QByteArray()); postContentType = config.readEntry(QStringLiteral("PostContentType").prepend(prefix), ""); doPost = config.readEntry(QStringLiteral("DoPost").prepend(prefix), false); pageReferrer = config.readEntry(QStringLiteral("PageReferrer").prepend(prefix), ""); pageSecurity = static_cast(config.readEntry( QStringLiteral("PageSecurity").prepend(prefix), 0)); reload = false; } } void KonqView::saveConfig(KConfigGroup &config, const QString &prefix, const KonqFrameBase::Options &options) { config.writeEntry(QStringLiteral("ServiceType").prepend(prefix), serviceType()); config.writeEntry(QStringLiteral("ServiceName").prepend(prefix), service()->desktopEntryName()); config.writeEntry(QStringLiteral("PassiveMode").prepend(prefix), isPassiveMode()); config.writeEntry(QStringLiteral("LinkedView").prepend(prefix), isLinkedView()); config.writeEntry(QStringLiteral("ToggleView").prepend(prefix), isToggleView()); config.writeEntry(QStringLiteral("LockedLocation").prepend(prefix), isLockedLocation()); if (options & KonqFrameBase::saveURLs) { config.writePathEntry(QStringLiteral("URL").prepend(prefix), url().url()); } else if (options & KonqFrameBase::saveHistoryItems) { if (m_pPart && !m_bLockHistory) { updateHistoryEntry(true); } QList::Iterator it = m_lstHistory.begin(); for (int i = 0; it != m_lstHistory.end(); ++it, ++i) { // In order to not end up with a huge config file, we only save full // history for current history item KonqFrameBase::Options options; if (i == m_lstHistoryIndex) { options = KonqFrameBase::saveHistoryItems; } else { options = KonqFrameBase::saveURLs; } (*it)->saveConfig(config, QLatin1String("HistoryItem") + QString::number(i).prepend(prefix), options); } config.writeEntry(QStringLiteral("CurrentHistoryItem").prepend(prefix), m_lstHistoryIndex); config.writeEntry(QStringLiteral("NumberOfHistoryItems").prepend(prefix), historyLength()); } } void KonqView::loadHistoryConfig(const KConfigGroup &config, const QString &prefix) { // First, remove any history qDeleteAll(m_lstHistory); m_lstHistory.clear(); int historySize = config.readEntry(QStringLiteral("NumberOfHistoryItems").prepend(prefix), 0); int currentIndex = config.readEntry(QStringLiteral("CurrentHistoryItem").prepend(prefix), historySize - 1); // No history to restore.. if (historySize == 0) { createHistoryEntry(); return; } // restore history list for (int i = 0; i < historySize; ++i) { HistoryEntry *historyEntry = new HistoryEntry; // Only current history item saves completely its HistoryEntry KonqFrameBase::Options options; if (i == currentIndex) { options = KonqFrameBase::saveHistoryItems; } else { options = KonqFrameBase::saveURLs; } historyEntry->loadItem(config, QLatin1String("HistoryItem") + QString::number(i).prepend(prefix), options); appendHistoryEntry(historyEntry); } // Shouldn't happen, but just in case.. if (currentIndex >= historyLength()) { currentIndex = historyLength() - 1; } // set and load the correct history index setHistoryIndex(currentIndex); restoreHistory(); } QString KonqView::internalViewMode() const { const QVariant viewModeProperty = m_pPart->property("currentViewMode"); return viewModeProperty.toString(); } void KonqView::setInternalViewMode(const QString &viewMode) { m_pPart->setProperty("currentViewMode", viewMode); } QString KonqView::nameFilter() const { const QVariant nameFilterProperty = m_pPart->property("nameFilter"); return nameFilterProperty.toString(); } bool KonqView::showsDirectory() const { return supportsMimeType(QStringLiteral("inode/directory")); } bool KonqView::isModified() const { if (m_pPart && (m_pPart->metaObject()->indexOfProperty("modified") != -1)) { const QVariant prop = m_pPart->property("modified"); return prop.isValid() && prop.toBool(); } return false; } void KonqView::setFocus() { if (m_pPart && m_pPart->widget() && !isErrorUrl()) { m_pPart->widget()->setFocus(); } } bool KonqView::isErrorUrl() const { return m_bErrorURL; } diff --git a/src/konqviewmanager.cpp b/src/konqviewmanager.cpp index 50ef4f175..f5fc2ccc0 100644 --- a/src/konqviewmanager.cpp +++ b/src/konqviewmanager.cpp @@ -1,1453 +1,1454 @@ /* This file is part of the KDE project Copyright (C) 1999 Simon Hausmann Copyright (C) 2007 Eduardo Robles Elvira This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "konqviewmanager.h" #include "konqcloseditem.h" #include "konqundomanager.h" #include "konqmisc.h" #include "konqview.h" #include "konqframestatusbar.h" #include "konqtabs.h" #include "konqsettingsxt.h" #include "konqframevisitor.h" +#include "konqaboutpage.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include //#define DEBUG_VIEWMGR KonqViewManager::KonqViewManager(KonqMainWindow *mainWindow) : KParts::PartManager(mainWindow) { m_pMainWindow = mainWindow; m_bLoadingProfile = false; m_tabContainer = 0; setIgnoreExplictFocusRequests(true); connect(this, SIGNAL(activePartChanged(KParts::Part*)), this, SLOT(slotActivePartChanged(KParts::Part*))); } KonqView *KonqViewManager::createFirstView(const QString &mimeType, const QString &serviceName) { //qDebug() << serviceName; KService::Ptr service; KService::List partServiceOffers, appServiceOffers; KonqViewFactory newViewFactory = createView(mimeType, serviceName, service, partServiceOffers, appServiceOffers, true /*forceAutoEmbed*/); if (newViewFactory.isNull()) { qDebug() << "No suitable factory found."; return 0; } KonqView *childView = setupView(tabContainer(), newViewFactory, service, partServiceOffers, appServiceOffers, mimeType, false); setActivePart(childView->part()); m_tabContainer->asQWidget()->show(); return childView; } KonqViewManager::~KonqViewManager() { clear(); } KonqView *KonqViewManager::splitView(KonqView *currentView, Qt::Orientation orientation, bool newOneFirst, bool forceAutoEmbed) { #ifdef DEBUG_VIEWMGR qDebug(); m_pMainWindow->dumpViewList(); printFullHierarchy(); #endif KonqFrame *splitFrame = currentView->frame(); const QString serviceType = currentView->serviceType(); KService::Ptr service; KService::List partServiceOffers, appServiceOffers; KonqViewFactory newViewFactory = createView(serviceType, currentView->service()->desktopEntryName(), service, partServiceOffers, appServiceOffers, forceAutoEmbed); if (newViewFactory.isNull()) { return 0; //do not split at all if we can't create the new view } Q_ASSERT(splitFrame); KonqFrameContainerBase *parentContainer = splitFrame->parentContainer(); // We need the sizes of the views in the parentContainer to restore these after the new container is inserted. // To access the sizes via QSplitter::sizes(), a pointer to a KonqFrameContainerBase is not sufficient. // We need a pointer to a KonqFrameContainer which is derived from QSplitter. KonqFrameContainer *parentKonqFrameContainer = dynamic_cast(parentContainer); QList parentSplitterSizes; if (parentKonqFrameContainer) { parentSplitterSizes = parentKonqFrameContainer->sizes(); } KonqFrameContainer *newContainer = parentContainer->splitChildFrame(splitFrame, orientation); //qDebug() << "Create new child"; KonqView *newView = setupView(newContainer, newViewFactory, service, partServiceOffers, appServiceOffers, serviceType, false); #ifndef DEBUG //printSizeInfo( splitFrame, parentContainer, "after child insert" ); #endif newContainer->insertWidget(newOneFirst ? 0 : 1, newView->frame()); if (newOneFirst) { newContainer->swapChildren(); } Q_ASSERT(newContainer->count() == 2); QList newSplitterSizes; newSplitterSizes << 50 << 50; newContainer->setSizes(newSplitterSizes); splitFrame->show(); newContainer->show(); if (parentKonqFrameContainer) { parentKonqFrameContainer->setSizes(parentSplitterSizes); } Q_ASSERT(newView->frame()); Q_ASSERT(newView->part()); newContainer->setActiveChild(newView->frame()); setActivePart(newView->part()); #ifdef DEBUG_VIEWMGR m_pMainWindow->dumpViewList(); printFullHierarchy(); qDebug() << "done"; #endif return newView; } KonqView *KonqViewManager::splitMainContainer(KonqView *currentView, Qt::Orientation orientation, const QString &serviceType, // This can be Browser/View, not necessarily a mimetype const QString &serviceName, bool newOneFirst) { //qDebug(); KService::Ptr service; KService::List partServiceOffers, appServiceOffers; KonqViewFactory newViewFactory = createView(serviceType, serviceName, service, partServiceOffers, appServiceOffers); if (newViewFactory.isNull()) { return 0; //do not split at all if we can't create the new view } // Get main frame. Note: this is NOT necessarily m_tabContainer! // When having tabs plus a konsole, the main frame is a splitter (KonqFrameContainer). KonqFrameBase *mainFrame = m_pMainWindow->childFrame(); KonqFrameContainer *newContainer = m_pMainWindow->splitChildFrame(mainFrame, orientation); KonqView *childView = setupView(newContainer, newViewFactory, service, partServiceOffers, appServiceOffers, serviceType, true); newContainer->insertWidget(newOneFirst ? 0 : 1, childView->frame()); if (newOneFirst) { newContainer->swapChildren(); } newContainer->show(); newContainer->setActiveChild(mainFrame); childView->openUrl(currentView->url(), currentView->locationBarURL()); #ifdef DEBUG_VIEWMGR m_pMainWindow->dumpViewList(); printFullHierarchy(); qDebug() << "done"; #endif return childView; } KonqView *KonqViewManager::addTab(const QString &serviceType, const QString &serviceName, bool passiveMode, bool openAfterCurrentPage, int pos) { #ifdef DEBUG_VIEWMGR qDebug() << "------------- KonqViewManager::addTab starting -------------"; m_pMainWindow->dumpViewList(); printFullHierarchy(); #endif KService::Ptr service; KService::List partServiceOffers, appServiceOffers; Q_ASSERT(!serviceType.isEmpty()); QString actualServiceName = serviceName; if (actualServiceName.isEmpty()) { // Use same part as the current view (e.g. khtml/webkit). // This is down here in this central method because it should work for // MMB-opens-tab, window.open (createNewWindow), and more. KonqView *currentView = m_pMainWindow->currentView(); // Don't use supportsMimeType("text/html"), it's true for katepart too. // (Testcase: view text file, ctrl+shift+n, was showing about page in katepart) if (currentView) { KMimeType::Ptr mime = currentView->mimeType(); if (mime && mime->is(serviceType)) { actualServiceName = currentView->service()->desktopEntryName(); } } } KonqViewFactory newViewFactory = createView(serviceType, actualServiceName, service, partServiceOffers, appServiceOffers, true /*forceAutoEmbed*/); if (newViewFactory.isNull()) { return 0L; //do not split at all if we can't create the new view } KonqView *childView = setupView(tabContainer(), newViewFactory, service, partServiceOffers, appServiceOffers, serviceType, passiveMode, openAfterCurrentPage, pos); #ifdef DEBUG_VIEWMGR m_pMainWindow->dumpViewList(); printFullHierarchy(); qDebug() << "------------- KonqViewManager::addTab done -------------"; #endif return childView; } KonqView *KonqViewManager::addTabFromHistory(KonqView *currentView, int steps, bool openAfterCurrentPage) { int oldPos = currentView->historyIndex(); int newPos = oldPos + steps; const HistoryEntry *he = currentView->historyAt(newPos); if (!he) { return 0L; } KonqView *newView = 0L; newView = addTab(he->strServiceType, he->strServiceName, false, openAfterCurrentPage); if (!newView) { return 0; } newView->copyHistory(currentView); newView->setHistoryIndex(newPos); newView->restoreHistory(); return newView; } void KonqViewManager::duplicateTab(int tabIndex, bool openAfterCurrentPage) { #ifdef DEBUG_VIEWMGR qDebug() << tabIndex; m_pMainWindow->dumpViewList(); printFullHierarchy(); #endif QTemporaryFile tempFile; tempFile.open(); KConfig config(tempFile.fileName()); KConfigGroup profileGroup(&config, "Profile"); KonqFrameBase *tab = tabContainer()->tabAt(tabIndex); QString prefix = KonqFrameBase::frameTypeToString(tab->frameType()) + QString::number(0); // always T0 profileGroup.writeEntry("RootItem", prefix); prefix.append(QLatin1Char('_')); KonqFrameBase::Options flags = KonqFrameBase::saveHistoryItems; tab->saveConfig(profileGroup, prefix, flags, 0L, 0, 1); loadRootItem(profileGroup, tabContainer(), QUrl(), true, QUrl(), QString(), openAfterCurrentPage); if (openAfterCurrentPage) { m_tabContainer->setCurrentIndex(m_tabContainer->currentIndex() + 1); } else { m_tabContainer->setCurrentIndex(m_tabContainer->count() - 1); } #ifdef DEBUG_VIEWMGR m_pMainWindow->dumpViewList(); printFullHierarchy(); #endif } KonqMainWindow *KonqViewManager::breakOffTab(int tab, const QSize &windowSize) { #ifdef DEBUG_VIEWMGR qDebug() << "tab=" << tab; m_pMainWindow->dumpViewList(); printFullHierarchy(); #endif QTemporaryFile tempFile; tempFile.open(); KSharedConfigPtr config = KSharedConfig::openConfig(tempFile.fileName()); KConfigGroup profileGroup(config, "Profile"); KonqFrameBase *tabFrame = tabContainer()->tabAt(tab); QString prefix = KonqFrameBase::frameTypeToString(tabFrame->frameType()) + QString::number(0); // always T0 profileGroup.writeEntry("RootItem", prefix); prefix.append(QLatin1Char('_')); KonqFrameBase::Options flags = KonqFrameBase::saveHistoryItems; tabFrame->saveConfig(profileGroup, prefix, flags, 0L, 0, 1); KonqMainWindow *mainWindow = new KonqMainWindow; KonqFrameTabs *newTabContainer = mainWindow->viewManager()->tabContainer(); mainWindow->viewManager()->loadRootItem(profileGroup, newTabContainer, QUrl(), true, QUrl()); removeTab(tabFrame, false); mainWindow->enableAllActions(true); mainWindow->resize(windowSize); mainWindow->activateChild(); mainWindow->show(); #ifdef DEBUG_VIEWMGR m_pMainWindow->dumpViewList(); printFullHierarchy(); #endif return mainWindow; } void KonqViewManager::openClosedWindow(const KonqClosedWindowItem &closedWindowItem) { openSavedWindow(closedWindowItem.configGroup())->show(); } KonqMainWindow *KonqViewManager::openSavedWindow(const KConfigGroup &configGroup) { // TODO factorize to avoid code duplication with loadViewProfileFromGroup KonqMainWindow *mainWindow = new KonqMainWindow; if (configGroup.readEntry("FullScreen", false)) { // Full screen on mainWindow->showFullScreen(); } else { // Full screen off if (mainWindow->isFullScreen()) { mainWindow->showNormal(); } // Window size comes from the applyMainWindowSettings call below } mainWindow->viewManager()->loadRootItem(configGroup, mainWindow, QUrl(), true, QUrl()); mainWindow->applyMainWindowSettings(configGroup); mainWindow->activateChild(); #ifdef DEBUG_VIEWMGR mainWindow->viewManager()->printFullHierarchy(); #endif return mainWindow; } KonqMainWindow *KonqViewManager::openSavedWindow(const KConfigGroup &configGroup, bool openTabsInsideCurrentWindow) { if (!openTabsInsideCurrentWindow) { return KonqViewManager::openSavedWindow(configGroup); } else { loadRootItem(configGroup, tabContainer(), QUrl(), true, QUrl()); #ifndef NDEBUG printFullHierarchy(); #endif return m_pMainWindow; } } void KonqViewManager::removeTab(KonqFrameBase *currentFrame, bool emitAboutToRemoveSignal) { Q_ASSERT(currentFrame); #ifdef DEBUG_VIEWMGR qDebug() << currentFrame; m_pMainWindow->dumpViewList(); printFullHierarchy(); #endif if (m_tabContainer->count() == 1) { m_pMainWindow->slotAddTab(); // #214378 } if (emitAboutToRemoveSignal) { emit aboutToRemoveTab(currentFrame); } if (currentFrame->asQWidget() == m_tabContainer->currentWidget()) { setActivePart(0); } const QList viewList = KonqViewCollector::collect(currentFrame); foreach (KonqView *view, viewList) { if (view == m_pMainWindow->currentView()) { setActivePart(0); } m_pMainWindow->removeChildView(view); delete view; } m_tabContainer->childFrameRemoved(currentFrame); delete currentFrame; m_tabContainer->slotCurrentChanged(m_tabContainer->currentIndex()); m_pMainWindow->viewCountChanged(); #ifdef DEBUG_VIEWMGR m_pMainWindow->dumpViewList(); printFullHierarchy(); #endif } void KonqViewManager::reloadAllTabs() { foreach (KonqFrameBase *frame, tabContainer()->childFrameList()) { if (frame && frame->activeChildView()) { if (!frame->activeChildView()->locationBarURL().isEmpty()) { frame->activeChildView()->openUrl(frame->activeChildView()->url(), frame->activeChildView()->locationBarURL()); } } } } void KonqViewManager::removeOtherTabs(int tabIndex) { QList tabs = m_tabContainer->childFrameList(); for (int i = 0; i < tabs.count(); ++i) { if (i != tabIndex) { removeTab(tabs.at(i)); } } } void KonqViewManager::moveTabBackward() { if (m_tabContainer->count() == 1) { return; } int iTab = m_tabContainer->currentIndex(); m_tabContainer->moveTabBackward(iTab); } void KonqViewManager::moveTabForward() { if (m_tabContainer->count() == 1) { return; } int iTab = m_tabContainer->currentIndex(); m_tabContainer->moveTabForward(iTab); } void KonqViewManager::activateNextTab() { if (m_tabContainer->count() == 1) { return; } int iTab = m_tabContainer->currentIndex(); iTab++; if (iTab == m_tabContainer->count()) { iTab = 0; } m_tabContainer->setCurrentIndex(iTab); } void KonqViewManager::activatePrevTab() { if (m_tabContainer->count() == 1) { return; } int iTab = m_tabContainer->currentIndex(); iTab--; if (iTab == -1) { iTab = m_tabContainer->count() - 1; } m_tabContainer->setCurrentIndex(iTab); } void KonqViewManager::activateTab(int position) { if (position < 0 || m_tabContainer->count() == 1 || position >= m_tabContainer->count()) { return; } m_tabContainer->setCurrentIndex(position); } void KonqViewManager::showTab(KonqView *view) { if (m_tabContainer->currentWidget() != view->frame()) { m_tabContainer->setCurrentIndex(m_tabContainer->indexOf(view->frame())); } } void KonqViewManager::showTab(int tabIndex) { if (m_tabContainer->currentIndex() != tabIndex) { m_tabContainer->setCurrentIndex(tabIndex); } } void KonqViewManager::updatePixmaps() { const QList viewList = KonqViewCollector::collect(tabContainer()); foreach (KonqView *view, viewList) { view->setTabIcon(QUrl::fromUserInput(view->locationBarURL())); } } void KonqViewManager::openClosedTab(const KonqClosedTabItem &closedTab) { qDebug(); loadRootItem(closedTab.configGroup(), m_tabContainer, QUrl(), true, QUrl(), QString(), false, closedTab.pos()); int pos = (closedTab.pos() < m_tabContainer->count()) ? closedTab.pos() : m_tabContainer->count() - 1; qDebug() << "pos, m_tabContainer->count():" << pos << m_tabContainer->count() - 1; m_tabContainer->setCurrentIndex(pos); } void KonqViewManager::removeView(KonqView *view) { #ifdef DEBUG_VIEWMGR qDebug() << view; m_pMainWindow->dumpViewList(); printFullHierarchy(); #endif if (!view) { return; } KonqFrame *frame = view->frame(); KonqFrameContainerBase *parentContainer = frame->parentContainer(); qDebug() << "view=" << view << "frame=" << frame << "parentContainer=" << parentContainer; if (parentContainer->frameType() == KonqFrameBase::Container) { setActivePart(0); qDebug() << "parentContainer is a KonqFrameContainer"; KonqFrameContainerBase *grandParentContainer = parentContainer->parentContainer(); qDebug() << "grandParentContainer=" << grandParentContainer; KonqFrameBase *otherFrame = static_cast(parentContainer)->otherChild(frame); if (!otherFrame) { qWarning() << "This shouldn't happen!"; return; } static_cast(parentContainer)->setAboutToBeDeleted(); // If the grand parent is a KonqFrameContainer, we need the sizes of the views inside it to restore these after // the parent is replaced. To access the sizes via QSplitter::sizes(), a pointer to a KonqFrameContainerBase // is not sufficient. We need a pointer to a KonqFrameContainer which is derived from QSplitter. KonqFrameContainer *grandParentKonqFrameContainer = dynamic_cast(grandParentContainer); QList grandParentSplitterSizes; if (grandParentKonqFrameContainer) { grandParentSplitterSizes = grandParentKonqFrameContainer->sizes(); } m_pMainWindow->removeChildView(view); //qDebug() << "--- Deleting view" << view; grandParentContainer->replaceChildFrame(parentContainer, otherFrame); //qDebug() << "--- Removing otherFrame from parentContainer"; parentContainer->childFrameRemoved(otherFrame); delete view; // This deletes the view, which deletes the part, which deletes its widget delete parentContainer; if (grandParentKonqFrameContainer) { grandParentKonqFrameContainer->setSizes(grandParentSplitterSizes); } grandParentContainer->setActiveChild(otherFrame); grandParentContainer->activateChild(); m_pMainWindow->viewCountChanged(); } else if (parentContainer->frameType() == KonqFrameBase::Tabs) { qDebug() << "parentContainer" << parentContainer << "is a KonqFrameTabs"; removeTab(frame); } else if (parentContainer->frameType() == KonqFrameBase::MainWindow) { qDebug() << "parentContainer is a KonqMainWindow. This shouldn't be removable, not removing."; } else { qDebug() << "Unrecognized frame type, not removing."; } #ifdef DEBUG_VIEWMGR printFullHierarchy(); m_pMainWindow->dumpViewList(); qDebug() << "done"; #endif } // reimplemented from PartManager void KonqViewManager::removePart(KParts::Part *part) { //qDebug() << part; // This is called when a part auto-deletes itself (case 1), or when // the "delete view" above deletes, in turn, the part (case 2) KParts::PartManager::removePart(part); // If we were called by PartManager::slotObjectDestroyed, then the inheritance has // been deleted already... Can't use inherits(). KonqView *view = m_pMainWindow->childView(static_cast(part)); if (view) { // the child view still exists, so we are in case 1 qDebug() << "Found a child view"; // Make sure that deleting the frame won't delete the part's widget; // that's already taken care of by the part. view->part()->widget()->hide(); view->part()->widget()->setParent(0); view->partDeleted(); // tell the child view that the part auto-deletes itself if (m_pMainWindow->mainViewsCount() == 1) { qDebug() << "Deleting last view -> closing the window"; clear(); qDebug() << "Closing m_pMainWindow" << m_pMainWindow; m_pMainWindow->close(); // will delete it return; } else { // normal case removeView(view); } } //qDebug() << part << "done"; } void KonqViewManager::slotPassiveModePartDeleted() { // Passive mode parts aren't registered to the part manager, // so we have to handle suicidal ones ourselves KParts::ReadOnlyPart *part = const_cast(static_cast(sender())); disconnect(part, SIGNAL(destroyed()), this, SLOT(slotPassiveModePartDeleted())); qDebug() << "part=" << part; KonqView *view = m_pMainWindow->childView(part); qDebug() << "view=" << view; if (view != 0L) { // the child view still exists, so the part suicided view->partDeleted(); // tell the child view that the part deleted itself removeView(view); } } void KonqViewManager::viewCountChanged() { bool bShowActiveViewIndicator = (m_pMainWindow->viewCount() > 1); bool bShowLinkedViewIndicator = (m_pMainWindow->linkableViewsCount() > 1); const KonqMainWindow::MapViews mapViews = m_pMainWindow->viewMap(); KonqMainWindow::MapViews::ConstIterator it = mapViews.begin(); KonqMainWindow::MapViews::ConstIterator end = mapViews.end(); for (; it != end; ++it) { KonqFrameStatusBar *sb = it.value()->frame()->statusbar(); sb->showActiveViewIndicator(bShowActiveViewIndicator && !it.value()->isPassiveMode()); sb->showLinkedViewIndicator(bShowLinkedViewIndicator && !it.value()->isFollowActive()); } } void KonqViewManager::clear() { //qDebug(); setActivePart(0); if (m_pMainWindow->childFrame() == 0) { return; } const QList viewList = KonqViewCollector::collect(m_pMainWindow); if (!viewList.isEmpty()) { //qDebug() << viewList.count() << "items"; foreach (KonqView *view, viewList) { m_pMainWindow->removeChildView(view); //qDebug() << "Deleting" << view; delete view; } } KonqFrameBase *frame = m_pMainWindow->childFrame(); Q_ASSERT(frame); //qDebug() << "deleting mainFrame "; m_pMainWindow->childFrameRemoved(frame); // will set childFrame() to NULL delete frame; // tab container was deleted by the above m_tabContainer = 0; m_pMainWindow->viewCountChanged(); } KonqView *KonqViewManager::chooseNextView(KonqView *view) { //qDebug() << view; int it = 0; const QList viewList = KonqViewCollector::collect(m_pMainWindow); if (viewList.isEmpty()) { return 0; // We have no view at all - this used to happen with totally-empty-profiles } if (view) { // find it in the list it = viewList.indexOf(view); } // the view should always be in the list if (it == -1) { qWarning() << "View" << view << "is not in list!"; it = 0; } bool rewinded = false; const int startIndex = it; const int end = viewList.count(); //qDebug() << "count=" << end; while (true) { //qDebug() << "going next"; if (++it == end) { // move to next // end reached: restart from begin (but only once) if (!rewinded) { it = 0; rewinded = true; } else { break; // nothing found, probably buggy profile } } if (it == startIndex && view) { break; // no next view found } KonqView *nextView = viewList.at(it);; if (nextView && !nextView->isPassiveMode()) { return nextView; } //qDebug() << "nextView=" << nextView << "passive=" << nextView->isPassiveMode(); } //qDebug() << "returning 0"; return 0; // no next view found } KonqViewFactory KonqViewManager::createView(const QString &serviceType, const QString &serviceName, KService::Ptr &service, KService::List &partServiceOffers, KService::List &appServiceOffers, bool forceAutoEmbed) { KonqViewFactory viewFactory; if (serviceType.isEmpty() && m_pMainWindow->currentView()) { //clone current view KonqView *cv = m_pMainWindow->currentView(); QString _serviceType, _serviceName; if (cv->service()->desktopEntryName() == QLatin1String("konq_sidebartng")) { _serviceType = QStringLiteral("text/html"); } else { _serviceType = cv->serviceType(); _serviceName = cv->service()->desktopEntryName(); } KonqFactory konqFactory; viewFactory = konqFactory.createView(_serviceType, _serviceName, &service, &partServiceOffers, &appServiceOffers, forceAutoEmbed); } else { //create view with the given servicetype KonqFactory konqFactory; viewFactory = konqFactory.createView(serviceType, serviceName, &service, &partServiceOffers, &appServiceOffers, forceAutoEmbed); } return viewFactory; } KonqView *KonqViewManager::setupView(KonqFrameContainerBase *parentContainer, KonqViewFactory &viewFactory, const KService::Ptr &service, const KService::List &partServiceOffers, const KService::List &appServiceOffers, const QString &serviceType, bool passiveMode, bool openAfterCurrentPage, int pos) { //qDebug() << "passiveMode=" << passiveMode; QString sType = serviceType; if (sType.isEmpty()) { // TODO remove this -- after checking all callers; splitMainContainer seems to need this logic sType = m_pMainWindow->currentView()->serviceType(); } //qDebug() << "creating KonqFrame with parent=" << parentContainer; KonqFrame *newViewFrame = new KonqFrame(parentContainer->asQWidget(), parentContainer); newViewFrame->setGeometry(0, 0, m_pMainWindow->width(), m_pMainWindow->height()); //qDebug() << "Creating KonqView"; KonqView *v = new KonqView(viewFactory, newViewFrame, m_pMainWindow, service, partServiceOffers, appServiceOffers, sType, passiveMode); //qDebug() << "KonqView created - v=" << v << "v->part()=" << v->part(); QObject::connect(v, SIGNAL(sigPartChanged(KonqView*,KParts::ReadOnlyPart*,KParts::ReadOnlyPart*)), m_pMainWindow, SLOT(slotPartChanged(KonqView*,KParts::ReadOnlyPart*,KParts::ReadOnlyPart*))); m_pMainWindow->insertChildView(v); int index = -1; if (openAfterCurrentPage) { index = m_tabContainer->currentIndex() + 1; } else if (pos > -1) { index = pos; } parentContainer->insertChildFrame(newViewFrame, index); if (parentContainer->frameType() != KonqFrameBase::Tabs) { newViewFrame->show(); } // Don't register passive views to the part manager if (!v->isPassiveMode()) { // note that KonqView's constructor could set this to true even if passiveMode is false addPart(v->part(), false); } else { // Passive views aren't registered, but we still want to detect the suicidal ones connect(v->part(), SIGNAL(destroyed()), this, SLOT(slotPassiveModePartDeleted())); } if (!m_bLoadingProfile) { m_pMainWindow->viewCountChanged(); } //qDebug() << "done"; return v; } void KonqViewManager::saveViewConfigToGroup(KConfigGroup &profileGroup, KonqFrameBase::Options options) { if (m_pMainWindow->childFrame()) { QString prefix = KonqFrameBase::frameTypeToString(m_pMainWindow->childFrame()->frameType()) + QString::number(0); profileGroup.writeEntry("RootItem", prefix); prefix.append(QLatin1Char('_')); m_pMainWindow->saveConfig(profileGroup, prefix, options, tabContainer(), 0, 1); } profileGroup.writeEntry("FullScreen", m_pMainWindow->fullScreenMode()); m_pMainWindow->saveMainWindowSettings(profileGroup); } void KonqViewManager::loadViewConfigFromGroup(const KConfigGroup &profileGroup, const QString &filename, const QUrl &forcedUrl, const KonqOpenURLRequest &req, bool openUrl) { Q_UNUSED(filename); // could be useful in case of error messages QUrl defaultURL; if (m_pMainWindow->currentView()) { defaultURL = m_pMainWindow->currentView()->url(); } clear(); if (forcedUrl.url() != QLatin1String("about:blank")) { loadRootItem(profileGroup, m_pMainWindow, defaultURL, openUrl && forcedUrl.isEmpty(), forcedUrl, req.serviceName); } else { // ## in this case we won't resize the window, so bool resetWindow could be useful after all? m_pMainWindow->disableActionsNoView(); m_pMainWindow->action("clear_location")->trigger(); } //qDebug() << "after loadRootItem"; // Set an active part first so that we open the URL in the current view // (to set the location bar correctly and asap) KonqView *nextChildView = 0; nextChildView = m_pMainWindow->activeChildView(); if (nextChildView == 0) { nextChildView = chooseNextView(0); } setActivePart(nextChildView ? nextChildView->part() : 0); // #71164 if (!req.browserArgs.frameName.isEmpty() && nextChildView) { nextChildView->setViewName(req.browserArgs.frameName); } if (openUrl && !forcedUrl.isEmpty()) { KonqOpenURLRequest _req(req); _req.openAfterCurrentPage = KonqSettings::openAfterCurrentPage(); _req.forceAutoEmbed = true; // it's a new window, let's use it m_pMainWindow->openUrl(nextChildView /* can be 0 for an empty profile */, forcedUrl, _req.args.mimeType(), _req, _req.browserArgs.trustedSource); // TODO choose a linked view if any (instead of just the first one), // then open the same URL in any non-linked one } else { if (forcedUrl.isEmpty() && m_pMainWindow->locationBarURL().isEmpty()) { // No URL -> the user will want to type one m_pMainWindow->focusLocationBar(); } } // Window size if (profileGroup.readEntry("FullScreen", false)) { // Full screen on m_pMainWindow->setWindowState(m_pMainWindow->windowState() | Qt::WindowFullScreen); } else { // Full screen off m_pMainWindow->setWindowState(m_pMainWindow->windowState() & ~Qt::WindowFullScreen); applyWindowSize(profileGroup); } //qDebug() << "done"; } void KonqViewManager::setActivePart(KParts::Part *part, QWidget *) { doSetActivePart(static_cast(part)); } void KonqViewManager::doSetActivePart(KParts::ReadOnlyPart *part) { if (part) { qDebug() << part << part->url(); } KParts::Part *mainWindowActivePart = m_pMainWindow->currentView() ? m_pMainWindow->currentView()->part() : 0; if (part == activePart() && mainWindowActivePart == part) { //qDebug() << "Part is already active!"; return; } // ## is this the right currentView() already? if (m_pMainWindow->currentView()) { m_pMainWindow->currentView()->setLocationBarURL(m_pMainWindow->locationBarURL()); } KParts::PartManager::setActivePart(part); if (part && part->widget()) { part->widget()->setFocus(); // However in case of an error URL we want to make it possible for the user to fix it KonqView *view = m_pMainWindow->viewMap().value(part); if (view && view->isErrorUrl()) { m_pMainWindow->focusLocationBar(); } } emitActivePartChanged(); // This is what triggers KonqMainWindow::slotPartActivated } void KonqViewManager::slotActivePartChanged(KParts::Part *newPart) { //qDebug() << newPart; if (newPart == 0L) { //qDebug() << "newPart = 0L , returning"; return; } // Send event to mainwindow - this is useful for plugins (like searchbar) KParts::PartActivateEvent ev(true, newPart, newPart->widget()); QApplication::sendEvent(m_pMainWindow, &ev); KonqView *view = m_pMainWindow->childView(static_cast(newPart)); if (view == 0L) { qDebug() << "No view associated with this part"; return; } if (view->frame()->parentContainer() == 0L) { return; } if (!m_bLoadingProfile) { view->frame()->statusbar()->updateActiveStatus(); view->frame()->parentContainer()->setActiveChild(view->frame()); } //qDebug() << "done"; } void KonqViewManager::emitActivePartChanged() { m_pMainWindow->slotPartActivated(activePart()); } // Read default size from profile (e.g. Width=80%) static QSize readDefaultSize(const KConfigGroup &cfg, QWidget *widget) { QString widthStr = cfg.readEntry("Width"); QString heightStr = cfg.readEntry("Height"); int width = -1; int height = -1; const QRect geom = QApplication::desktop()->screenGeometry(widget); bool ok; if (widthStr.endsWith('%')) { widthStr.truncate(widthStr.length() - 1); const int relativeWidth = widthStr.toInt(&ok); if (ok) { width = relativeWidth * geom.width() / 100; } } else { width = widthStr.toInt(&ok); if (!ok) { width = -1; } } if (heightStr.endsWith('%')) { heightStr.truncate(heightStr.length() - 1); int relativeHeight = heightStr.toInt(&ok); if (ok) { height = relativeHeight * geom.height() / 100; } } else { height = heightStr.toInt(&ok); if (!ok) { height = -1; } } return QSize(width, height); } void KonqViewManager::applyWindowSize(const KConfigGroup &profileGroup) { const QSize size = readDefaultSize(profileGroup, m_pMainWindow); // example: "Width=80%" if (size.isValid()) { m_pMainWindow->resize(size); } KWindowConfig::restoreWindowSize(m_pMainWindow->windowHandle(), profileGroup); // example: "Width 1400=1120" } void KonqViewManager::loadRootItem(const KConfigGroup &cfg, KonqFrameContainerBase *parent, const QUrl &defaultURL, bool openUrl, const QUrl &forcedUrl, const QString &forcedService, bool openAfterCurrentPage, int pos) { const QString rootItem = cfg.readEntry("RootItem", "empty"); // This flag is used by KonqView, to distinguish manual view creation // from profile loading (e.g. in switchView) m_bLoadingProfile = true; loadItem(cfg, parent, rootItem, defaultURL, openUrl, forcedUrl, forcedService, openAfterCurrentPage, pos); m_bLoadingProfile = false; m_pMainWindow->enableAllActions(true); // This flag disables calls to viewCountChanged while creating the views, // so we do it once at the end: viewCountChanged(); } void KonqViewManager::loadItem(const KConfigGroup &cfg, KonqFrameContainerBase *parent, const QString &name, const QUrl &defaultURL, bool openUrl, const QUrl &forcedUrl, const QString &forcedService, bool openAfterCurrentPage, int pos) { QString prefix; if (name != QLatin1String("InitialView")) { // InitialView is old stuff, not in use anymore prefix = name + QLatin1Char('_'); } #ifdef DEBUG_VIEWMGR qDebug() << "begin name=" << name << "openUrl=" << openUrl; #endif if (name.startsWith(QLatin1String("View")) || name == QLatin1String("empty")) { // load view config QString serviceType; QString serviceName; if (name == QLatin1String("empty")) { // An empty profile is an empty KHTML part. Makes all KHTML actions available, avoids crashes, // makes it easy to DND a URL onto it, and makes it fast to load a website from there. serviceType = QStringLiteral("text/html"); serviceName = forcedService; // coming e.g. from the cmdline, otherwise empty } else { serviceType = cfg.readEntry(QStringLiteral("ServiceType").prepend(prefix), QStringLiteral("inode/directory")); serviceName = cfg.readEntry(QStringLiteral("ServiceName").prepend(prefix), QString()); if (serviceName == QLatin1String("konq_aboutpage")) { - if ((!forcedUrl.isEmpty() && forcedUrl.scheme() != QLatin1String("about")) || + if ((!forcedUrl.isEmpty() && forcedUrl.scheme() != KonqAboutPage::aboutProtocol()) || (forcedUrl.isEmpty() && openUrl == false)) { // e.g. window.open // No point in loading the about page if we're going to replace it with a KHTML part right away serviceType = QStringLiteral("text/html"); serviceName = forcedService; // coming e.g. from the cmdline, otherwise empty } } } //qDebug() << "serviceType" << serviceType << serviceName; KService::Ptr service; KService::List partServiceOffers, appServiceOffers; KonqFactory konqFactory; KonqViewFactory viewFactory = konqFactory.createView(serviceType, serviceName, &service, &partServiceOffers, &appServiceOffers, true /*forceAutoEmbed*/); if (viewFactory.isNull()) { qWarning() << "Profile Loading Error: View creation failed"; return; //ugh.. } bool passiveMode = cfg.readEntry(QStringLiteral("PassiveMode").prepend(prefix), false); //qDebug() << "Creating View Stuff; parent=" << parent; if (parent == m_pMainWindow) { parent = tabContainer(); } KonqView *childView = setupView(parent, viewFactory, service, partServiceOffers, appServiceOffers, serviceType, passiveMode, openAfterCurrentPage, pos); if (!childView->isFollowActive()) { childView->setLinkedView(cfg.readEntry(QStringLiteral("LinkedView").prepend(prefix), false)); } const bool isToggleView = cfg.readEntry(QStringLiteral("ToggleView").prepend(prefix), false); childView->setToggleView(isToggleView); if (isToggleView /*100373*/ || !cfg.readEntry(QStringLiteral("ShowStatusBar").prepend(prefix), true)) { childView->frame()->statusbar()->hide(); } if (parent == m_tabContainer && m_tabContainer->count() == 1) { // First tab, make it the active one parent->setActiveChild(childView->frame()); } if (openUrl) { const QString keyHistoryItems = QStringLiteral("NumberOfHistoryItems").prepend(prefix); if (cfg.hasKey(keyHistoryItems)) { childView->loadHistoryConfig(cfg, prefix); m_pMainWindow->updateHistoryActions(); } else { // determine URL const QString urlKey = QStringLiteral("URL").prepend(prefix); QUrl url; if (cfg.hasKey(urlKey)) { url = QUrl(cfg.readPathEntry(urlKey, QStringLiteral("about:blank"))); } else if (urlKey == QLatin1String("empty_URL")) { // old stuff, not in use anymore url = QUrl(QLatin1String("about:blank")); } else { url = defaultURL; } if (!url.isEmpty()) { //qDebug() << "calling openUrl" << url; //childView->openUrl( url, url.toDisplayString() ); // We need view-follows-view (for the dirtree, for instance) KonqOpenURLRequest req; - if (url.scheme() != QLatin1String("about")) { + if (url.scheme() != KonqAboutPage::aboutProtocol()) { req.typedUrl = url.toDisplayString(); } m_pMainWindow->openView(serviceType, url, childView, req); } //else qDebug() << "url is empty"; } } // Do this after opening the URL, so that it's actually possible to open it :) childView->setLockedLocation(cfg.readEntry(QStringLiteral("LockedLocation").prepend(prefix), false)); } else if (name.startsWith(QLatin1String("Container"))) { //qDebug() << "Item is Container"; //load container config QString ostr = cfg.readEntry(QStringLiteral("Orientation").prepend(prefix), QString()); //qDebug() << "Orientation:" << ostr; Qt::Orientation o; if (ostr == QLatin1String("Vertical")) { o = Qt::Vertical; } else if (ostr == QLatin1String("Horizontal")) { o = Qt::Horizontal; } else { qWarning() << "Profile Loading Error: No orientation specified in" << name; o = Qt::Horizontal; } QList sizes = cfg.readEntry(QStringLiteral("SplitterSizes").prepend(prefix), QList()); int index = cfg.readEntry(QStringLiteral("activeChildIndex").prepend(prefix), -1); QStringList childList = cfg.readEntry(QStringLiteral("Children").prepend(prefix), QStringList()); if (childList.count() < 2) { qWarning() << "Profile Loading Error: Less than two children in" << name; // fallback to defaults loadItem(cfg, parent, QStringLiteral("InitialView"), defaultURL, openUrl, forcedUrl, forcedService); } else { KonqFrameContainer *newContainer = new KonqFrameContainer(o, parent->asQWidget(), parent); int tabindex = pos; if (openAfterCurrentPage && parent->frameType() == KonqFrameBase::Tabs) { // Need to honor it, if possible tabindex = static_cast(parent)->currentIndex() + 1; } parent->insertChildFrame(newContainer, tabindex); loadItem(cfg, newContainer, childList.at(0), defaultURL, openUrl, forcedUrl, forcedService); loadItem(cfg, newContainer, childList.at(1), defaultURL, openUrl, forcedUrl, forcedService); //qDebug() << "setSizes" << sizes; newContainer->setSizes(sizes); if (index == 1) { newContainer->setActiveChild(newContainer->secondChild()); } else if (index == 0) { newContainer->setActiveChild(newContainer->firstChild()); } newContainer->show(); } } else if (name.startsWith(QLatin1String("Tabs"))) { //qDebug() << "Item is a Tabs"; int index = cfg.readEntry(QStringLiteral("activeChildIndex").prepend(prefix), 0); if (!m_tabContainer) { createTabContainer(parent->asQWidget(), parent); parent->insertChildFrame(m_tabContainer); } const QStringList childList = cfg.readEntry(QStringLiteral("Children").prepend(prefix), QStringList()); for (QStringList::const_iterator it = childList.begin(); it != childList.end(); ++it) { loadItem(cfg, tabContainer(), *it, defaultURL, openUrl, forcedUrl, forcedService); QWidget *currentPage = m_tabContainer->currentWidget(); if (currentPage != 0L) { KonqView *activeChildView = dynamic_cast(currentPage)->activeChildView(); if (activeChildView != 0L) { activeChildView->setCaption(activeChildView->caption()); activeChildView->setTabIcon(activeChildView->url()); } } } QWidget *w = m_tabContainer->widget(index); if (w) { m_tabContainer->setActiveChild(dynamic_cast(w)); m_tabContainer->setCurrentIndex(index); m_tabContainer->show(); } else { qWarning() << "Profile Loading Error: Unknown current item index" << index; } } else { qWarning() << "Profile Loading Error: Unknown item" << name; } //qDebug() << "end" << name; } void KonqViewManager::setLoading(KonqView *view, bool loading) { tabContainer()->setLoading(view->frame(), loading); } ///////////////// Debug stuff //////////////// #ifndef NDEBUG void KonqViewManager::printSizeInfo(KonqFrameBase *frame, KonqFrameContainerBase *parent, const char *msg) { const QRect r = frame->asQWidget()->geometry(); qDebug("Child size %s : x: %d, y: %d, w: %d, h: %d", msg, r.x(), r.y(), r.width(), r.height()); if (parent->frameType() == KonqFrameBase::Container) { const QList sizes = static_cast(parent)->sizes(); printf("Parent sizes %s :", msg); foreach (int i, sizes) { printf(" %d", i); } printf("\n"); } } class KonqDebugFrameVisitor : public KonqFrameVisitor { public: KonqDebugFrameVisitor() {} bool visit(KonqFrame *frame) Q_DECL_OVERRIDE { QString className; if (!frame->part()) { className = QStringLiteral("NoPart!"); } else if (!frame->part()->widget()) { className = QStringLiteral("NoWidget!"); } else { className = frame->part()->widget()->metaObject()->className(); } qDebug() << m_spaces << frame << "parent=" << frame->parentContainer() << (frame->isHidden() ? "hidden" : "shown") << "containing view" << frame->childView() << "and part" << frame->part() << "whose widget is a" << className; return true; } bool visit(KonqFrameContainer *container) Q_DECL_OVERRIDE { qDebug() << m_spaces << container << (container->isHidden() ? "hidden" : "shown") << (container->orientation() == Qt::Horizontal ? "horizontal" : "vertical") << "sizes=" << container->sizes() << "parent=" << container->parentContainer() << "activeChild=" << container->activeChild(); if (!container->activeChild()) { qDebug() << "WARNING:" << container << "has a null active child!"; } m_spaces += QLatin1String(" "); return true; } bool visit(KonqFrameTabs *tabs) Q_DECL_OVERRIDE { qDebug() << m_spaces << "KonqFrameTabs" << tabs << "visible=" << tabs->isVisible() << "activeChild=" << tabs->activeChild(); if (!tabs->activeChild()) { qDebug() << "WARNING:" << tabs << "has a null active child!"; } m_spaces += QLatin1String(" "); return true; } bool visit(KonqMainWindow *) Q_DECL_OVERRIDE { return true; } bool endVisit(KonqFrameTabs *) Q_DECL_OVERRIDE { m_spaces.resize(m_spaces.size() - 2); return true; } bool endVisit(KonqFrameContainer *) Q_DECL_OVERRIDE { m_spaces.resize(m_spaces.size() - 2); return true; } bool endVisit(KonqMainWindow *) Q_DECL_OVERRIDE { return true; } private: QString m_spaces; }; void KonqViewManager::printFullHierarchy() { qDebug() << "currentView=" << m_pMainWindow->currentView(); KonqDebugFrameVisitor visitor; m_pMainWindow->accept(&visitor); } #endif KonqFrameTabs *KonqViewManager::tabContainer() { if (!m_tabContainer) { createTabContainer(m_pMainWindow /*as widget*/, m_pMainWindow /*as container*/); m_pMainWindow->insertChildFrame(m_tabContainer); } return m_tabContainer; } bool KonqViewManager::isTabBarVisible() const { if (!m_tabContainer) { return false; } return !m_tabContainer->tabBar()->isHidden(); } void KonqViewManager::createTabContainer(QWidget *parent, KonqFrameContainerBase *parentContainer) { #ifdef DEBUG_VIEWMGR qDebug() << "createTabContainer" << parent << parentContainer; #endif m_tabContainer = new KonqFrameTabs(parent, parentContainer, this); // Delay the opening of the URL for #106641 bool ok = connect(m_tabContainer, SIGNAL(openUrl(KonqView*,QUrl)), m_pMainWindow, SLOT(openUrl(KonqView*,QUrl)), Qt::QueuedConnection); Q_ASSERT(ok); Q_UNUSED(ok); applyConfiguration(); } void KonqViewManager::applyConfiguration() { tabContainer()->setAlwaysTabbedMode(KonqSettings::alwaysTabbedMode()); tabContainer()->setTabsClosable(KonqSettings::permanentCloseButton()); } KonqMainWindow *KonqViewManager::duplicateWindow() { QTemporaryFile tempFile; tempFile.open(); KConfig config(tempFile.fileName()); KConfigGroup group(&config, "Profile"); KonqFrameBase::Options flags = KonqFrameBase::saveHistoryItems; saveViewConfigToGroup(group, flags); KonqMainWindow *mainWindow = openSavedWindow(group); #ifndef NDEBUG mainWindow->viewManager()->printFullHierarchy(); #endif return mainWindow; }