KParts

readonlypart.cpp
1 /*
2  This file is part of the KDE project
3  SPDX-FileCopyrightText: 1999 Simon Hausmann <hausmann@kde.org>
4  SPDX-FileCopyrightText: 1999-2005 David Faure <faure@kde.org>
5 
6  SPDX-License-Identifier: LGPL-2.0-or-later
7 */
8 
9 #include "readonlypart.h"
10 #include "readonlypart_p.h"
11 
12 #include "kparts_logging.h"
13 
14 #include "guiactivateevent.h"
15 #include "navigationextension.h"
16 
17 #include <KIO/FileCopyJob>
18 #include <KIO/StatJob>
19 #include <KJobWidgets>
20 #include <KProtocolInfo>
21 
22 #include <QDir>
23 #include <QFileInfo>
24 #include <QMimeDatabase>
25 #include <QTemporaryFile>
26 
27 using namespace KParts;
28 
30  : Part(*new ReadOnlyPartPrivate(this, data), parent)
31 {
32 }
33 
34 ReadOnlyPart::ReadOnlyPart(ReadOnlyPartPrivate &dd, QObject *parent)
35  : Part(dd, parent)
36 {
37 }
38 
40 {
42  d->m_closeUrlFromDestructor = true;
44 }
45 
46 QUrl ReadOnlyPart::url() const
47 {
48  Q_D(const ReadOnlyPart);
49 
50  return d->m_url;
51 }
52 
53 void ReadOnlyPart::setUrl(const QUrl &url)
54 {
56 
57  if (d->m_url != url) {
58  d->m_url = url;
59  if (!d->m_closeUrlFromDestructor) {
60  Q_EMIT urlChanged(url);
61  }
62  }
63 }
64 
66 {
67  Q_D(const ReadOnlyPart);
68 
69  return d->m_file;
70 }
71 
72 void ReadOnlyPart::setLocalFilePath(const QString &localFilePath)
73 {
75 
76  d->m_file = localFilePath;
77 }
78 
80 {
82 
83  d->m_showProgressInfo = show;
84 }
85 
87 {
88  Q_D(const ReadOnlyPart);
89 
90  return d->m_showProgressInfo;
91 }
92 
93 bool ReadOnlyPart::openUrl(const QUrl &url)
94 {
96 
97  if (!url.isValid()) {
98  return false;
99  }
100  if (d->m_bAutoDetectedMime) {
101  d->m_arguments.setMimeType(QString());
102  d->m_bAutoDetectedMime = false;
103  }
104  OpenUrlArguments args = d->m_arguments;
105  d->m_closeUrlFromOpenUrl = true;
106  const bool closed = closeUrl();
107  d->m_closeUrlFromOpenUrl = false;
108  if (!closed) {
109  return false;
110  }
111  d->m_arguments = args;
112  setUrl(url);
113 
114  d->m_file.clear();
115 
116  if (d->m_url.isLocalFile()) {
117  d->m_file = d->m_url.toLocalFile();
118  return d->openLocalFile();
119  } else if (KProtocolInfo::protocolClass(url.scheme()) == QLatin1String(":local")) {
120  // Maybe we can use a "local path", to avoid a temp copy?
121  KIO::JobFlags flags = d->m_showProgressInfo ? KIO::DefaultFlags : KIO::HideProgressInfo;
122  d->m_statJob = KIO::mostLocalUrl(d->m_url, flags);
123  KJobWidgets::setWindow(d->m_statJob, widget());
124  connect(d->m_statJob, &KJob::result, this, [d](KJob *job) {
125  d->slotStatJobFinished(job);
126  });
127  return true;
128  } else {
129  d->openRemoteFile();
130  return true;
131  }
132 }
133 
135 {
136  qCWarning(KPARTSLOG) << "Default implementation of ReadOnlyPart::openFile called!" << metaObject()->className()
137  << "should reimplement either openUrl or openFile.";
138  return false;
139 }
140 
141 bool ReadOnlyPartPrivate::openLocalFile()
142 {
143  Q_Q(ReadOnlyPart);
144  Q_EMIT q->started(nullptr);
145  m_bTemp = false;
146  // set the mimetype only if it was not already set (for example, by the host application)
147  if (m_arguments.mimeType().isEmpty()) {
148  // get the mimetype of the file
149  // using findByUrl() to avoid another string -> url conversion
150  QMimeDatabase db;
151  QMimeType mime = db.mimeTypeForUrl(m_url);
152  if (!mime.isDefault()) {
153  m_arguments.setMimeType(mime.name());
154  m_bAutoDetectedMime = true;
155  }
156  }
157  const bool ret = q->openFile();
158  if (ret) {
159  Q_EMIT q->setWindowCaption(m_url.toDisplayString());
160  Q_EMIT q->completed();
161  } else {
162  Q_EMIT q->canceled(QString());
163  }
164  return ret;
165 }
166 
167 void ReadOnlyPartPrivate::openRemoteFile()
168 {
169  Q_Q(ReadOnlyPart);
170  m_bTemp = true;
171  // Use same extension as remote file. This is important for mimetype-determination (e.g. koffice)
172  QString fileName = m_url.fileName();
173  QFileInfo fileInfo(fileName);
174  QString ext = fileInfo.completeSuffix();
175  QString extension;
176  if (!ext.isEmpty() && !m_url.hasQuery()) { // not if the URL has a query, e.g. cgi.pl?something
177  extension = QLatin1Char('.') + ext; // keep the '.'
178  }
179  QTemporaryFile tempFile(QDir::tempPath() + QLatin1Char('/') + m_metaData.pluginId() + QLatin1String("XXXXXX") + extension);
180  tempFile.setAutoRemove(false);
181  tempFile.open();
182  m_file = tempFile.fileName();
183 
184  QUrl destURL = QUrl::fromLocalFile(m_file);
185  KIO::JobFlags flags = m_showProgressInfo ? KIO::DefaultFlags : KIO::HideProgressInfo;
186  flags |= KIO::Overwrite;
187  m_job = KIO::file_copy(m_url, destURL, 0600, flags);
188  m_job->setFinishedNotificationHidden(true);
189  KJobWidgets::setWindow(m_job, q->widget());
190  Q_EMIT q->started(m_job);
191 
192  QObject::connect(m_job, &KJob::result, q, [this](KJob *job) {
193  slotJobFinished(job);
194  });
195  QObject::connect(m_job, &KIO::FileCopyJob::mimeTypeFound, q, [this](KIO::Job *job, const QString &mimeType) {
196  slotGotMimeType(job, mimeType);
197  });
198 }
199 
201 {
202  Q_D(ReadOnlyPart);
203 
204  if (d->m_statJob) {
205  // qDebug() << "Aborting job" << d->m_statJob;
206  d->m_statJob->kill();
207  d->m_statJob = nullptr;
208  }
209  if (d->m_job) {
210  // qDebug() << "Aborting job" << d->m_job;
211  d->m_job->kill();
212  d->m_job = nullptr;
213  }
214 }
215 
217 {
218  Q_D(ReadOnlyPart);
219 
220  abortLoad(); // just in case
221 
222  d->m_arguments = KParts::OpenUrlArguments();
223  if (!d->m_closeUrlFromOpenUrl) {
224  setUrl(QUrl());
225  }
226 
227  if (d->m_bTemp) {
228  QFile::remove(d->m_file);
229  d->m_bTemp = false;
230  }
231  // It always succeeds for a read-only part,
232  // but the return value exists for reimplementations
233  // (e.g. pressing cancel for a modified read-write part)
234  return true;
235 }
236 
237 void ReadOnlyPartPrivate::slotStatJobFinished(KJob *job)
238 {
239  Q_ASSERT(job == m_statJob);
240  m_statJob = nullptr;
241 
242  // We could emit canceled on error, but we haven't even emitted started yet,
243  // this could maybe confuse some apps? So for now we'll just fallback to KIO::get
244  // and error again. Well, maybe this even helps with wrong stat results.
245  if (!job->error()) {
246  const QUrl localUrl = static_cast<KIO::StatJob *>(job)->mostLocalUrl();
247  if (localUrl.isLocalFile()) {
248  m_file = localUrl.toLocalFile();
249  (void)openLocalFile();
250  return;
251  }
252  }
253  openRemoteFile();
254 }
255 
256 void ReadOnlyPartPrivate::slotJobFinished(KJob *job)
257 {
258  Q_Q(ReadOnlyPart);
259 
260  Q_ASSERT(job == m_job);
261  m_job = nullptr;
262  if (job->error()) {
263  Q_EMIT q->canceled(job->errorString());
264  } else {
265  if (q->openFile()) {
266  Q_EMIT q->setWindowCaption(m_url.toDisplayString());
267  Q_EMIT q->completed();
268  } else {
269  Q_EMIT q->canceled(QString());
270  }
271  }
272 }
273 
274 void ReadOnlyPartPrivate::slotGotMimeType(KIO::Job *job, const QString &mime)
275 {
276  // qDebug() << mime;
277  Q_ASSERT(job == m_job);
278  Q_UNUSED(job)
279  // set the mimetype only if it was not already set (for example, by the host application)
280  if (m_arguments.mimeType().isEmpty()) {
281  m_arguments.setMimeType(mime);
282  m_bAutoDetectedMime = true;
283  }
284 }
285 
287 {
288  Q_D(ReadOnlyPart);
289 
290  if (event->activated()) {
291  if (!d->m_url.isEmpty()) {
292  // qDebug() << d->m_url;
293  Q_EMIT setWindowCaption(d->m_url.toDisplayString());
294  } else {
296  }
297  }
298 }
299 
300 bool ReadOnlyPart::openStream(const QString &mimeType, const QUrl &url)
301 {
302  Q_D(ReadOnlyPart);
303 
304  OpenUrlArguments args = d->m_arguments;
305  if (!closeUrl()) {
306  return false;
307  }
308  d->m_arguments = args;
309  setUrl(url);
310  return doOpenStream(mimeType);
311 }
312 
314 {
315  return doWriteStream(data);
316 }
317 
319 {
320  return doCloseStream();
321 }
322 
324 {
325  return findChild<KParts::NavigationExtension *>();
326 }
327 
329 {
330  Q_D(ReadOnlyPart);
331  d->m_arguments = arguments;
332  d->m_bAutoDetectedMime = arguments.mimeType().isEmpty();
333 }
334 
336 {
337  Q_D(const ReadOnlyPart);
338  return d->m_arguments;
339 }
340 
341 #include "moc_readonlypart.cpp"
virtual bool doCloseStream()
This is called by closeStream(), to indicate that all the data has been sent.
Definition: readonlypart.h:201
virtual bool doOpenStream(const QString &mimeType)
Called by openStream to initiate sending of data.
Definition: readonlypart.h:180
ReadOnlyPart(QObject *parent=nullptr, const KPluginMetaData &data={})
Constructor.
QMimeType mimeTypeForUrl(const QUrl &url) const const
bool remove()
Q_EMITQ_EMIT
virtual bool closeUrl()
Called when closing the current URL (for example, a document), for instance when switching to another...
void result(KJob *job)
QString scheme() const const
NavigationExtension * navigationExtension() const
This convenience method returns the NavigationExtension for this part, or nullptr if there isn't one.
QString mimeType() const
The mimetype to use when opening the url, when known by the calling application.
This event is sent to a Part when its GUI has been activated or deactivated. This is related to PartA...
bool closeStream()
Terminate the sending of data to the part.
void setArguments(const OpenUrlArguments &arguments)
Sets the arguments to use for the next openUrl() call.
void setProgressInfoEnabled(bool show)
Call this to turn off the progress info dialog used by the internal KIO job.
DefaultFlags
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
~ReadOnlyPart() override
Destructor.
QString tempPath()
void setUrl(const QUrl &url)
Sets the URL associated with this part.
bool isValid() const const
bool isProgressInfoEnabled() const
Returns whether the part shows the progress info dialog used by the internal KIO job.
OpenUrlArguments arguments() const
virtual bool event(QEvent *e)
void guiActivateEvent(GUIActivateEvent *event) override
Reimplemented from Part, so that the window caption is set to the current URL (decoded) when the part...
void setLocalFilePath(const QString &localFilePath)
Sets the local file path associated with this part.
bool isEmpty() const const
QUrl fromLocalFile(const QString &localFile)
QString toLocalFile() const const
virtual bool openFile()
If the part uses the standard implementation of openUrl(), it must reimplement this to open the local...
virtual bool openUrl(const QUrl &url)
Only reimplement this if you don't want the network transparency support to download from the URL int...
virtual bool doWriteStream(const QByteArray &data)
Receive some data from the hosting application.
Definition: readonlypart.h:191
virtual const QMetaObject * metaObject() const const
void urlChanged(const QUrl &url)
Emitted by the part when url() changes.
const char * className() const const
FileCopyJob * file_copy(const QUrl &src, const QUrl &dest, JobFlags flags)=delete
bool openStream(const QString &mimeType, const QUrl &url)
Initiate sending data to this part.
Base class for parts.
Definition: part.h:56
QString localFilePath() const
Returns the local file path associated with this part.
bool isLocalFile() const const
void mimeTypeFound(KIO::Job *job, const QString &mimeType)
HideProgressInfo
void setWindow(QObject *job, QWidget *widget)
virtual QString errorString() const
Base class for any "viewer" part.
Definition: readonlypart.h:51
int error() const
virtual QWidget * widget()
Definition: part.cpp:61
OpenUrlArguments is the set of arguments that specify how a URL should be opened by KParts::ReadOnlyP...
bool writeStream(const QByteArray &data)
Send some data to the part.
The KParts namespace,.
void setWindowCaption(const QString &caption)
Emitted by the part, to set the caption of the window(s) hosting this part.
Q_D(Todo)
static QString protocolClass(const QString &protocol)
An extension to KParts::ReadOnlyPart, which allows a better integration of parts with browsers (in pa...
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Thu Feb 15 2024 03:48:58 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.