diff --git a/CMakeLists.txt b/CMakeLists.txt index d68a86e..6c9ebe0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,96 +1,98 @@ cmake_minimum_required(VERSION 3.5) set(KF5_VERSION "5.63.0") # handled by release scripts set(KF5_DEP_VERSION "5.63.0") # handled by release scripts project(KParts VERSION ${KF5_VERSION}) include(FeatureSummary) find_package(ECM 5.63.0 NO_MODULE) set_package_properties(ECM PROPERTIES TYPE REQUIRED DESCRIPTION "Extra CMake Modules." URL "https://projects.kde.org/projects/kdesupport/extra-cmake-modules") feature_summary(WHAT REQUIRED_PACKAGES_NOT_FOUND FATAL_ON_MISSING_REQUIRED_PACKAGES) set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH}) include(KDEInstallDirs) include(KDEFrameworkCompilerSettings NO_POLICY_SCOPE) include(KDECMakeSettings) include(KDEPackageAppTemplates) include(ECMAddQch) -include(GenerateExportHeader) +include(ECMGenerateExportHeader) include(ECMSetupVersion) +set(EXCLUDE_DEPRECATED_BEFORE_AND_AT 0 CACHE STRING "Control how much of deprecated API is build [default=0].") + option(BUILD_QCH "Build API documentation in QCH format (for e.g. Qt Assistant, Qt Creator & KDevelop)" OFF) add_feature_info(QCH ${BUILD_QCH} "API documentation in QCH format (for e.g. Qt Assistant, Qt Creator & KDevelop)") ecm_setup_version(PROJECT VARIABLE_PREFIX KPARTS VERSION_HEADER "${CMAKE_CURRENT_BINARY_DIR}/kparts_version.h" PACKAGE_VERSION_FILE "${CMAKE_CURRENT_BINARY_DIR}/KF5PartsConfigVersion.cmake" SOVERSION 5) set(REQUIRED_QT_VERSION 5.11.0) find_package(Qt5 ${REQUIRED_QT_VERSION} CONFIG REQUIRED Core Widgets Xml) find_package(KF5Config ${KF5_DEP_VERSION} REQUIRED) find_package(KF5CoreAddons ${KF5_DEP_VERSION} REQUIRED) find_package(KF5I18n ${KF5_DEP_VERSION} REQUIRED) find_package(KF5IconThemes ${KF5_DEP_VERSION} REQUIRED) find_package(KF5KIO ${KF5_DEP_VERSION} REQUIRED) find_package(KF5JobWidgets ${KF5_DEP_VERSION} REQUIRED) find_package(KF5Service ${KF5_DEP_VERSION} REQUIRED) find_package(KF5TextWidgets ${KF5_DEP_VERSION} REQUIRED) find_package(KF5WidgetsAddons ${KF5_DEP_VERSION} REQUIRED) find_package(KF5XmlGui ${KF5_DEP_VERSION} REQUIRED) if(BUILD_TESTING) add_subdirectory( tests ) add_subdirectory( autotests ) endif() add_definitions(-DTRANSLATION_DOMAIN=\"kparts5\") if (IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/po") ki18n_install(po) endif() add_definitions(-DQT_DISABLE_DEPRECATED_BEFORE=0x050d00) add_definitions(-DQT_NO_FOREACH) add_subdirectory( src ) add_subdirectory(templates) # create a Config.cmake and a ConfigVersion.cmake file and install them set(CMAKECONFIG_INSTALL_DIR "${KDE_INSTALL_CMAKEPACKAGEDIR}/KF5Parts") if (BUILD_QCH) ecm_install_qch_export( TARGETS KF5Parts_QCH FILE KF5PartsQchTargets.cmake DESTINATION "${CMAKECONFIG_INSTALL_DIR}" COMPONENT Devel ) set(PACKAGE_INCLUDE_QCHTARGETS "include(\"\${CMAKE_CURRENT_LIST_DIR}/KF5PartsQchTargets.cmake\")") endif() include(CMakePackageConfigHelpers) configure_package_config_file( "${CMAKE_CURRENT_SOURCE_DIR}/KF5PartsConfig.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/KF5PartsConfig.cmake" INSTALL_DESTINATION ${CMAKECONFIG_INSTALL_DIR} ) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/KF5PartsConfig.cmake" "${CMAKE_CURRENT_BINARY_DIR}/KF5PartsConfigVersion.cmake" DESTINATION "${CMAKECONFIG_INSTALL_DIR}" COMPONENT Devel ) install(EXPORT KF5PartsTargets DESTINATION "${CMAKECONFIG_INSTALL_DIR}" FILE KF5PartsTargets.cmake NAMESPACE KF5:: ) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/kparts_version.h DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF5} COMPONENT Devel ) feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f896abc..83b283d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,143 +1,151 @@ set(KParts_LIB_SRCS partbase.cpp part.cpp openurlarguments.cpp readonlypart.cpp readwritepart.cpp plugin.cpp partmanager.cpp mainwindow.cpp event.cpp guiactivateevent.cpp partactivateevent.cpp partselectevent.cpp browserextension.cpp browserhostextension.cpp browserarguments.cpp liveconnectextension.cpp openurlevent.cpp windowargs.cpp historyprovider.cpp browserinterface.cpp browserrun.cpp browseropenorsavequestion.cpp statusbarextension.cpp scriptableextension.cpp textextension.cpp htmlextension.cpp htmlsettingsinterface.cpp selectorinterface.cpp fileinfoextension.cpp listingfilterextension.cpp listingnotificationextension.cpp ) include(ECMGenerateHeaders) ecm_generate_headers(KParts_CamelCase_HEADERS HEADER_NAMES BrowserArguments BrowserExtension BrowserHostExtension BrowserInterface BrowserOpenOrSaveQuestion BrowserRun Event FileInfoExtension GUIActivateEvent HistoryProvider HtmlExtension HtmlSettingsInterface ListingFilterExtension ListingNotificationExtension LiveConnectExtension MainWindow OpenUrlArguments OpenUrlEvent Part PartActivateEvent PartBase PartManager PartSelectEvent Plugin ReadOnlyPart ReadWritePart ScriptableExtension SelectorInterface StatusBarExtension TextExtension WindowArgs REQUIRED_HEADERS KParts_HEADERS PREFIX KParts ) install(FILES ${KParts_CamelCase_HEADERS} DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF5}/KParts/KParts COMPONENT Devel) add_library(KF5Parts ${KParts_LIB_SRCS}) -generate_export_header(KF5Parts EXPORT_FILE_NAME ${KParts_BINARY_DIR}/kparts/kparts_export.h BASE_NAME KParts) add_library(KF5::Parts ALIAS KF5Parts) +ecm_generate_export_header(KF5Parts + EXPORT_FILE_NAME ${KParts_BINARY_DIR}/kparts/kparts_export.h + BASE_NAME KParts + # GROUP_BASE_NAME KF <- enable once all of KF modules use ecm_generate_export_header + VERSION ${KF5_VERSION} + DEPRECATED_BASE_VERSION 0 + DEPRECATION_VERSIONS 5.0 + EXCLUDE_DEPRECATED_BEFORE_AND_AT ${EXCLUDE_DEPRECATED_BEFORE_AND_AT} +) set(KParts_BUILD_INCLUDE_DIRS ${KParts_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}) target_include_directories(KF5Parts PUBLIC "$") target_include_directories(KF5Parts INTERFACE "$" ) target_link_libraries(KF5Parts PUBLIC KF5::KIOWidgets #browserrun.h uses krun.h KF5::XmlGui # essential to the technology KF5::TextWidgets # needed for KFind, as interface PRIVATE KF5::I18n #few uses of i18n and i18nc, can be probably stripped down KF5::IconThemes #only used by KPart::iconLoader() ) set_target_properties(KF5Parts PROPERTIES VERSION ${KPARTS_VERSION_STRING} SOVERSION ${KPARTS_SOVERSION} EXPORT_NAME Parts ) install(TARGETS KF5Parts EXPORT KF5PartsTargets ${KF5_INSTALL_TARGETS_DEFAULT_ARGS}) install(FILES kpart.desktop krop.desktop krwp.desktop browserview.desktop DESTINATION ${KDE_INSTALL_KSERVICETYPES5DIR} ) install(FILES ${KParts_BINARY_DIR}/kparts/kparts_export.h ${KParts_HEADERS} DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF5}/KParts/kparts COMPONENT Devel ) install(FILES kde_terminal_interface.h DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF5}/KParts ) if(BUILD_QCH) ecm_add_qch( KF5Parts_QCH NAME KParts BASE_NAME KF5Parts VERSION ${KF5_VERSION} ORG_DOMAIN org.kde SOURCES # using only public headers, to cover only public API ${KParts_HEADERS} kde_terminal_interface.h MD_MAINPAGE "${CMAKE_SOURCE_DIR}/README.md" LINK_QCHS KF5KIO_QCH KF5XmlGui_QCH KF5TextWidgets_QCH INCLUDE_DIRS ${KParts_BUILD_INCLUDE_DIRS} BLANK_MACROS KPARTS_EXPORT KPARTS_DEPRECATED KPARTS_DEPRECATED_EXPORT TAGFILE_INSTALL_DESTINATION ${KDE_INSTALL_QTQCHDIR} QCH_INSTALL_DESTINATION ${KDE_INSTALL_QTQCHDIR} COMPONENT Devel ) endif() include(ECMGeneratePriFile) ecm_generate_pri_file(BASE_NAME KParts LIB_NAME KF5Parts DEPS "KIOWidgets KXmlGui KTextWidgets" FILENAME_VAR PRI_FILENAME INCLUDE_INSTALL_DIR ${KDE_INSTALL_INCLUDEDIR_KF5}/KParts) install(FILES ${PRI_FILENAME} DESTINATION ${ECM_MKSPECS_INSTALL_DIR}) diff --git a/src/browserextension.h b/src/browserextension.h index 44b9a44..2d99865 100644 --- a/src/browserextension.h +++ b/src/browserextension.h @@ -1,483 +1,485 @@ /* This file is part of the KDE project Copyright (C) 1999 Simon Hausmann David Faure This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef __kparts_browserextension_h__ #define __kparts_browserextension_h__ #include #include #include #include #include //mode_t template class QMap; template class QList; class KFileItem; class KFileItemList; class QDataStream; class QPoint; namespace KParts { class BrowserInterface; /** * The Browser Extension is an extension (yes, no kidding) to * KParts::ReadOnlyPart, which allows a better integration of parts * with browsers (in particular Konqueror). * Remember that ReadOnlyPart only has openUrl(QUrl) and a few arguments() but not much more. * For full-fledged browsing, we need much more than that, including * enabling/disabling of standard actions (print, copy, paste...), * allowing parts to save and restore their data into the back/forward history, * allowing parts to control the location bar URL, to requests URLs * to be opened by the hosting browser, etc. * * The part developer needs to define its own class derived from BrowserExtension, * to implement the virtual methods [and the standard-actions slots, see below]. * * The way to associate the BrowserExtension with the part is to simply * create the BrowserExtension as a child of the part (in QObject's terms). * The hosting application will look for it automatically. * * Another aspect of the browser integration is that a set of standard * actions are provided by the browser, but implemented by the part * (for the actions it supports). * * The following standard actions are defined by the host of the view: * * [selection-dependent actions] * @li @p cut : Copy selected items to clipboard and store 'not cut' in clipboard. * @li @p copy : Copy selected items to clipboard and store 'cut' in clipboard. * @li @p paste : Paste clipboard into view URL. * @li @p pasteTo(const QUrl &) : Paste clipboard into given URL. * @li @p searchProvider : Lookup selected text at default search provider * * [normal actions] * @li None anymore. * * * The view defines a slot with the name of the action in order to implement the action. * The browser will detect the slot automatically and connect its action to it when * appropriate (i.e. when the view is active). * * * The selection-dependent actions are disabled by default and the view should * enable them when the selection changes, emitting enableAction(). * * The normal actions do not depend on the selection. * * A special case is the configuration slots, not connected to any action directly. * * [configuration slot] * @li @p reparseConfiguration : Re-read configuration and apply it. * @li @p disableScrolling: no scrollbars */ class KPARTS_EXPORT BrowserExtension : public QObject { Q_OBJECT Q_PROPERTY(bool urlDropHandling READ isURLDropHandlingEnabled WRITE setURLDropHandlingEnabled) public: /** * Constructor * * @param parent The KParts::ReadOnlyPart that this extension ... "extends" :) */ explicit BrowserExtension(KParts::ReadOnlyPart *parent); virtual ~BrowserExtension(); /** * Set of flags passed via the popupMenu signal, to ask for some items in the popup menu. */ enum PopupFlag { DefaultPopupItems = 0x0000, /**< default value, no additional menu item */ +#if KPARTS_ENABLE_DEPRECATED_SINCE(5, 27) ShowNavigationItems = 0x0001, /**< @deprecated since 5.27, no effect anymore */ ShowUp = 0x0002, /**< @deprecated since 5.27, no effect anymore */ ShowReload = 0x0004, /**< @deprecated since 5.27, no effect anymore */ +#endif ShowBookmark = 0x0008, /**< show "add to bookmarks" (usually not done on the local filesystem) */ ShowCreateDirectory = 0x0010, /**< show "create directory" (usually only done on the background of the view, or * in hierarchical views like directory trees, where the new dir would be visible) */ ShowTextSelectionItems = 0x0020, /**< set when selecting text, for a popup that only contains text-related items. */ NoDeletion = 0x0040, /**< deletion, trashing and renaming not allowed (e.g. parent dir not writeable). * (this is only needed if the protocol itself supports deletion, unlike e.g. HTTP) */ IsLink = 0x0080, /**< show "Bookmark This Link" and other link-related actions (linkactions merging group) */ ShowUrlOperations = 0x0100, /**< show copy, paste, as well as cut if NoDeletion is not set. */ ShowProperties = 0x200 /**< show "Properties" action (usually done by directory views) */ }; Q_DECLARE_FLAGS(PopupFlags, PopupFlag) /** * Set the parameters to use for opening the next URL. * This is called by the "hosting" application, to pass parameters to the part. * @see BrowserArguments */ virtual void setBrowserArguments(const BrowserArguments &args); /** * Retrieve the set of parameters to use for opening the URL * (this must be called from openUrl() in the part). * @see BrowserArguments */ BrowserArguments browserArguments() const; /** * Returns the current x offset. * * For a scrollview, implement this using contentsX(). */ virtual int xOffset(); /** * Returns the current y offset. * * For a scrollview, implement this using contentsY(). */ virtual int yOffset(); /** * Used by the browser to save the current state of the view * (in order to restore it if going back in navigation). * * If you want to save additional properties, reimplement it * but don't forget to call the parent method (probably first). */ virtual void saveState(QDataStream &stream); /** * Used by the browser to restore the view in the state * it was when we left it. * * If you saved additional properties, reimplement it * but don't forget to call the parent method (probably first). */ virtual void restoreState(QDataStream &stream); /** * Returns whether url drop handling is enabled. * See setURLDropHandlingEnabled for more information about this * property. */ bool isURLDropHandlingEnabled() const; /** * Enables or disables url drop handling. URL drop handling is a property * describing whether the hosting shell component is allowed to install an * event filter on the part's widget, to listen for URI drop events. * Set it to true if you are exporting a BrowserExtension implementation and * do not provide any special URI drop handling. If set to false you can be * sure to receive all those URI drop events unfiltered. Also note that the * implementation as of Konqueror installs the event filter only on the part's * widget itself, not on child widgets. */ void setURLDropHandlingEnabled(bool enable); void setBrowserInterface(BrowserInterface *impl); BrowserInterface *browserInterface() const; /** * @return the status (enabled/disabled) of an action. * When the enableAction signal is emitted, the browserextension * stores the status of the action internally, so that it's possible * to query later for the status of the action, using this method. */ bool isActionEnabled(const char *name) const; /** * @return the text of an action, if it was set explicitly by the part. * When the setActionText signal is emitted, the browserextension * stores the text of the action internally, so that it's possible * to query later for the text of the action, using this method. */ QString actionText(const char *name) const; typedef QMap ActionSlotMap; /** * Returns a map containing the action names as keys and corresponding * SLOT()'ified method names as data entries. * * This is very useful for * the host component, when connecting the own signals with the * extension's slots. * Basically you iterate over the map, check if the extension implements * the slot and connect to the slot using the data value of your map * iterator. * Checking if the extension implements a certain slot can be done like this: * * \code * extension->metaObject()->slotNames().contains( actionName + "()" ) * \endcode * * (note that @p actionName is the iterator's key value if already * iterating over the action slot map, returned by this method) * * Connecting to the slot can be done like this: * * \code * connect( yourObject, SIGNAL( yourSignal() ), * extension, mapIterator.data() ) * \endcode * * (where "mapIterator" is your QMap iterator) */ static ActionSlotMap actionSlotMap(); /** * @return a pointer to the static action-slot map. Preferred method to get it. * The map is created if it doesn't exist yet */ static ActionSlotMap *actionSlotMapPtr(); /** * Queries @p obj for a child object which inherits from this * BrowserExtension class. Convenience method. */ static BrowserExtension *childObject(QObject *obj); /** * Asks the hosting browser to perform a paste (using openUrlRequestDelayed()) */ void pasteRequest(); /** * Associates a list of actions with a predefined name known by the host's popupmenu: * "editactions" for actions related text editing, * "linkactions" for actions related to hyperlinks, * "partactions" for any other actions provided by the part */ typedef QMap > ActionGroupMap; Q_SIGNALS: /** * Enables or disable a standard action held by the browser. * * See class documentation for the list of standard actions. */ void enableAction(const char *name, bool enabled); /** * Change the text of a standard action held by the browser. * This can be used to change "Paste" into "Paste Image" for instance. * * See class documentation for the list of standard actions. */ void setActionText(const char *name, const QString &text); /** * Asks the host (browser) to open @p url. * To set a reload, the x and y offsets, the service type etc., fill in the * appropriate fields in the @p args structure. * Hosts should not connect to this signal but to openUrlRequestDelayed(). */ void openUrlRequest(const QUrl &url, const KParts::OpenUrlArguments &arguments = KParts::OpenUrlArguments(), const KParts::BrowserArguments &browserArguments = KParts::BrowserArguments()); /** * This signal is emitted when openUrlRequest() is called, after a 0-seconds timer. * This allows the caller to terminate what it's doing first, before (usually) * being destroyed. Parts should never use this signal, hosts should only connect * to this signal. */ void openUrlRequestDelayed(const QUrl &url, const KParts::OpenUrlArguments &arguments, const KParts::BrowserArguments &browserArguments); /** * Tells the hosting browser that the part opened a new URL (which can be * queried via KParts::Part::url(). * * This helps the browser to update/create an entry in the history. * The part may @em not emit this signal together with openUrlRequest(). * Emit openUrlRequest() if you want the browser to handle a URL the user * asked to open (from within your part/document). This signal however is * useful if you want to handle URLs all yourself internally, while still * telling the hosting browser about new opened URLs, in order to provide * a proper history functionality to the user. * An example of usage is a html rendering component which wants to emit * this signal when a child frame document changed its URL. * Conclusion: you probably want to use openUrlRequest() instead. */ void openUrlNotify(); /** * Updates the URL shown in the browser's location bar to @p url. */ void setLocationBarUrl(const QString &url); /** * Sets the URL of an icon for the currently displayed page. */ void setIconUrl(const QUrl &url); /** * Asks the hosting browser to open a new window for the given @p url * and return a reference to the content part. * * @p arguments is optional additional information about how to open the url, * @see KParts::OpenUrlArguments * * @p browserArguments is optional additional information for web browsers, * @see KParts::BrowserArguments * * The request for a pointer to the part is only fulfilled/processed * if the mimeType is set in the @p browserArguments. * (otherwise the request cannot be processed synchronously). */ void createNewWindow(const QUrl &url, const KParts::OpenUrlArguments &arguments = KParts::OpenUrlArguments(), const KParts::BrowserArguments &browserArguments = KParts::BrowserArguments(), const KParts::WindowArgs &windowArgs = KParts::WindowArgs(), KParts::ReadOnlyPart **part = nullptr); // TODO consider moving to BrowserHostExtension? /** * Since the part emits the jobid in the started() signal, * progress information is automatically displayed. * * However, if you don't use a KIO::Job in the part, * you can use loadingProgress() and speedProgress() * to display progress information. */ void loadingProgress(int percent); /** * @see loadingProgress */ void speedProgress(int bytesPerSecond); void infoMessage(const QString &); /** * Emit this to make the browser show a standard popup menu for the files @p items. * * @param global global coordinates where the popup should be shown * @param items list of file items which the popup applies to * @param args OpenUrlArguments, mostly for metadata here * @param browserArguments BrowserArguments, mostly for referrer * @param flags enables/disables certain builtin actions in the popupmenu * @param actionGroups named groups of actions which should be inserted into the popup, see ActionGroupMap */ void popupMenu(const QPoint &global, const KFileItemList &items, const KParts::OpenUrlArguments &args = KParts::OpenUrlArguments(), const KParts::BrowserArguments &browserArguments = KParts::BrowserArguments(), KParts::BrowserExtension::PopupFlags flags = KParts::BrowserExtension::DefaultPopupItems, const KParts::BrowserExtension::ActionGroupMap &actionGroups = ActionGroupMap()); /** * Emit this to make the browser show a standard popup menu for the given @p url. * * Give as much information about this URL as possible, * like @p args.mimeType and the file type @p mode * * @param global global coordinates where the popup should be shown * @param url the URL this popup applies to * @param mode the file type of the url (S_IFREG, S_IFDIR...) * @param args OpenUrlArguments, set the mimetype of the URL using setMimeType() * @param browserArguments BrowserArguments, mostly for referrer * @param flags enables/disables certain builtin actions in the popupmenu * @param actionGroups named groups of actions which should be inserted into the popup, see ActionGroupMap */ void popupMenu(const QPoint &global, const QUrl &url, mode_t mode = static_cast(-1), const KParts::OpenUrlArguments &args = KParts::OpenUrlArguments(), const KParts::BrowserArguments &browserArguments = KParts::BrowserArguments(), KParts::BrowserExtension::PopupFlags flags = KParts::BrowserExtension::DefaultPopupItems, const KParts::BrowserExtension::ActionGroupMap &actionGroups = ActionGroupMap()); /** * Inform the hosting application about the current selection. * Used when a set of files/URLs is selected (with full information * about those URLs, including size, permissions etc.) */ void selectionInfo(const KFileItemList &items); /** * Inform the hosting application about the current selection. * Used when some text is selected. */ void selectionInfo(const QString &text); /** * Inform the hosting application about the current selection. * Used when a set of URLs is selected. */ void selectionInfo(const QList &urls); /** * Inform the hosting application that the user moved the mouse over an item. * Used when the mouse is on an URL. */ void mouseOverInfo(const KFileItem &item); /** * Ask the hosting application to add a new HTML (aka Mozilla/Netscape) * SideBar entry. */ void addWebSideBar(const QUrl &url, const QString &name); /** * Ask the hosting application to move the top level widget. */ void moveTopLevelWidget(int x, int y); /** * Ask the hosting application to resize the top level widget. */ void resizeTopLevelWidget(int w, int h); /** * Ask the hosting application to focus @p part. */ void requestFocus(KParts::ReadOnlyPart *part); /** * Tell the host (browser) about security state of current page * enum PageSecurity { NotCrypted, Encrypted, Mixed }; */ void setPageSecurity(int); /** * Inform the host about items that have been removed. */ void itemsRemoved(const KFileItemList &items); private Q_SLOTS: void slotCompleted(); void slotOpenUrlRequest(const QUrl &url, const KParts::OpenUrlArguments &arguments = KParts::OpenUrlArguments(), const KParts::BrowserArguments &browserArguments = KParts::BrowserArguments()); void slotEmitOpenUrlRequestDelayed(); void slotEnableAction(const char *, bool); void slotSetActionText(const char *, const QString &); public: typedef QMap ActionNumberMap; private: class BrowserExtensionPrivate; BrowserExtensionPrivate *const d; }; } Q_DECLARE_OPERATORS_FOR_FLAGS(KParts::BrowserExtension::PopupFlags) #endif diff --git a/src/browserrun.cpp b/src/browserrun.cpp index f71bc34..650a184 100644 --- a/src/browserrun.cpp +++ b/src/browserrun.cpp @@ -1,579 +1,579 @@ /* This file is part of the KDE project * * Copyright (C) 2002 David Faure * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License version 2, as published by the Free Software Foundation. * * This library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "browserrun.h" #include "browserrun_p.h" #include "browseropenorsavequestion.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace KParts; class Q_DECL_HIDDEN BrowserRun::BrowserRunPrivate { public: bool m_bHideErrorDialog; bool m_bRemoveReferrer; bool m_bTrustedSource; KParts::OpenUrlArguments m_args; KParts::BrowserArguments m_browserArgs; KParts::ReadOnlyPart *m_part; // QGuardedPtr? QPointer m_window; QString m_mimeType; QString m_contentDisposition; }; BrowserRun::BrowserRun(const QUrl &url, const KParts::OpenUrlArguments &args, const KParts::BrowserArguments &browserArgs, KParts::ReadOnlyPart *part, QWidget *window, bool removeReferrer, bool trustedSource, bool hideErrorDialog) : KRun(url, window, false /* no GUI */), d(new BrowserRunPrivate) { d->m_bHideErrorDialog = hideErrorDialog; d->m_bRemoveReferrer = removeReferrer; d->m_bTrustedSource = trustedSource; d->m_args = args; d->m_browserArgs = browserArgs; d->m_part = part; d->m_window = window; } BrowserRun::~BrowserRun() { delete d; } KParts::ReadOnlyPart *BrowserRun::part() const { return d->m_part; } QUrl BrowserRun::url() const { return KRun::url(); } void BrowserRun::init() { if (d->m_bHideErrorDialog) { // ### KRun doesn't call a virtual method when it finds out that the URL // is either malformed, or points to a non-existing local file... // So we need to reimplement some of the checks, to handle d->m_bHideErrorDialog if (!KRun::url().isValid()) { redirectToError(KIO::ERR_MALFORMED_URL, KRun::url().toString()); return; } if (isLocalFile()) { const QString localPath = KRun::url().toLocalFile(); if (!QFile::exists(localPath)) { // qDebug() << localPath << "doesn't exist."; redirectToError(KIO::ERR_DOES_NOT_EXIST, localPath); return; } } } KRun::init(); } void BrowserRun::scanFile() { const QUrl url = KRun::url(); // qDebug() << url; // Let's check for well-known extensions // Not when there is a query in the URL, in any case. // Optimization for http/https, findByURL doesn't trust extensions over http. QString protocol = url.scheme(); if (!KProtocolInfo::proxiedBy(protocol).isEmpty()) { QString dummy; protocol = KProtocolManager::slaveProtocol(url, dummy); } if (!url.hasQuery() && !protocol.startsWith(QLatin1String("http")) && (!url.path().endsWith(QLatin1Char('/')) || KProtocolManager::supportsListing(url))) { QMimeDatabase db; QMimeType mime = db.mimeTypeForUrl(url); if (!mime.isDefault() || isLocalFile()) { // qDebug() << "MIME TYPE is" << mime.name(); mimeTypeDetermined(mime.name()); return; } } QMap &metaData = d->m_args.metaData(); if (d->m_part) { const QString proto = d->m_part->url().scheme(); if (proto == QLatin1String("https") || proto == QLatin1String("webdavs")) { metaData.insert(QStringLiteral("main_frame_request"), QStringLiteral("TRUE")); metaData.insert(QStringLiteral("ssl_was_in_use"), QStringLiteral("TRUE")); // metaData.insert(QStringLiteral("ssl_activate_warnings"), QStringLiteral("TRUE")); } else if (proto == QLatin1String("http") || proto == QLatin1String("webdav")) { // metaData.insert(QStringLiteral("ssl_activate_warnings"), QStringLiteral("TRUE")); metaData.insert(QStringLiteral("ssl_was_in_use"), QStringLiteral("FALSE")); } // Set the PropagateHttpHeader meta-data if it has not already been set... if (!metaData.contains(QStringLiteral("PropagateHttpHeader"))) { metaData.insert(QStringLiteral("PropagateHttpHeader"), QStringLiteral("TRUE")); } } KIO::TransferJob *job; if (d->m_browserArgs.doPost() && url.scheme().startsWith(QLatin1String("http"))) { job = KIO::http_post(url, d->m_browserArgs.postData, KIO::HideProgressInfo); job->addMetaData(QStringLiteral("content-type"), d->m_browserArgs.contentType()); } else { job = KIO::get(url, d->m_args.reload() ? KIO::Reload : KIO::NoReload, KIO::HideProgressInfo); } if (d->m_bRemoveReferrer) { metaData.remove(QStringLiteral("referrer")); } job->addMetaData(metaData); KJobWidgets::setWindow(job, d->m_window); connect(job, &KIO::TransferJob::result, this, &BrowserRun::slotBrowserScanFinished); connect(job, static_cast(&KIO::TransferJob::mimetype), this, &BrowserRun::slotBrowserMimetype); setJob(job); } void BrowserRun::slotBrowserScanFinished(KJob *job) { // qDebug() << job->error(); if (job->error() == KIO::ERR_IS_DIRECTORY) { // It is in fact a directory. This happens when HTTP redirects to FTP. // Due to the "protocol doesn't support listing" code in BrowserRun, we // assumed it was a file. // qDebug() << "It is in fact a directory!"; // Update our URL in case of a redirection KRun::setUrl(static_cast(job)->url()); setJob(nullptr); mimeTypeDetermined(QStringLiteral("inode/directory")); } else { KRun::slotScanFinished(job); } } static QMimeType fixupMimeType(const QString &mimeType, const QString &fileName) { QMimeDatabase db; QMimeType mime = db.mimeTypeForName(mimeType); if ((!mime.isValid() || mime.isDefault()) && !fileName.isEmpty()) { mime = db.mimeTypeForFile(fileName, QMimeDatabase::MatchExtension); } return mime; } void BrowserRun::slotBrowserMimetype(KIO::Job *_job, const QString &type) { Q_ASSERT(_job == KRun::job()); Q_UNUSED(_job) KIO::TransferJob *job = static_cast(KRun::job()); // Update our URL in case of a redirection //qDebug() << "old URL=" << KRun::url(); //qDebug() << "new URL=" << job->url(); setUrl(job->url()); if (job->isErrorPage()) { d->m_mimeType = type; handleError(job); setJob(nullptr); } else { // qDebug() << "found" << type << "for" << KRun::url(); // Suggested filename given by the server (e.g. HTTP content-disposition) // When set, we should really be saving instead of embedding const QString suggestedFileName = job->queryMetaData(QStringLiteral("content-disposition-filename")); setSuggestedFileName(suggestedFileName); // store it (in KRun) //qDebug() << "suggestedFileName=" << suggestedFileName; d->m_contentDisposition = job->queryMetaData(QStringLiteral("content-disposition-type")); const QString modificationTime = job->queryMetaData(QStringLiteral("content-disposition-modification-date")); if (!modificationTime.isEmpty()) { d->m_args.metaData().insert(QStringLiteral("content-disposition-modification-date"), modificationTime); } QMapIterator it(job->metaData()); while (it.hasNext()) { it.next(); if (it.key().startsWith(QLatin1String("ssl_"), Qt::CaseInsensitive)) { d->m_args.metaData().insert(it.key(), it.value()); } } // Make a copy to avoid a dead reference QString _type = type; job->putOnHold(); setJob(nullptr); // If the current mime-type is the default mime-type, then attempt to // determine the "real" mimetype from the file name. QMimeType mime = fixupMimeType(_type, suggestedFileName.isEmpty() ? url().fileName() : suggestedFileName); if (mime.isValid() && mime.name() != _type) { _type = mime.name(); } mimeTypeDetermined(_type); } } BrowserRun::NonEmbeddableResult BrowserRun::handleNonEmbeddable(const QString &mimeType) { return handleNonEmbeddable(mimeType, nullptr); } BrowserRun::NonEmbeddableResult BrowserRun::handleNonEmbeddable(const QString &_mimeType, KService::Ptr *selectedService) { QString mimeType(_mimeType); Q_ASSERT(!hasFinished()); // only come here if the mimetype couldn't be embedded // Support for saving remote files. if (mimeType != QLatin1String("inode/directory") && // dirs can't be saved !KRun::url().isLocalFile()) { if (isTextExecutable(mimeType)) { mimeType = QStringLiteral("text/plain"); // view, don't execute } // ... -> ask whether to save BrowserOpenOrSaveQuestion question(d->m_window, KRun::url(), mimeType); question.setSuggestedFileName(suggestedFileName()); if (selectedService) { question.setFeatures(BrowserOpenOrSaveQuestion::ServiceSelection); } BrowserOpenOrSaveQuestion::Result res = question.askOpenOrSave(); if (res == BrowserOpenOrSaveQuestion::Save) { save(KRun::url(), suggestedFileName()); // qDebug() << "Save: returning Handled"; setFinished(true); return Handled; } else if (res == BrowserOpenOrSaveQuestion::Cancel) { // saving done or canceled // qDebug() << "Cancel: returning Handled"; setFinished(true); return Handled; } else { // "Open" chosen (done by KRun::foundMimeType, called when returning NotHandled) // If we were in a POST, we can't just pass a URL to an external application. // We must save the data to a tempfile first. if (d->m_browserArgs.doPost()) { // qDebug() << "request comes from a POST, can't pass a URL to another app, need to save"; d->m_mimeType = mimeType; QString extension; QString fileName = suggestedFileName().isEmpty() ? KRun::url().fileName() : suggestedFileName(); int extensionPos = fileName.lastIndexOf(QLatin1Char('.')); if (extensionPos != -1) { extension = fileName.mid(extensionPos); // keep the '.' } QTemporaryFile tempFile(QDir::tempPath() + QLatin1Char('/') + QCoreApplication::applicationName() + QLatin1String("XXXXXX") + extension); tempFile.setAutoRemove(false); tempFile.open(); QUrl destURL = QUrl::fromLocalFile(tempFile.fileName()); KIO::Job *job = KIO::file_copy(KRun::url(), destURL, 0600, KIO::Overwrite); KJobWidgets::setWindow(job, d->m_window); connect(job, &KIO::Job::result, this, &BrowserRun::slotCopyToTempFileResult); return Delayed; // We'll continue after the job has finished } if (selectedService && question.selectedService()) { *selectedService = question.selectedService(); // KRun will use this when starting an app KRun::setPreferredService(question.selectedService()->desktopEntryName()); } } } // Check if running is allowed if (!d->m_bTrustedSource && // ... and untrusted source... !allowExecution(mimeType, KRun::url())) { // ...and the user said no (for executables etc.) setFinished(true); return Handled; } KIO::Scheduler::publishSlaveOnHold(); // publish any slave on hold so it can be reused. return NotHandled; } //static bool BrowserRun::allowExecution(const QString &mimeType, const QUrl &url) { if (!KRun::isExecutable(mimeType)) { return true; } if (!url.isLocalFile()) { // Don't permit to execute remote files return false; } return (KMessageBox::warningContinueCancel(nullptr, i18n("Do you really want to execute '%1'?", url.toDisplayString()), i18n("Execute File?"), KGuiItem(i18n("Execute"))) == KMessageBox::Continue); } //static, deprecated -#ifndef KPARTS_NO_DEPRECATED +#if KPARTS_BUILD_DEPRECATED_SINCE(5, 0) BrowserRun::AskSaveResult BrowserRun::askSave(const QUrl &url, KService::Ptr offer, const QString &mimeType, const QString &suggestedFileName) { Q_UNUSED(offer); BrowserOpenOrSaveQuestion question(nullptr, url, mimeType); question.setSuggestedFileName(suggestedFileName); const BrowserOpenOrSaveQuestion::Result result = question.askOpenOrSave(); return result == BrowserOpenOrSaveQuestion::Save ? Save : BrowserOpenOrSaveQuestion::Open ? Open : Cancel; } #endif //static, deprecated -#ifndef KPARTS_NO_DEPRECATED +#if KPARTS_BUILD_DEPRECATED_SINCE(5, 0) BrowserRun::AskSaveResult BrowserRun::askEmbedOrSave(const QUrl &url, const QString &mimeType, const QString &suggestedFileName, int flags) { BrowserOpenOrSaveQuestion question(nullptr, url, mimeType); question.setSuggestedFileName(suggestedFileName); const BrowserOpenOrSaveQuestion::Result result = question.askEmbedOrSave(flags); return result == BrowserOpenOrSaveQuestion::Save ? Save : result == BrowserOpenOrSaveQuestion::Embed ? Open : Cancel; } #endif // Default implementation, overridden in KHTMLRun void BrowserRun::save(const QUrl &url, const QString &suggestedFileName) { saveUrl(url, suggestedFileName, d->m_window, d->m_args); } // static void BrowserRun::simpleSave(const QUrl &url, const QString &suggestedFileName, QWidget *window) { saveUrl(url, suggestedFileName, window, KParts::OpenUrlArguments()); } void KParts::BrowserRun::saveUrl(const QUrl &url, const QString &suggestedFileName, QWidget *window, const KParts::OpenUrlArguments &args) { // DownloadManager <-> konqueror integration // find if the integration is enabled // the empty key means no integration // only use the downloadmanager for non-local urls if (!url.isLocalFile()) { KConfigGroup cfg = KSharedConfig::openConfig(QStringLiteral("konquerorrc"), KConfig::NoGlobals)->group("HTML Settings"); QString downloadManger = cfg.readPathEntry("DownloadManager", QString()); if (!downloadManger.isEmpty()) { // then find the download manager location // qDebug() << "Using: "<setAcceptMode(QFileDialog::AcceptSave); dlg->setWindowTitle(i18n("Save As")); dlg->setOption(QFileDialog::DontConfirmOverwrite, false); QString name; if (!suggestedFileName.isEmpty()) { name = suggestedFileName; } else { name = url.fileName(); // can be empty, e.g. in case http://www.kde.org/ } dlg->selectFile(name); if (dlg->exec()) { QUrl destURL(dlg->selectedUrls().at(0)); if (destURL.isValid()) { saveUrlUsingKIO(url, destURL, window, args.metaData()); } } delete dlg; } void BrowserRun::saveUrlUsingKIO(const QUrl &srcUrl, const QUrl &destUrl, QWidget *window, const QMap &metaData) { KIO::FileCopyJob *job = KIO::file_copy(srcUrl, destUrl, -1, KIO::Overwrite); const QString modificationTime = metaData[QStringLiteral("content-disposition-modification-date")]; if (!modificationTime.isEmpty()) { job->setModificationTime(QDateTime::fromString(modificationTime, Qt::RFC2822Date)); } job->setMetaData(metaData); job->addMetaData(QStringLiteral("MaxCacheSize"), QStringLiteral("0")); // Don't store in http cache. job->addMetaData(QStringLiteral("cache"), QStringLiteral("cache")); // Use entry from cache if available. KJobWidgets::setWindow(job, window); job->uiDelegate()->setAutoErrorHandlingEnabled(true); new DownloadJobWatcher(job, metaData); } void BrowserRun::handleError(KJob *job) { if (!job) { // Shouldn't happen qWarning() << "handleError called with job=0! hideErrorDialog=" << d->m_bHideErrorDialog; return; } KIO::TransferJob *tjob = qobject_cast(job); if (tjob && tjob->isErrorPage() && !job->error()) { // The default handling of error pages is to show them like normal pages // But this is done here in handleError so that KHTMLRun can reimplement it tjob->putOnHold(); setJob(nullptr); if (!d->m_mimeType.isEmpty()) { mimeTypeDetermined(d->m_mimeType); } return; } if (d->m_bHideErrorDialog && job->error() != KIO::ERR_NO_CONTENT) { redirectToError(job->error(), job->errorText()); return; } // Reuse code in KRun, to benefit from d->m_showingError etc. KRun::handleError(job); } // static QUrl BrowserRun::makeErrorUrl(int error, const QString &errorText, const QUrl &initialUrl) { /* * The format of the error:/ URL is error:/?query#url, * where two variables are passed in the query: * error = int kio error code, errText = QString error text from kio * The sub-url is the URL that we were trying to open. */ QUrl newURL(QStringLiteral("error:/?error=%1&errText=%2") .arg(error) .arg(QString::fromUtf8(QUrl::toPercentEncoding(errorText)))); QString cleanedOrigUrl = initialUrl.toString(); QUrl runURL(cleanedOrigUrl); if (runURL.isValid()) { runURL.setPassword(QString()); // don't put the password in the error URL cleanedOrigUrl = runURL.toString(); } newURL.setFragment(cleanedOrigUrl); return newURL; } void BrowserRun::redirectToError(int error, const QString &errorText) { /** * To display this error in KHTMLPart instead of inside a dialog box, * we tell konq that the mimetype is text/html, and we redirect to * an error:/ URL that sends the info to khtml. */ KRun::setUrl(makeErrorUrl(error, errorText, url())); setJob(nullptr); mimeTypeDetermined(QStringLiteral("text/html")); } void BrowserRun::slotCopyToTempFileResult(KJob *job) { if (job->error()) { job->uiDelegate()->showErrorMessage(); } else { // Same as KRun::foundMimeType but with a different URL (void)(KRun::runUrl(static_cast(job)->destUrl(), d->m_mimeType, d->m_window, KRun::RunFlags(KRun::RunExecutables))); } setError(true); // see above setFinished(true); } bool BrowserRun::isTextExecutable(const QString &mimeType) { return (mimeType == QLatin1String("application/x-desktop") || mimeType == QLatin1String("application/x-shellscript")); } bool BrowserRun::hideErrorDialog() const { return d->m_bHideErrorDialog; } QString BrowserRun::contentDisposition() const { return d->m_contentDisposition; } bool BrowserRun::serverSuggestsSave() const { // RfC 2183, section 2.8: // Unrecognized disposition types should be treated as `attachment'. return !contentDisposition().isEmpty() && (contentDisposition() != QLatin1String("inline")); } KParts::OpenUrlArguments &KParts::BrowserRun::arguments() { return d->m_args; } KParts::BrowserArguments &KParts::BrowserRun::browserArguments() { return d->m_browserArgs; } #include "moc_browserrun.cpp" #include "moc_browserrun_p.cpp" diff --git a/src/browserrun.h b/src/browserrun.h index a557e05..4dd229b 100644 --- a/src/browserrun.h +++ b/src/browserrun.h @@ -1,215 +1,218 @@ /* This file is part of the KDE project * * Copyright (C) 2002 David Faure * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License version 2, as published by the Free Software Foundation. * * This library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef kparts_browserrun_h #define kparts_browserrun_h #include #include #include namespace KParts { /** * This class extends KRun to provide additional functionality for browsers: * - "save or open" dialog boxes * - "save" functionality * - support for HTTP POST (including saving the result to a temp file if * opening a separate application) * - warning before launching executables off the web * - custom error handling (i.e. treating errors as HTML pages) * - generation of SSL metadata depending on the previous URL shown by the part * @author David Faure */ class KPARTS_EXPORT BrowserRun : public KRun { Q_OBJECT public: /** * @param url the URL we're probing * @param args URL args - includes reload, metaData, etc. * @param browserArgs browser-related args - includes data for a HTTP POST, etc. * @param part the part going to open this URL - can be @c nullptr if not created yet * @param window the mainwindow - passed to KIO::Job::setWindow() * @param removeReferrer if true, the "referrer" metadata from @p args isn't passed on * @param trustedSource if false, a warning will be shown before launching an executable. Always pass false for @p trustedSource, except for local directory views. * @param hideErrorDialog if true, no dialog will be shown in case of errors. */ BrowserRun(const QUrl &url, const KParts::OpenUrlArguments &args, const KParts::BrowserArguments &browserArgs, KParts::ReadOnlyPart *part, QWidget *window, bool removeReferrer, bool trustedSource, bool hideErrorDialog = false); virtual ~BrowserRun(); KParts::OpenUrlArguments &arguments(); KParts::BrowserArguments &browserArguments(); KParts::ReadOnlyPart *part() const; QUrl url() const; bool hideErrorDialog() const; /** * @return Suggested disposition by the server (e.g. HTTP content-disposition) */ QString contentDisposition() const; /** * @return Whether the returned disposition suggests saving or opening inline */ bool serverSuggestsSave() const; +#if KPARTS_ENABLE_DEPRECATED_SINCE(5, 0) enum AskSaveResult { Save, Open, Cancel }; /** * Ask the user whether to save or open a url in another application. * @param url the URL in question * @param offer the application that will be used to open the URL * @param mimeType the mimetype of the URL * @param suggestedFileName optional file name suggested by the server * @return Save, Open or Cancel. - * @deprecated use BrowserOpenOrSaveQuestion + * @deprecated Since 5.0, use BrowserOpenOrSaveQuestion * @code * BrowserOpenOrSaveQuestion dlg(parent, url, mimeType, suggestedFileName); * const BrowserOpenOrSaveQuestion::Result res = dlg.askOpenOrSave(); * @endcode */ -#ifndef KPARTS_NO_DEPRECATED - static KPARTS_DEPRECATED AskSaveResult askSave(const QUrl &url, KService::Ptr offer, const QString &mimeType, const QString &suggestedFileName = QString()); + KPARTS_DEPRECATED_VERSION(5, 0, "Use KParts::BrowserOpenOrSaveQuestion") + static AskSaveResult askSave(const QUrl &url, KService::Ptr offer, const QString &mimeType, const QString &suggestedFileName = QString()); #endif enum AskEmbedOrSaveFlags { InlineDisposition = 0, AttachmentDisposition = 1 }; + +#if KPARTS_ENABLE_DEPRECATED_SINCE(5, 0) /** * Similar to askSave but for the case where the current application is * able to embed the url itself (instead of passing it to another app). * @param url the URL in question * @param mimeType the mimetype of the URL * @param suggestedFileName optional filename suggested by the server * @param flags set to AttachmentDisposition if suggested by the server * @return Save, Open or Cancel. - * @deprecated use BrowserOpenOrSaveQuestion + * @deprecated Since 5.0, use BrowserOpenOrSaveQuestion * @code * BrowserOpenOrSaveQuestion dlg(parent, url, mimeType, suggestedFileName); * const BrowserOpenOrSaveQuestion::Result res = dlg.askEmbedOrSave(flags); * // Important: returns Embed now, not Open! * @endcode */ -#ifndef KPARTS_NO_DEPRECATED - static KPARTS_DEPRECATED AskSaveResult askEmbedOrSave(const QUrl &url, const QString &mimeType, const QString &suggestedFileName = QString(), int flags = 0); + KPARTS_DEPRECATED_VERSION(5, 0, "Use KParts::BrowserOpenOrSaveQuestion") + static AskSaveResult askEmbedOrSave(const QUrl &url, const QString &mimeType, const QString &suggestedFileName = QString(), int flags = 0); #endif // virtual so that KHTML can implement differently (HTML cache) virtual void save(const QUrl &url, const QString &suggestedFileName); // static so that it can be called from other classes static void simpleSave(const QUrl &url, const QString &suggestedFileName, QWidget *window = nullptr); // KDE5: remove /** * If kget integration is enabled, passes the url to kget. * Otherwise, asks the user for a destination url, and calls saveUrlUsingKIO. * @since 4.4 */ static void saveUrl(const QUrl &url, const QString &suggestedFileName, QWidget *window, const KParts::OpenUrlArguments &args); /** * Starts the KIO file copy job to download @p srcUrl into @p destUrl. * @since 4.4 */ static void saveUrlUsingKIO(const QUrl &srcUrl, const QUrl &destUrl, QWidget *window, const QMap &metaData); static bool allowExecution(const QString &mimeType, const QUrl &url); static bool isTextExecutable(const QString &mimeType); /** * KDE webbrowsing kparts support error urls to display errors in-line in the browser component. * This helper method creates the error URL from its parameters. * @param error the KIO error code (or KIO::ERR_SLAVE_DEFINED if not from KIO) * @param errorText the text of the error message * @param initialUrl the URL that we were trying to open (as a string, so that this can * support invalid URLs as well) (changed from QString to QUrl in KF5) * @since 4.6 */ static QUrl makeErrorUrl(int error, const QString &errorText, const QUrl &initialUrl); protected: /** * Reimplemented from KRun */ void scanFile() override; /** * Reimplemented from KRun */ void init() override; /** * Reimplemented from KRun */ void handleError(KJob *job) override; /** * NotHandled means that foundMimeType should call KRun::foundMimeType, * i.e. launch an external app. */ enum NonEmbeddableResult { Handled, NotHandled, Delayed }; /** * Helper for foundMimeType: call this if the mimetype couldn't be embedded */ NonEmbeddableResult handleNonEmbeddable(const QString &mimeType); // TODO KDE5: remove, and add =0 to the other overload /** * Helper for foundMimeType: call this if the mimetype couldn't be embedded * @param mimeType the mimetype found for the URL * @param pSelectedService Output variable: pointer to a KService::Ptr, which will be set * to the service selected in the BrowserOpenOrSaveQuestion dialog, if any. * * How to handle this properly: if pSelectedService is non-zero, then the dialog will show * additional "open with" buttons. In your code, you should write: * @code if (selectedService) { KRun::setPreferredService(selectedService->desktopEntryName()); // not necessary since 4.9.3 KRun::foundMimeType(mimeType); } else { // the user requested an open-with dialog KRun::displayOpenWithDialog(url(), m_window, false, suggestedFileName()); setFinished(true); } * @endcode * * @since 4.5 */ NonEmbeddableResult handleNonEmbeddable(const QString &mimeType, KService::Ptr *pSelectedService); protected Q_SLOTS: void slotBrowserScanFinished(KJob *job); void slotBrowserMimetype(KIO::Job *job, const QString &type); void slotCopyToTempFileResult(KJob *job); private: void redirectToError(int error, const QString &errorText); class BrowserRunPrivate; BrowserRunPrivate *const d; }; } #endif diff --git a/src/readonlypart.cpp b/src/readonlypart.cpp index 22cfce5..109ce57 100644 --- a/src/readonlypart.cpp +++ b/src/readonlypart.cpp @@ -1,368 +1,368 @@ /* This file is part of the KDE project Copyright (C) 1999 Simon Hausmann (C) 1999-2005 David Faure This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "readonlypart.h" #include "readonlypart_p.h" #include "browserextension.h" #include "guiactivateevent.h" #include #include #include #include #include #include #include #include using namespace KParts; ReadOnlyPart::ReadOnlyPart(QObject *parent) : Part(*new ReadOnlyPartPrivate(this), parent) { } ReadOnlyPart::ReadOnlyPart(ReadOnlyPartPrivate &dd, QObject *parent) : Part(dd, parent) { } ReadOnlyPart::~ReadOnlyPart() { ReadOnlyPart::closeUrl(); } QUrl ReadOnlyPart::url() const { Q_D(const ReadOnlyPart); return d->m_url; } void ReadOnlyPart::setUrl(const QUrl &url) { Q_D(ReadOnlyPart); if (d->m_url != url) { d->m_url = url; emit urlChanged(url); } } QString ReadOnlyPart::localFilePath() const { Q_D(const ReadOnlyPart); return d->m_file; } void ReadOnlyPart::setLocalFilePath(const QString &localFilePath) { Q_D(ReadOnlyPart); d->m_file = localFilePath; } -#ifndef KPARTS_NO_DEPRECATED +#if KPARTS_BUILD_DEPRECATED_SINCE(5, 0) bool ReadOnlyPart::isLocalFileTemporary() const { Q_D(const ReadOnlyPart); return d->m_bTemp; } #endif -#ifndef KPARTS_NO_DEPRECATED +#if KPARTS_BUILD_DEPRECATED_SINCE(5, 0) void ReadOnlyPart::setLocalFileTemporary(bool temp) { Q_D(ReadOnlyPart); d->m_bTemp = temp; } #endif void ReadOnlyPart::setProgressInfoEnabled(bool show) { Q_D(ReadOnlyPart); d->m_showProgressInfo = show; } bool ReadOnlyPart::isProgressInfoEnabled() const { Q_D(const ReadOnlyPart); return d->m_showProgressInfo; } #ifndef KDE_NO_COMPAT void ReadOnlyPart::showProgressInfo(bool show) { Q_D(ReadOnlyPart); d->m_showProgressInfo = show; } #endif bool ReadOnlyPart::openUrl(const QUrl &url) { Q_D(ReadOnlyPart); if (!url.isValid()) { return false; } if (d->m_bAutoDetectedMime) { d->m_arguments.setMimeType(QString()); d->m_bAutoDetectedMime = false; } OpenUrlArguments args = d->m_arguments; d->m_closeUrlFromOpenUrl = true; const bool closed = closeUrl(); d->m_closeUrlFromOpenUrl = false; if (!closed) { return false; } d->m_arguments = args; setUrl(url); d->m_file.clear(); if (d->m_url.isLocalFile()) { d->m_file = d->m_url.toLocalFile(); return d->openLocalFile(); } else if (KProtocolInfo::protocolClass(url.scheme()) == QLatin1String(":local")) { // Maybe we can use a "local path", to avoid a temp copy? KIO::JobFlags flags = d->m_showProgressInfo ? KIO::DefaultFlags : KIO::HideProgressInfo; d->m_statJob = KIO::mostLocalUrl(d->m_url, flags); KJobWidgets::setWindow(d->m_statJob, widget()); connect(d->m_statJob, SIGNAL(result(KJob*)), this, SLOT(_k_slotStatJobFinished(KJob*))); return true; } else { d->openRemoteFile(); return true; } } bool ReadOnlyPart::openFile() { qWarning() << "Default implementation of ReadOnlyPart::openFile called!" << metaObject()->className() << "should reimplement either openUrl or openFile."; return false; } bool ReadOnlyPartPrivate::openLocalFile() { Q_Q(ReadOnlyPart); emit q->started(nullptr); m_bTemp = false; // set the mimetype only if it was not already set (for example, by the host application) if (m_arguments.mimeType().isEmpty()) { // get the mimetype of the file // using findByUrl() to avoid another string -> url conversion QMimeDatabase db; QMimeType mime = db.mimeTypeForUrl(m_url); if (!mime.isDefault()) { m_arguments.setMimeType(mime.name()); m_bAutoDetectedMime = true; } } const bool ret = q->openFile(); if (ret) { emit q->setWindowCaption(m_url.toDisplayString()); emit q->completed(); } else { emit q->canceled(QString()); } return ret; } void ReadOnlyPartPrivate::openRemoteFile() { Q_Q(ReadOnlyPart); m_bTemp = true; // Use same extension as remote file. This is important for mimetype-determination (e.g. koffice) QString fileName = m_url.fileName(); QFileInfo fileInfo(fileName); QString ext = fileInfo.completeSuffix(); QString extension; if (!ext.isEmpty() && !m_url.hasQuery()) { // not if the URL has a query, e.g. cgi.pl?something extension = QLatin1Char('.') + ext; // keep the '.' } QTemporaryFile tempFile(QDir::tempPath() + QLatin1Char('/') + q->componentData().componentName() + QLatin1String("XXXXXX") + extension); tempFile.setAutoRemove(false); tempFile.open(); m_file = tempFile.fileName(); QUrl destURL = QUrl::fromLocalFile(m_file); KIO::JobFlags flags = m_showProgressInfo ? KIO::DefaultFlags : KIO::HideProgressInfo; flags |= KIO::Overwrite; m_job = KIO::file_copy(m_url, destURL, 0600, flags); KJobWidgets::setWindow(m_job, q->widget()); emit q->started(m_job); QObject::connect(m_job, SIGNAL(result(KJob*)), q, SLOT(_k_slotJobFinished(KJob*))); QObject::connect(m_job, SIGNAL(mimetype(KIO::Job*,QString)), q, SLOT(_k_slotGotMimeType(KIO::Job*,QString))); } void ReadOnlyPart::abortLoad() { Q_D(ReadOnlyPart); if (d->m_statJob) { //qDebug() << "Aborting job" << d->m_statJob; d->m_statJob->kill(); d->m_statJob = nullptr; } if (d->m_job) { //qDebug() << "Aborting job" << d->m_job; d->m_job->kill(); d->m_job = nullptr; } } bool ReadOnlyPart::closeUrl() { Q_D(ReadOnlyPart); abortLoad(); //just in case d->m_arguments = KParts::OpenUrlArguments(); if (!d->m_closeUrlFromOpenUrl) { setUrl(QUrl()); } if (d->m_bTemp) { QFile::remove(d->m_file); d->m_bTemp = false; } // It always succeeds for a read-only part, // but the return value exists for reimplementations // (e.g. pressing cancel for a modified read-write part) return true; } void ReadOnlyPartPrivate::_k_slotStatJobFinished(KJob *job) { Q_ASSERT(job == m_statJob); m_statJob = nullptr; // We could emit canceled on error, but we haven't even emitted started yet, // this could maybe confuse some apps? So for now we'll just fallback to KIO::get // and error again. Well, maybe this even helps with wrong stat results. if (!job->error()) { const QUrl localUrl = static_cast(job)->mostLocalUrl(); if (localUrl.isLocalFile()) { m_file = localUrl.toLocalFile(); (void)openLocalFile(); return; } } openRemoteFile(); } void ReadOnlyPartPrivate::_k_slotJobFinished(KJob *job) { Q_Q(ReadOnlyPart); Q_ASSERT(job == m_job); m_job = nullptr; if (job->error()) { emit q->canceled(job->errorString()); } else { if (q->openFile()) { emit q->setWindowCaption(m_url.toDisplayString()); emit q->completed(); } else { emit q->canceled(QString()); } } } void ReadOnlyPartPrivate::_k_slotGotMimeType(KIO::Job *job, const QString &mime) { // qDebug() << mime; Q_ASSERT(job == m_job); Q_UNUSED(job) // set the mimetype only if it was not already set (for example, by the host application) if (m_arguments.mimeType().isEmpty()) { m_arguments.setMimeType(mime); m_bAutoDetectedMime = true; } } void ReadOnlyPart::guiActivateEvent(GUIActivateEvent *event) { Q_D(ReadOnlyPart); if (event->activated()) { if (!d->m_url.isEmpty()) { // qDebug() << d->m_url; emit setWindowCaption(d->m_url.toDisplayString()); } else { emit setWindowCaption(QString()); } } } bool ReadOnlyPart::openStream(const QString &mimeType, const QUrl &url) { Q_D(ReadOnlyPart); OpenUrlArguments args = d->m_arguments; if (!closeUrl()) { return false; } d->m_arguments = args; setUrl(url); return doOpenStream(mimeType); } bool ReadOnlyPart::writeStream(const QByteArray &data) { return doWriteStream(data); } bool ReadOnlyPart::closeStream() { return doCloseStream(); } BrowserExtension *ReadOnlyPart::browserExtension() const { return findChild(); } void KParts::ReadOnlyPart::setArguments(const OpenUrlArguments &arguments) { Q_D(ReadOnlyPart); d->m_arguments = arguments; d->m_bAutoDetectedMime = arguments.mimeType().isEmpty(); } OpenUrlArguments KParts::ReadOnlyPart::arguments() const { Q_D(const ReadOnlyPart); return d->m_arguments; } #include "moc_readonlypart.cpp" diff --git a/src/readonlypart.h b/src/readonlypart.h index e2c51cf..5cc20db 100644 --- a/src/readonlypart.h +++ b/src/readonlypart.h @@ -1,327 +1,327 @@ /* This file is part of the KDE project Copyright (C) 1999 Simon Hausmann (C) 1999 David Faure This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _KPARTS_READONLYPART_H #define _KPARTS_READONLYPART_H #include #include class KJob; namespace KIO { class Job; } namespace KParts { class ReadOnlyPartPrivate; class BrowserExtension; class OpenUrlArguments; /** * Base class for any "viewer" part. * * This class takes care of network transparency for you, * in the simplest way (downloading to a temporary file, then letting the part * load from the temporary file). * To use the built-in network transparency, you only need to implement * openFile(), not openUrl(). * * To implement network transparency differently (e.g. for progressive loading, * like a web browser does for instance), or to prevent network transparency * (but why would you do that?), you can override openUrl(). * * KParts Application can use the signals to show feedback while the URL is being loaded. * * ReadOnlyPart handles the window caption by setting it to the current URL * (set in openUrl(), and each time the part is activated). * If you want another caption, set it in openFile() and * (if the part might ever be used with a part manager) in guiActivateEvent() */ class KPARTS_EXPORT ReadOnlyPart : public Part { Q_OBJECT Q_PROPERTY(QUrl url READ url) KPARTS_DECLARE_PRIVATE(ReadOnlyPart) public: /** * Constructor * See also Part for the setXXX methods to call. */ explicit ReadOnlyPart(QObject *parent = nullptr); /** * Destructor */ ~ReadOnlyPart() override; /** * Call this to turn off the progress info dialog used by * the internal KIO job. Use this if you provide another way * of displaying progress info (e.g. a statusbar), using the * signals emitted by this class, and/or those emitted by * the Job given by started. */ void setProgressInfoEnabled(bool show); /** * Returns whether the part shows the progress info dialog used by internal * KIO job. */ bool isProgressInfoEnabled() const; #ifndef KDE_NO_COMPAT void showProgressInfo(bool show); #endif public Q_SLOTS: /** * Only reimplement openUrl if you don't want the network transparency support * to download from the url into a temporary file (when the url isn't local). * Otherwise, reimplement openFile() only . * * If you reimplement it, don't forget to set the caption, usually with * emit setWindowCaption( url.prettyUrl() ); */ virtual bool openUrl(const QUrl &url); public: /** * Returns the URL currently opened in (or being opened by) this part. * @note url() is not cleared if openUrl() fails to load the URL. * Call closeUrl() if you need to explicitly reset it. * * @return The current URL. */ QUrl url() const; /** * Called when closing the current url (e.g. document), for instance * when switching to another url (note that openUrl() calls it * automatically in this case). * If the current URL is not fully loaded yet, aborts loading. * Deletes the temporary file used when the url is remote. * Resets the current url() to QUrl(). * @return always true, but the return value exists for reimplementations */ virtual bool closeUrl(); /** * This convenience method returns the browserExtension for this part, * or @c nullptr if there isn't any. */ BrowserExtension *browserExtension() const; /** * Sets the arguments to use for the next openUrl call. */ void setArguments(const OpenUrlArguments &arguments); // TODO to avoid problems with the case where the loading fails, this could also be a openUrl() argument (heavy porting!). // However we need to have setArguments in any case for updated made by the part, see e.g. KHTMLPart::openUrl. // Well, maybe we should have setArguments (affects next openurl call) and updateArguments? /** * @return the arguments that were used to open this URL. */ OpenUrlArguments arguments() const; public: /** * Initiate sending data to this part. * This is an alternative to openUrl, which allows the user of the part * to load the data itself, and send it progressively to the part. * * @param mimeType the type of data that is going to be sent to this part. * @param url the URL representing this data. Although not directly used, * every ReadOnlyPart has a URL (see url()), so this simply sets it. * @return true if the part supports progressive loading and accepts data, false otherwise. */ bool openStream(const QString &mimeType, const QUrl &url); /** * Send some data to the part. openStream must have been called previously, * and must have returned true. * @return true if the data was accepted by the part. If false is returned, * the application should stop sending data, and doesn't have to call closeStream. */ bool writeStream(const QByteArray &data); /** * Terminate the sending of data to the part. * With some data types (text, html...) closeStream might never actually be called, * in the case of continuous streams, for instance plain text or HTML data. */ bool closeStream(); #ifdef DOXYGEN_SHOULD_SKIP_THIS protected: // are parsed by doxygen (kapidox/ecm_add_qch): unhide for doxygen configured to skip private methods #else private: // Makes no sense for inherited classes to call those. But make it protected there. #endif // DOXYGEN_SHOULD_SKIP_THIS /** * Called by openStream to initiate sending of data. * Parts which implement progress loading should check the @p mimeType * parameter, and return true if they can accept a data stream of that type. */ virtual bool doOpenStream(const QString &mimeType) { Q_UNUSED(mimeType); return false; } /** * Receive some data from the hosting application. * In this method the part should attempt to display the data progressively. * With some data types (text, html...) closeStream might never actually be called, * in the case of continuous streams. This can't happen with e.g. images. */ virtual bool doWriteStream(const QByteArray &data) { Q_UNUSED(data); return false; } /** * This is called by closeStream(), to indicate that all the data has been sent. * Parts should ensure that all of the data is displayed at this point. * @return whether the data could be displayed correctly. */ virtual bool doCloseStream() { return false; } Q_SIGNALS: /** * The part emits this when starting data. * If using a KIO::Job, it sets the job in the signal, so that * progress information can be shown. Otherwise, job is @c nullptr. **/ void started(KIO::Job *); /** * Emit this when you have completed loading data. * Hosting apps will want to know when the process of loading the data * is finished, so that they can access the data when everything is loaded. **/ void completed(); /** * Same as the above signal except it indicates whether there is * a pending action to be executed on a delay timer. An example of * this is the meta-refresh tags on web pages used to reload/redirect * after a certain period of time. This signal is useful if you want * to give the user the ability to cancel such pending actions. * * @p pendingAction true if a pending action exists, false otherwise. */ void completed(bool pendingAction); /** * Emit this if loading is canceled by the user or by an error. * @param errMsg the error message, empty if the user canceled the loading voluntarily. */ void canceled(const QString &errMsg); /** * Emitted by the part when url() changes * @since 4.10 */ void urlChanged(const QUrl &url); protected: /** * If the part uses the standard implementation of openUrl(), * it must reimplement this, to open the local file. * The default implementation is simply { return false; } * * If this method returns true, the part emits completed(), * otherwise it emits canceled(). * * @see completed(), canceled() */ virtual bool openFile(); /** * @internal */ void abortLoad(); /** * Reimplemented from Part, so that the window caption is set to * the current url (decoded) when the part is activated * This is the usual behavior in 99% of the apps * Reimplement if you don't like it - test for event->activated() ! * * Technical note : this is done with GUIActivateEvent and not with * PartActivateEvent because it's handled by the mainwindow * (which gets the even after the PartActivateEvent events have been sent) */ void guiActivateEvent(GUIActivateEvent *event) override; +#if KPARTS_ENABLE_DEPRECATED_SINCE(5, 0) /** * @internal */ -#ifndef KPARTS_NO_DEPRECATED - KPARTS_DEPRECATED bool isLocalFileTemporary() const; -#endif + KPARTS_DEPRECATED_VERSION(5, 0, "Do not use feature") + bool isLocalFileTemporary() const; /** * @internal */ -#ifndef KPARTS_NO_DEPRECATED - KPARTS_DEPRECATED void setLocalFileTemporary(bool temp); + KPARTS_DEPRECATED_VERSION(5, 0, "Do not use feature") + void setLocalFileTemporary(bool temp); #endif /** * Sets the url associated with this part. */ void setUrl(const QUrl &url); /** * Returns the local file path associated with this part. */ QString localFilePath() const; /** * Sets the local file path associated with this part. */ void setLocalFilePath(const QString &localFilePath); protected: ReadOnlyPart(ReadOnlyPartPrivate &dd, QObject *parent); private: Q_PRIVATE_SLOT(d_func(), void _k_slotJobFinished(KJob *job)) Q_PRIVATE_SLOT(d_func(), void _k_slotStatJobFinished(KJob *)) Q_PRIVATE_SLOT(d_func(), void _k_slotGotMimeType(KIO::Job *job, const QString &mime)) Q_DISABLE_COPY(ReadOnlyPart) }; } // namespace #endif