diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 644fa2c..475edf2 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,152 +1,152 @@ 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}) 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 VERSION ${KF5_VERSION} DEPRECATED_BASE_VERSION 0 - DEPRECATION_VERSIONS 5.0 + DEPRECATION_VERSIONS 3.0 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 "KPARTS_DEPRECATED_VERSION(x, y, t)" 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/readonlypart.cpp b/src/readonlypart.cpp index 109ce57..63ee003 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; } #if KPARTS_BUILD_DEPRECATED_SINCE(5, 0) bool ReadOnlyPart::isLocalFileTemporary() const { Q_D(const ReadOnlyPart); return d->m_bTemp; } #endif #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 +#if KPARTS_BUILD_DEPRECATED_SINCE(3, 0) 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 5cc20db..da80e3f 100644 --- a/src/readonlypart.h +++ b/src/readonlypart.h @@ -1,327 +1,331 @@ /* 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 +#if KPARTS_ENABLE_DEPRECATED_SINCE(3, 0) + /** + * @deprecated Since 3.0, use setProgressInfoEnabled(bool) + */ + KPARTS_DEPRECATED_VERSION(3, 0, "Use ReadOnlyPart::setProgressInfoEnabled(bool)") 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 */ KPARTS_DEPRECATED_VERSION(5, 0, "Do not use feature") bool isLocalFileTemporary() const; /** * @internal */ 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