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

because KParts::ReadWritePart::closeUrl() is not called from the KParts::ReadWritePart destructor (and even if it is bad stuff may happen) for most rw parts (exception being okular which does its own query, maybe some other parts too) saving was not actually done (e.g. for ark). now the part will be queried to close, if the upload job fails (e.g. because of insufficient access) the application/part will not close (intentionally) tho and no error is reported via message box which is something that needs to be looked into Signed-off-by: Ivailo Monev <xakepa10@gmail.com>
967 lines
22 KiB
C++
967 lines
22 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);
|
|
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);
|
|
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;
|
|
m_file = KTemporaryFile::urlPath(m_url);
|
|
|
|
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*))
|
|
);
|
|
}
|
|
|
|
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() != KJob::NoError) {
|
|
KIO::StatJob* statjob = static_cast<KIO::StatJob*>(job);
|
|
const KUrl localUrl = statjob->mostLocalUrl();
|
|
const QString mime = statjob->statResult().stringValue(KIO::UDSEntry::UDS_MIME_TYPE);
|
|
// 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;
|
|
}
|
|
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 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"
|