mirror of
https://bitbucket.org/smil3y/kdelibs.git
synced 2025-02-23 18:32:49 +00:00

unfortunate as it is the class for getting protocol information is not part of kio library so generic.. Signed-off-by: Ivailo Monev <xakepa10@gmail.com>
985 lines
23 KiB
C++
985 lines
23 KiB
C++
/* This file is part of the KDE project
|
|
Copyright (C) 1999 Simon Hausmann <hausmann@kde.org>
|
|
(C) 1999-2005 David Faure <faure@kde.org>
|
|
|
|
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 "part.h"
|
|
#include "event.h"
|
|
#include "mainwindow.h"
|
|
|
|
#include <QtGui/QApplication>
|
|
#include <QtCore/QFile>
|
|
#include <QtCore/QFileInfo>
|
|
#include <QtGui/QPainter>
|
|
#include <QtCore/QPoint>
|
|
|
|
#include <kprotocolinfo.h>
|
|
#include <kdirnotify.h>
|
|
#include <kfiledialog.h>
|
|
#include <kcomponentdata.h>
|
|
#include <kio/job.h>
|
|
#include <kio/jobuidelegate.h>
|
|
#include <klocale.h>
|
|
#include <kmessagebox.h>
|
|
#include <kstandarddirs.h>
|
|
#include <ktemporaryfile.h>
|
|
#include <kxmlguifactory.h>
|
|
|
|
#include <stdio.h>
|
|
#include <unistd.h>
|
|
#include <kdebug.h>
|
|
#include <kiconloader.h>
|
|
|
|
using namespace KParts;
|
|
|
|
namespace KParts
|
|
{
|
|
|
|
class PartBasePrivate
|
|
{
|
|
public:
|
|
Q_DECLARE_PUBLIC(PartBase)
|
|
|
|
PartBasePrivate(PartBase *q): q_ptr(q)
|
|
{
|
|
}
|
|
|
|
PartBase *q_ptr;
|
|
};
|
|
|
|
class PartPrivate: public PartBasePrivate
|
|
{
|
|
public:
|
|
Q_DECLARE_PUBLIC(Part)
|
|
|
|
PartPrivate(Part *q)
|
|
: PartBasePrivate(q),
|
|
m_iconLoader(nullptr),
|
|
m_bSelectable(true),
|
|
m_autoDeleteWidget(true),
|
|
m_autoDeletePart(true)
|
|
{
|
|
}
|
|
|
|
~PartPrivate()
|
|
{
|
|
}
|
|
|
|
KIconLoader* m_iconLoader;
|
|
bool m_bSelectable;
|
|
bool m_autoDeleteWidget;
|
|
bool m_autoDeletePart;
|
|
QPointer<QWidget> m_widget;
|
|
};
|
|
|
|
}
|
|
|
|
PartBase::PartBase()
|
|
: d_ptr(new PartBasePrivate(this))
|
|
{
|
|
}
|
|
|
|
PartBase::PartBase(PartBasePrivate &dd)
|
|
: d_ptr(&dd)
|
|
{
|
|
}
|
|
|
|
PartBase::~PartBase()
|
|
{
|
|
delete d_ptr;
|
|
}
|
|
|
|
void PartBase::setComponentData(const KComponentData &componentData)
|
|
{
|
|
KXMLGUIClient::setComponentData(componentData);
|
|
KGlobal::locale()->insertCatalog(componentData.catalogName());
|
|
// install 'instancename'data resource type
|
|
KGlobal::dirs()->addResourceType(QString(componentData.componentName() + "data").toUtf8(),
|
|
"data", componentData.componentName());
|
|
}
|
|
|
|
Part::Part( QObject *parent )
|
|
: QObject( parent ), PartBase( *new PartPrivate(this) )
|
|
{
|
|
}
|
|
|
|
Part::Part(PartPrivate &dd, QObject *parent)
|
|
: QObject( parent ), PartBase( dd )
|
|
{
|
|
}
|
|
|
|
Part::~Part()
|
|
{
|
|
Q_D(Part);
|
|
|
|
// kDebug() << this;
|
|
|
|
if ( d->m_widget )
|
|
{
|
|
// We need to disconnect first to avoid calling slotWidgetDestroyed() !
|
|
disconnect( d->m_widget, 0, this, 0 );
|
|
}
|
|
|
|
if ( d->m_widget && d->m_autoDeleteWidget )
|
|
{
|
|
kDebug() << "deleting widget" << d->m_widget << d->m_widget->objectName();
|
|
delete static_cast<QWidget*>(d->m_widget);
|
|
}
|
|
|
|
delete d->m_iconLoader;
|
|
}
|
|
|
|
void Part::embed( QWidget * parentWidget )
|
|
{
|
|
if ( widget() )
|
|
{
|
|
widget()->setParent( parentWidget, 0 );
|
|
widget()->setGeometry( 0, 0, widget()->width(), widget()->height() );
|
|
widget()->show();
|
|
}
|
|
}
|
|
|
|
QWidget *Part::widget()
|
|
{
|
|
Q_D(Part);
|
|
|
|
return d->m_widget;
|
|
}
|
|
|
|
void Part::setAutoDeleteWidget(bool autoDeleteWidget)
|
|
{
|
|
Q_D(Part);
|
|
d->m_autoDeleteWidget = autoDeleteWidget;
|
|
if (d->m_widget) {
|
|
if (autoDeleteWidget) {
|
|
connect(
|
|
d->m_widget, SIGNAL(destroyed()),
|
|
this, SLOT(slotWidgetDestroyed()),
|
|
Qt::UniqueConnection
|
|
);
|
|
} else {
|
|
disconnect(d->m_widget, 0, this, 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
void Part::setAutoDeletePart(bool autoDeletePart)
|
|
{
|
|
Q_D(Part);
|
|
d->m_autoDeletePart = autoDeletePart;
|
|
}
|
|
|
|
KIconLoader* Part::iconLoader()
|
|
{
|
|
Q_D(Part);
|
|
if (!d->m_iconLoader) {
|
|
Q_ASSERT(componentData().isValid());
|
|
d->m_iconLoader = new KIconLoader(componentData());
|
|
}
|
|
return d->m_iconLoader;
|
|
}
|
|
|
|
Part* Part::hitTest(QWidget *widget, const QPoint &)
|
|
{
|
|
Q_D(Part);
|
|
if ((QWidget *)d->m_widget != widget) {
|
|
return 0;
|
|
}
|
|
return this;
|
|
}
|
|
|
|
void Part::setWidget( QWidget *widget )
|
|
{
|
|
Q_D(Part);
|
|
d->m_widget = widget;
|
|
connect(
|
|
d->m_widget, SIGNAL(destroyed()),
|
|
this, SLOT(slotWidgetDestroyed()),
|
|
Qt::UniqueConnection
|
|
);
|
|
}
|
|
|
|
void Part::setSelectable(bool selectable)
|
|
{
|
|
Q_D(Part);
|
|
d->m_bSelectable = selectable;
|
|
}
|
|
|
|
bool Part::isSelectable() const
|
|
{
|
|
Q_D(const Part);
|
|
return d->m_bSelectable;
|
|
}
|
|
|
|
void Part::customEvent(QEvent *ev)
|
|
{
|
|
if (GUIActivateEvent::test(ev)) {
|
|
guiActivateEvent(static_cast<GUIActivateEvent*>(ev));
|
|
return;
|
|
}
|
|
QObject::customEvent(ev);
|
|
}
|
|
|
|
void Part::guiActivateEvent(GUIActivateEvent *)
|
|
{
|
|
}
|
|
|
|
QWidget *Part::hostContainer(const QString &containerName)
|
|
{
|
|
if (!factory()) {
|
|
return nullptr;
|
|
}
|
|
return factory()->container(containerName, this);
|
|
}
|
|
|
|
void Part::slotWidgetDestroyed()
|
|
{
|
|
Q_D(Part);
|
|
d->m_widget = nullptr;
|
|
if (d->m_autoDeletePart) {
|
|
kDebug() << "deleting part" << objectName();
|
|
delete this; // ouch, this should probably be deleteLater()
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////
|
|
|
|
namespace KParts
|
|
{
|
|
|
|
class ReadOnlyPartPrivate: public PartPrivate
|
|
{
|
|
public:
|
|
Q_DECLARE_PUBLIC(ReadOnlyPart)
|
|
|
|
ReadOnlyPartPrivate(ReadOnlyPart *q): PartPrivate(q),
|
|
m_job(0),
|
|
m_statJob(0),
|
|
m_uploadJob(0),
|
|
m_showProgressInfo(true),
|
|
m_saveOk(false),
|
|
m_waitForSave(false),
|
|
m_duringSaveAs(false),
|
|
m_bTemp(false),
|
|
m_bAutoDetectedMime(false),
|
|
m_url(0),
|
|
m_file("")
|
|
{
|
|
}
|
|
|
|
void _k_slotJobFinished(KJob *job);
|
|
void _k_slotStatJobFinished(KJob *job);
|
|
void _k_slotGotMimeType(KIO::Job *job, const QString &mime);
|
|
bool openLocalFile();
|
|
void openRemoteFile();
|
|
|
|
KIO::FileCopyJob* m_job;
|
|
KIO::StatJob* m_statJob;
|
|
KIO::FileCopyJob* m_uploadJob;
|
|
KUrl m_originalURL; // for saveAs
|
|
QString m_originalFilePath; // for saveAs
|
|
bool m_showProgressInfo;
|
|
bool m_saveOk;
|
|
bool m_waitForSave;
|
|
bool m_duringSaveAs;
|
|
|
|
/**
|
|
* If @p true, @p m_file is a temporary file that needs to be deleted later.
|
|
*/
|
|
bool m_bTemp;
|
|
|
|
// whether the mimetype in the arguments was detected by the part itself
|
|
bool m_bAutoDetectedMime;
|
|
|
|
/**
|
|
* Remote (or local) url - the one displayed to the user.
|
|
*/
|
|
KUrl m_url;
|
|
|
|
/**
|
|
* Local file - the only one the part implementation should deal with.
|
|
*/
|
|
QString m_file;
|
|
|
|
OpenUrlArguments m_arguments;
|
|
};
|
|
|
|
class ReadWritePartPrivate: public ReadOnlyPartPrivate
|
|
{
|
|
public:
|
|
Q_DECLARE_PUBLIC(ReadWritePart)
|
|
|
|
ReadWritePartPrivate(ReadWritePart *q)
|
|
: ReadOnlyPartPrivate(q)
|
|
{
|
|
m_bModified = false;
|
|
m_bReadWrite = true;
|
|
m_bClosing = false;
|
|
}
|
|
|
|
void _k_slotUploadFinished(KJob *job);
|
|
|
|
void prepareSaving();
|
|
|
|
bool m_bModified;
|
|
bool m_bReadWrite;
|
|
bool m_bClosing;
|
|
QEventLoop m_eventLoop;
|
|
};
|
|
|
|
}
|
|
|
|
ReadOnlyPart::ReadOnlyPart(QObject *parent)
|
|
: Part(*new ReadOnlyPartPrivate(this), parent)
|
|
{
|
|
}
|
|
|
|
ReadOnlyPart::ReadOnlyPart(ReadOnlyPartPrivate &dd, QObject *parent)
|
|
: Part(dd, parent)
|
|
{
|
|
}
|
|
|
|
ReadOnlyPart::~ReadOnlyPart()
|
|
{
|
|
ReadOnlyPart::closeUrl();
|
|
}
|
|
|
|
KUrl ReadOnlyPart::url() const
|
|
{
|
|
Q_D(const ReadOnlyPart);
|
|
return d->m_url;
|
|
}
|
|
|
|
void ReadOnlyPart::setUrl(const KUrl &url)
|
|
{
|
|
Q_D(ReadOnlyPart);
|
|
emit urlAboutToChange();
|
|
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;
|
|
}
|
|
|
|
void ReadOnlyPart::setProgressInfoEnabled(bool show)
|
|
{
|
|
Q_D(ReadOnlyPart);
|
|
d->m_showProgressInfo = show;
|
|
}
|
|
|
|
bool ReadOnlyPart::isProgressInfoEnabled() const
|
|
{
|
|
Q_D(const ReadOnlyPart);
|
|
return d->m_showProgressInfo;
|
|
}
|
|
|
|
bool ReadOnlyPart::openUrl(const KUrl &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;
|
|
if (!closeUrl()) {
|
|
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::protocolIsLocal(url.protocol())) {
|
|
// 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);
|
|
d->m_statJob->ui()->setWindow(widget() ? widget()->window() : nullptr);
|
|
connect(
|
|
d->m_statJob, SIGNAL(result(KJob*)),
|
|
this, SLOT(_k_slotStatJobFinished(KJob*))
|
|
);
|
|
return true;
|
|
}
|
|
d->openRemoteFile();
|
|
return true;
|
|
}
|
|
|
|
bool ReadOnlyPart::openFile()
|
|
{
|
|
kWarning() << "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(0);
|
|
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
|
|
KMimeType::Ptr mime = KMimeType::findByUrl(m_url, 0, true /* local file*/);
|
|
if (mime) {
|
|
m_arguments.setMimeType(mime->name());
|
|
m_bAutoDetectedMime = true;
|
|
}
|
|
}
|
|
const bool ret = q->openFile();
|
|
if (ret) {
|
|
emit q->setWindowCaption(m_url.prettyUrl());
|
|
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
|
|
QString fileName = m_url.fileName();
|
|
QFileInfo fileInfo(fileName);
|
|
QString ext = fileInfo.completeSuffix();
|
|
QString extension;
|
|
if (!ext.isEmpty() && m_url.query().isNull()) {
|
|
// not if the URL has a query, e.g. cgi.pl?something. keep the '.'
|
|
extension = '.' + ext;
|
|
}
|
|
m_file = KTemporaryFile::filePath(QString::fromLatin1("XXXXXXXXXX%1").arg(extension));
|
|
|
|
KUrl destURL;
|
|
destURL.setPath(m_file);
|
|
KIO::JobFlags flags = (m_showProgressInfo ? KIO::DefaultFlags : KIO::HideProgressInfo);
|
|
flags |= KIO::Overwrite;
|
|
m_job = KIO::file_copy(m_url, destURL, 0600, flags);
|
|
m_job->ui()->setWindow(q->widget() ? q->widget()->window() : 0);
|
|
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 ) {
|
|
// kDebug() << "Aborting job" << d->m_statJob;
|
|
d->m_statJob->kill();
|
|
d->m_statJob = nullptr;
|
|
}
|
|
if ( d->m_job ) {
|
|
// kDebug() << "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_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 KUrl localUrl = static_cast<KIO::StatJob*>(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.prettyUrl());
|
|
emit q->completed();
|
|
} else {
|
|
emit q->canceled(QString());
|
|
}
|
|
}
|
|
}
|
|
|
|
void ReadOnlyPartPrivate::_k_slotGotMimeType(KIO::Job *job, const QString &mime)
|
|
{
|
|
kDebug() << 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()) {
|
|
kDebug() << d->m_url;
|
|
emit setWindowCaption(d->m_url.prettyUrl());
|
|
} else {
|
|
emit setWindowCaption("");
|
|
}
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
//////////////////////////////////////////////////
|
|
|
|
|
|
ReadWritePart::ReadWritePart(QObject *parent)
|
|
: ReadOnlyPart(*new ReadWritePartPrivate(this), parent)
|
|
{
|
|
}
|
|
|
|
ReadWritePart::~ReadWritePart()
|
|
{
|
|
// parent destructor will delete temp file
|
|
// we can't call our own closeUrl() here, because
|
|
// "cancel" wouldn't cancel anything. We have to assume
|
|
// the app called closeUrl() before destroying us.
|
|
}
|
|
|
|
void ReadWritePart::setReadWrite(bool readwrite)
|
|
{
|
|
Q_D(ReadWritePart);
|
|
// Perhaps we should check isModified here and issue a warning if true
|
|
d->m_bReadWrite = readwrite;
|
|
}
|
|
|
|
void ReadWritePart::setModified(bool modified)
|
|
{
|
|
Q_D(ReadWritePart);
|
|
kDebug() << "setModified(" << (modified ? "true" : "false") << ")";
|
|
if (!d->m_bReadWrite && modified) {
|
|
kError() << "Can't set a read-only document to 'modified' !";
|
|
return;
|
|
}
|
|
d->m_bModified = modified;
|
|
}
|
|
|
|
void ReadWritePart::setModified()
|
|
{
|
|
setModified(true);
|
|
}
|
|
|
|
bool ReadWritePart::queryClose()
|
|
{
|
|
Q_D(ReadWritePart);
|
|
|
|
if (!isReadWrite() || !isModified()) {
|
|
return true;
|
|
}
|
|
|
|
QString docName = url().fileName();
|
|
if (docName.isEmpty()) {
|
|
docName = i18n("Untitled");
|
|
}
|
|
|
|
QWidget *parentWidget = widget();
|
|
if (!parentWidget) {
|
|
parentWidget = QApplication::activeWindow();
|
|
}
|
|
|
|
int res = KMessageBox::warningYesNoCancel(
|
|
parentWidget,
|
|
i18n(
|
|
"The document \"%1\" has been modified.\n"
|
|
"Do you want to save your changes or discard them?", docName
|
|
),
|
|
i18n("Close Document"),
|
|
KStandardGuiItem::save(), KStandardGuiItem::discard()
|
|
);
|
|
|
|
bool abortClose = false;
|
|
bool handled = false;
|
|
|
|
switch(res) {
|
|
case KMessageBox::Yes: {
|
|
sigQueryClose(&handled,&abortClose);
|
|
if (!handled) {
|
|
if (d->m_url.isEmpty()) {
|
|
KUrl url = KFileDialog::getSaveUrl(KUrl(), QString(), parentWidget);
|
|
if (url.isEmpty()) {
|
|
return false;
|
|
}
|
|
saveAs(url);
|
|
} else {
|
|
save();
|
|
}
|
|
} else if (abortClose) {
|
|
return false;
|
|
}
|
|
return waitSaveComplete();
|
|
}
|
|
case KMessageBox::No: {
|
|
return true;
|
|
}
|
|
// case KMessageBox::Cancel:
|
|
default: {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
bool ReadWritePart::closeUrl()
|
|
{
|
|
abortLoad(); //just in case
|
|
if (isReadWrite() && isModified()) {
|
|
if (!queryClose()) {
|
|
return false;
|
|
}
|
|
}
|
|
// Not modified => ok and delete temp file.
|
|
return ReadOnlyPart::closeUrl();
|
|
}
|
|
|
|
bool ReadWritePart::closeUrl(bool promptToSave)
|
|
{
|
|
return (promptToSave ? closeUrl() : ReadOnlyPart::closeUrl());
|
|
}
|
|
|
|
bool ReadWritePart::save()
|
|
{
|
|
Q_D(ReadWritePart);
|
|
|
|
d->m_saveOk = false;
|
|
if (d->m_file.isEmpty()) {
|
|
// document was created empty
|
|
d->prepareSaving();
|
|
}
|
|
if (saveFile()) {
|
|
return saveToUrl();
|
|
} else {
|
|
emit canceled(QString());
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool ReadWritePart::saveAs(const KUrl &kurl)
|
|
{
|
|
Q_D(ReadWritePart);
|
|
|
|
if (!kurl.isValid()) {
|
|
kError() << "saveAs: Malformed URL " << kurl.url();
|
|
return false;
|
|
}
|
|
d->m_duringSaveAs = true;
|
|
d->m_originalURL = d->m_url;
|
|
d->m_originalFilePath = d->m_file;
|
|
d->m_url = kurl; // Store where to upload in saveToURL
|
|
d->prepareSaving();
|
|
bool result = save(); // Save local file and upload local file
|
|
if (result) {
|
|
emit urlChanged(d->m_url);
|
|
emit setWindowCaption(d->m_url.prettyUrl());
|
|
} else {
|
|
d->m_url = d->m_originalURL;
|
|
d->m_file = d->m_originalFilePath;
|
|
d->m_duringSaveAs = false;
|
|
d->m_originalURL = KUrl();
|
|
d->m_originalFilePath.clear();
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
// Set m_file correctly for m_url
|
|
void ReadWritePartPrivate::prepareSaving()
|
|
{
|
|
// Local file
|
|
if (m_url.isLocalFile()) {
|
|
if (m_bTemp) {
|
|
// get rid of a possible temp file first (happens if previous url was remote)
|
|
QFile::remove(m_file);
|
|
m_bTemp = false;
|
|
}
|
|
m_file = m_url.toLocalFile();
|
|
} else {
|
|
// Remote file not saved yet, or it was but locally - provide a temp file
|
|
if (m_file.isEmpty() || !m_bTemp) {
|
|
m_file = KTemporaryFile::filePath();
|
|
m_bTemp = true;
|
|
}
|
|
// otherwise, already had a temp file
|
|
}
|
|
}
|
|
|
|
bool ReadWritePart::saveToUrl()
|
|
{
|
|
Q_D(ReadWritePart);
|
|
if (d->m_url.isLocalFile()) {
|
|
setModified(false);
|
|
emit completed();
|
|
// if m_url is a local file there won't be a temp file -> nothing to remove
|
|
Q_ASSERT(!d->m_bTemp);
|
|
d->m_saveOk = true;
|
|
d->m_duringSaveAs = false;
|
|
d->m_originalURL = KUrl();
|
|
d->m_originalFilePath.clear();
|
|
return true; // Nothing to do
|
|
} else {
|
|
if (d->m_uploadJob) {
|
|
QFile::remove(d->m_uploadJob->srcUrl().toLocalFile());
|
|
d->m_uploadJob->kill();
|
|
d->m_uploadJob = 0;
|
|
}
|
|
QString uploadFile = KTemporaryFile::filePath();
|
|
KUrl uploadUrl;
|
|
uploadUrl.setPath(uploadFile);
|
|
// Create hardlink
|
|
if (::link(QFile::encodeName(d->m_file), QFile::encodeName(uploadFile)) != 0) {
|
|
// Uh oh, some error happened.
|
|
return false;
|
|
}
|
|
d->m_uploadJob = KIO::file_move(uploadUrl, d->m_url, -1, KIO::Overwrite);
|
|
d->m_uploadJob->ui()->setWindow( widget() ? widget()->window() : 0 );
|
|
connect(
|
|
d->m_uploadJob, SIGNAL(result(KJob*)),
|
|
this, SLOT(_k_slotUploadFinished(KJob*))
|
|
);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
void ReadWritePartPrivate::_k_slotUploadFinished(KJob *)
|
|
{
|
|
Q_Q(ReadWritePart);
|
|
if (m_uploadJob->error())
|
|
{
|
|
QFile::remove(m_uploadJob->srcUrl().toLocalFile());
|
|
QString error = m_uploadJob->errorString();
|
|
m_uploadJob = nullptr;
|
|
if (m_duringSaveAs) {
|
|
q->setUrl(m_originalURL);
|
|
m_file = m_originalFilePath;
|
|
}
|
|
emit q->canceled(error);
|
|
} else {
|
|
KUrl dirUrl(m_url);
|
|
dirUrl.setPath( dirUrl.directory() );
|
|
::org::kde::KDirNotify::emitFilesAdded(dirUrl.url());
|
|
|
|
m_uploadJob = 0;
|
|
q->setModified(false);
|
|
emit q->completed();
|
|
m_saveOk = true;
|
|
}
|
|
m_duringSaveAs = false;
|
|
m_originalURL = KUrl();
|
|
m_originalFilePath.clear();
|
|
if (m_waitForSave) {
|
|
m_eventLoop.quit();
|
|
}
|
|
}
|
|
|
|
bool ReadWritePart::isReadWrite() const
|
|
{
|
|
Q_D(const ReadWritePart);
|
|
return d->m_bReadWrite;
|
|
}
|
|
|
|
bool ReadWritePart::isModified() const
|
|
{
|
|
Q_D(const ReadWritePart);
|
|
return d->m_bModified;
|
|
}
|
|
|
|
bool ReadWritePart::waitSaveComplete()
|
|
{
|
|
Q_D(ReadWritePart);
|
|
if (!d->m_uploadJob) {
|
|
return d->m_saveOk;
|
|
}
|
|
d->m_waitForSave = true;
|
|
d->m_eventLoop.exec();
|
|
d->m_waitForSave = false;
|
|
return d->m_saveOk;
|
|
}
|
|
|
|
////
|
|
|
|
class KParts::OpenUrlArgumentsPrivate : public QSharedData
|
|
{
|
|
public:
|
|
OpenUrlArgumentsPrivate()
|
|
: reload(false),
|
|
actionRequestedByUser(true),
|
|
xOffset(0),
|
|
yOffset(0)
|
|
{
|
|
}
|
|
|
|
bool reload;
|
|
bool actionRequestedByUser;
|
|
int xOffset;
|
|
int yOffset;
|
|
QString mimeType;
|
|
QMap<QString, QString> metaData;
|
|
};
|
|
|
|
KParts::OpenUrlArguments::OpenUrlArguments()
|
|
: d(new OpenUrlArgumentsPrivate)
|
|
{
|
|
}
|
|
|
|
KParts::OpenUrlArguments::OpenUrlArguments(const OpenUrlArguments &other)
|
|
: d(other.d)
|
|
{
|
|
}
|
|
|
|
KParts::OpenUrlArguments & KParts::OpenUrlArguments::operator=( const OpenUrlArguments &other)
|
|
{
|
|
d = other.d;
|
|
return *this;
|
|
}
|
|
|
|
KParts::OpenUrlArguments::~OpenUrlArguments()
|
|
{
|
|
}
|
|
|
|
bool KParts::OpenUrlArguments::reload() const
|
|
{
|
|
return d->reload;
|
|
}
|
|
|
|
void KParts::OpenUrlArguments::setReload(bool b)
|
|
{
|
|
d->reload = b;
|
|
}
|
|
|
|
int KParts::OpenUrlArguments::xOffset() const
|
|
{
|
|
return d->xOffset;
|
|
}
|
|
|
|
void KParts::OpenUrlArguments::setXOffset(int x)
|
|
{
|
|
d->xOffset = x;
|
|
}
|
|
|
|
int KParts::OpenUrlArguments::yOffset() const
|
|
{
|
|
return d->yOffset;
|
|
}
|
|
|
|
void KParts::OpenUrlArguments::setYOffset(int y)
|
|
{
|
|
d->yOffset = y;
|
|
}
|
|
|
|
QString KParts::OpenUrlArguments::mimeType() const
|
|
{
|
|
return d->mimeType;
|
|
}
|
|
|
|
void KParts::OpenUrlArguments::setMimeType(const QString& mime)
|
|
{
|
|
d->mimeType = mime;
|
|
}
|
|
|
|
QMap<QString, QString>& KParts::OpenUrlArguments::metaData()
|
|
{
|
|
return d->metaData;
|
|
}
|
|
|
|
const QMap<QString, QString> & KParts::OpenUrlArguments::metaData() const
|
|
{
|
|
return d->metaData;
|
|
}
|
|
|
|
bool KParts::OpenUrlArguments::actionRequestedByUser() const
|
|
{
|
|
return d->actionRequestedByUser;
|
|
}
|
|
|
|
void KParts::OpenUrlArguments::setActionRequestedByUser(bool userRequested)
|
|
{
|
|
d->actionRequestedByUser = userRequested;
|
|
}
|
|
|
|
#include "moc_part.cpp"
|