• Skip to content
  • Skip to link menu
KDE 4.7 API Reference
  • KDE API Reference
  • kdelibs
  • KDE Home
  • Contact Us
 

KParts

part.cpp
Go to the documentation of this file.
00001 /* This file is part of the KDE project
00002    Copyright (C) 1999 Simon Hausmann <hausmann@kde.org>
00003              (C) 1999-2005 David Faure <faure@kde.org>
00004 
00005    This library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Library General Public
00007    License as published by the Free Software Foundation; either
00008    version 2 of the License, or (at your option) any later version.
00009 
00010    This library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Library General Public License for more details.
00014 
00015    You should have received a copy of the GNU Library General Public License
00016    along with this library; see the file COPYING.LIB.  If not, write to
00017    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00018    Boston, MA 02110-1301, USA.
00019 */
00020 
00021 #include "part.h"
00022 #include <kprotocolinfo.h>
00023 #include "event.h"
00024 #include "plugin.h"
00025 #include "mainwindow.h"
00026 #include "partmanager.h"
00027 #include "browserextension.h"
00028 
00029 #include <QtGui/QApplication>
00030 #include <QtCore/QFile>
00031 #include <QtCore/QFileInfo>
00032 #include <QtGui/QPainter>
00033 #include <QtCore/QPoint>
00034 
00035 #include <kdirnotify.h>
00036 #include <kfiledialog.h>
00037 #include <kcomponentdata.h>
00038 #include <kio/job.h>
00039 #include <kio/jobuidelegate.h>
00040 #include <klocale.h>
00041 #include <kmessagebox.h>
00042 #include <kstandarddirs.h>
00043 #include <ktemporaryfile.h>
00044 #include <kxmlguifactory.h>
00045 
00046 #include <stdio.h>
00047 #include <unistd.h>
00048 #include <assert.h>
00049 #include <kdebug.h>
00050 #include <kiconloader.h>
00051 
00052 using namespace KParts;
00053 
00054 namespace KParts
00055 {
00056 
00057 class PartBasePrivate
00058 {
00059 public:
00060     Q_DECLARE_PUBLIC(PartBase)
00061 
00062     PartBasePrivate(PartBase *q): q_ptr(q)
00063     {
00064         m_pluginLoadingMode = PartBase::LoadPlugins;
00065         m_pluginInterfaceVersion = 0;
00066         m_obj = 0;
00067     }
00068 
00069     virtual ~PartBasePrivate()
00070     {
00071     }
00072 
00073     PartBase *q_ptr;
00074     PartBase::PluginLoadingMode m_pluginLoadingMode;
00075     int m_pluginInterfaceVersion;
00076     QObject *m_obj;
00077 };
00078 
00079 class PartPrivate: public PartBasePrivate
00080 {
00081 public:
00082     Q_DECLARE_PUBLIC(Part)
00083 
00084     PartPrivate(Part *q)
00085         : PartBasePrivate(q),
00086           m_iconLoader(0),
00087           m_bSelectable(true),
00088           m_autoDeleteWidget(true),
00089           m_autoDeletePart(true),
00090           m_manager(0)
00091     {
00092     }
00093 
00094     ~PartPrivate()
00095     {
00096     }
00097 
00098     KIconLoader* m_iconLoader;
00099     bool m_bSelectable;
00100     bool m_autoDeleteWidget;
00101     bool m_autoDeletePart;
00102     PartManager * m_manager;
00103     QPointer<QWidget> m_widget;
00104 };
00105 
00106 }
00107 
00108 PartBase::PartBase()
00109     : d_ptr(new PartBasePrivate(this))
00110 {
00111 }
00112 
00113 PartBase::PartBase(PartBasePrivate &dd)
00114     : d_ptr(&dd)
00115 {
00116 }
00117 
00118 PartBase::~PartBase()
00119 {
00120     delete d_ptr;
00121 }
00122 
00123 void PartBase::setPartObject( QObject *obj )
00124 {
00125     Q_D(PartBase);
00126 
00127     d->m_obj = obj;
00128 }
00129 
00130 QObject *PartBase::partObject() const
00131 {
00132     Q_D(const PartBase);
00133 
00134     return d->m_obj;
00135 }
00136 
00137 void PartBase::setComponentData(const KComponentData &componentData)
00138 {
00139     setComponentData(componentData, true);
00140 }
00141 
00142 void PartBase::setComponentData(const KComponentData &componentData, bool bLoadPlugins)
00143 {
00144     Q_D(PartBase);
00145 
00146     KXMLGUIClient::setComponentData(componentData);
00147     KGlobal::locale()->insertCatalog(componentData.catalogName());
00148     // install 'instancename'data resource type
00149     KGlobal::dirs()->addResourceType(QString(componentData.componentName() + "data").toUtf8(),
00150                                      "data", componentData.componentName());
00151     if (bLoadPlugins) {
00152         loadPlugins(d->m_obj, this, componentData);
00153     }
00154 }
00155 
00156 void PartBase::loadPlugins(QObject *parent, KXMLGUIClient *parentGUIClient, const KComponentData &instance)
00157 {
00158     Q_D(PartBase);
00159 
00160     if( d->m_pluginLoadingMode != DoNotLoadPlugins )
00161         Plugin::loadPlugins( parent, parentGUIClient, instance, d->m_pluginLoadingMode == LoadPlugins, d->m_pluginInterfaceVersion );
00162 }
00163 
00164 void PartBase::setPluginLoadingMode( PluginLoadingMode loadingMode )
00165 {
00166     Q_D(PartBase);
00167 
00168     d->m_pluginLoadingMode = loadingMode;
00169 }
00170 
00171 void KParts::PartBase::setPluginInterfaceVersion( int version )
00172 {
00173     Q_D(PartBase);
00174 
00175     d->m_pluginInterfaceVersion = version;
00176 }
00177 
00178 Part::Part( QObject *parent )
00179     : QObject( parent ), PartBase( *new PartPrivate(this) )
00180 {
00181     PartBase::setPartObject( this );
00182 }
00183 
00184 Part::Part(PartPrivate &dd, QObject *parent)
00185     : QObject( parent ), PartBase( dd )
00186 {
00187     PartBase::setPartObject( this );
00188 }
00189 
00190 Part::~Part()
00191 {
00192     Q_D(Part);
00193 
00194     //kDebug(1000) << this;
00195 
00196     if ( d->m_widget )
00197     {
00198         // We need to disconnect first, to avoid calling it !
00199         disconnect( d->m_widget, SIGNAL( destroyed() ),
00200                     this, SLOT( slotWidgetDestroyed() ) );
00201     }
00202 
00203     if ( d->m_manager )
00204         d->m_manager->removePart(this);
00205 
00206     if ( d->m_widget && d->m_autoDeleteWidget )
00207     {
00208         kDebug(1000) << "deleting widget" << d->m_widget << d->m_widget->objectName();
00209         delete static_cast<QWidget*>(d->m_widget);
00210     }
00211 
00212     delete d->m_iconLoader;
00213 }
00214 
00215 void Part::embed( QWidget * parentWidget )
00216 {
00217     if ( widget() )
00218     {
00219         widget()->setParent( parentWidget, 0 );
00220         widget()->setGeometry( 0, 0, widget()->width(), widget()->height() );
00221         widget()->show();
00222     }
00223 }
00224 
00225 QWidget *Part::widget()
00226 {
00227     Q_D(Part);
00228 
00229     return d->m_widget;
00230 }
00231 
00232 void Part::setAutoDeleteWidget(bool autoDeleteWidget)
00233 {
00234     Q_D(Part);
00235     d->m_autoDeleteWidget = autoDeleteWidget;
00236 }
00237 
00238 void Part::setAutoDeletePart(bool autoDeletePart)
00239 {
00240     Q_D(Part);
00241     d->m_autoDeletePart = autoDeletePart;
00242 }
00243 
00244 
00245 
00246 KIconLoader* Part::iconLoader()
00247 {
00248     Q_D(Part);
00249 
00250     if (!d->m_iconLoader) {
00251         Q_ASSERT(componentData().isValid());
00252         d->m_iconLoader = new KIconLoader( componentData() );
00253     }
00254     return d->m_iconLoader;
00255 }
00256 
00257 void Part::setManager( PartManager *manager )
00258 {
00259     Q_D(Part);
00260 
00261     d->m_manager = manager;
00262 }
00263 
00264 PartManager *Part::manager() const
00265 {
00266     Q_D(const Part);
00267 
00268     return d->m_manager;
00269 }
00270 
00271 Part *Part::hitTest( QWidget *widget, const QPoint & )
00272 {
00273     Q_D(Part);
00274 
00275     if ( (QWidget *)d->m_widget != widget )
00276         return 0;
00277 
00278     return this;
00279 }
00280 
00281 void Part::setWidget( QWidget *widget )
00282 {
00283     Q_D(Part);
00284     d->m_widget = widget;
00285     connect( d->m_widget, SIGNAL( destroyed() ),
00286              this, SLOT( slotWidgetDestroyed() ), Qt::UniqueConnection );
00287 }
00288 
00289 void Part::setSelectable( bool selectable )
00290 {
00291     Q_D(Part);
00292 
00293     d->m_bSelectable = selectable;
00294 }
00295 
00296 bool Part::isSelectable() const
00297 {
00298     Q_D(const Part);
00299 
00300     return d->m_bSelectable;
00301 }
00302 
00303 void Part::customEvent( QEvent *ev )
00304 {
00305     if ( PartActivateEvent::test( ev ) )
00306     {
00307         partActivateEvent( static_cast<PartActivateEvent *>(ev) );
00308         return;
00309     }
00310 
00311     if ( PartSelectEvent::test( ev ) )
00312     {
00313         partSelectEvent( static_cast<PartSelectEvent *>(ev) );
00314         return;
00315     }
00316 
00317     if ( GUIActivateEvent::test( ev ) )
00318     {
00319         guiActivateEvent( static_cast<GUIActivateEvent *>(ev) );
00320         return;
00321     }
00322 
00323     QObject::customEvent( ev );
00324 }
00325 
00326 void Part::partActivateEvent( PartActivateEvent * )
00327 {
00328 }
00329 
00330 void Part::partSelectEvent( PartSelectEvent * )
00331 {
00332 }
00333 
00334 void Part::guiActivateEvent( GUIActivateEvent * )
00335 {
00336 }
00337 
00338 QWidget *Part::hostContainer( const QString &containerName )
00339 {
00340     if ( !factory() )
00341         return 0;
00342 
00343     return factory()->container( containerName, this );
00344 }
00345 
00346 void Part::slotWidgetDestroyed()
00347 {
00348     Q_D(Part);
00349 
00350     d->m_widget = 0;
00351     if (d->m_autoDeletePart) {
00352         kDebug(1000) << "deleting part" << objectName();
00353         delete this; // ouch, this should probably be deleteLater()
00354     }
00355 }
00356 
00357 void Part::loadPlugins()
00358 {
00359     PartBase::loadPlugins(this, this, componentData());
00360 }
00361 
00363 
00364 namespace KParts
00365 {
00366 
00367 class ReadOnlyPartPrivate: public PartPrivate
00368 {
00369 public:
00370     Q_DECLARE_PUBLIC(ReadOnlyPart)
00371 
00372     ReadOnlyPartPrivate(ReadOnlyPart *q): PartPrivate(q)
00373     {
00374         m_job = 0;
00375         m_statJob = 0;
00376         m_uploadJob = 0;
00377         m_showProgressInfo = true;
00378         m_saveOk = false;
00379         m_waitForSave = false;
00380         m_duringSaveAs = false;
00381         m_bTemp = false;
00382         m_bAutoDetectedMime = false;
00383     }
00384 
00385     ~ReadOnlyPartPrivate()
00386     {
00387     }
00388 
00389     void _k_slotJobFinished( KJob * job );
00390     void _k_slotStatJobFinished(KJob * job);
00391     void _k_slotGotMimeType(KIO::Job *job, const QString &mime);
00392     bool openLocalFile();
00393     void openRemoteFile();
00394 
00395     KIO::FileCopyJob * m_job;
00396     KIO::StatJob * m_statJob;
00397     KIO::FileCopyJob * m_uploadJob;
00398     KUrl m_originalURL; // for saveAs
00399     QString m_originalFilePath; // for saveAs
00400     bool m_showProgressInfo : 1;
00401     bool m_saveOk : 1;
00402     bool m_waitForSave : 1;
00403     bool m_duringSaveAs : 1;
00404 
00408     bool m_bTemp: 1;
00409 
00410     // whether the mimetype in the arguments was detected by the part itself
00411     bool m_bAutoDetectedMime : 1;
00412 
00416     KUrl m_url;
00417 
00421     QString m_file;
00422 
00423     OpenUrlArguments m_arguments;
00424 };
00425 
00426 class ReadWritePartPrivate: public ReadOnlyPartPrivate
00427 {
00428 public:
00429     Q_DECLARE_PUBLIC(ReadWritePart)
00430 
00431     ReadWritePartPrivate(ReadWritePart *q): ReadOnlyPartPrivate(q)
00432     {
00433         m_bModified = false;
00434         m_bReadWrite = true;
00435         m_bClosing = false;
00436     }
00437 
00438     void _k_slotUploadFinished( KJob * job );
00439 
00440     void prepareSaving();
00441 
00442     bool m_bModified;
00443     bool m_bReadWrite;
00444     bool m_bClosing;
00445     QEventLoop m_eventLoop;
00446 };
00447 
00448 }
00449 
00450 ReadOnlyPart::ReadOnlyPart( QObject *parent )
00451     : Part( *new ReadOnlyPartPrivate(this), parent )
00452 {
00453 }
00454 
00455 ReadOnlyPart::ReadOnlyPart( ReadOnlyPartPrivate &dd, QObject *parent )
00456     : Part( dd, parent )
00457 {
00458 }
00459 
00460 ReadOnlyPart::~ReadOnlyPart()
00461 {
00462     ReadOnlyPart::closeUrl();
00463 }
00464 
00465 KUrl ReadOnlyPart::url() const
00466 {
00467     Q_D(const ReadOnlyPart);
00468 
00469     return d->m_url;
00470 }
00471 
00472 void ReadOnlyPart::setUrl(const KUrl &url)
00473 {
00474     Q_D(ReadOnlyPart);
00475 
00476     d->m_url = url;
00477 }
00478 
00479 QString ReadOnlyPart::localFilePath() const
00480 {
00481     Q_D(const ReadOnlyPart);
00482 
00483     return d->m_file;
00484 }
00485 
00486 void ReadOnlyPart::setLocalFilePath( const QString &localFilePath )
00487 {
00488     Q_D(ReadOnlyPart);
00489 
00490     d->m_file = localFilePath;
00491 }
00492 
00493 #ifndef KDE_NO_DEPRECATED
00494 bool ReadOnlyPart::isLocalFileTemporary() const
00495 {
00496     Q_D(const ReadOnlyPart);
00497 
00498     return d->m_bTemp;
00499 }
00500 #endif
00501 
00502 #ifndef KDE_NO_DEPRECATED
00503 void ReadOnlyPart::setLocalFileTemporary( bool temp )
00504 {
00505     Q_D(ReadOnlyPart);
00506 
00507     d->m_bTemp = temp;
00508 }
00509 #endif
00510 
00511 void ReadOnlyPart::setProgressInfoEnabled( bool show )
00512 {
00513     Q_D(ReadOnlyPart);
00514 
00515     d->m_showProgressInfo = show;
00516 }
00517 
00518 bool ReadOnlyPart::isProgressInfoEnabled() const
00519 {
00520     Q_D(const ReadOnlyPart);
00521 
00522     return d->m_showProgressInfo;
00523 }
00524 
00525 #ifndef KDE_NO_COMPAT
00526 void ReadOnlyPart::showProgressInfo( bool show )
00527 {
00528     Q_D(ReadOnlyPart);
00529 
00530     d->m_showProgressInfo = show;
00531 }
00532 #endif
00533 
00534 bool ReadOnlyPart::openUrl( const KUrl &url )
00535 {
00536     Q_D(ReadOnlyPart);
00537 
00538     if ( !url.isValid() )
00539         return false;
00540     if (d->m_bAutoDetectedMime) {
00541         d->m_arguments.setMimeType(QString());
00542         d->m_bAutoDetectedMime = false;
00543     }
00544     OpenUrlArguments args = d->m_arguments;
00545     if ( !closeUrl() )
00546         return false;
00547     d->m_arguments = args;
00548     d->m_url = url;
00549 
00550     d->m_file.clear();
00551 
00552     if (d->m_url.isLocalFile()) {
00553         d->m_file = d->m_url.toLocalFile();
00554         return d->openLocalFile();
00555     } else if (KProtocolInfo::protocolClass(url.protocol()) == ":local") {
00556         // Maybe we can use a "local path", to avoid a temp copy?
00557         KIO::JobFlags flags = d->m_showProgressInfo ? KIO::DefaultFlags : KIO::HideProgressInfo;
00558         d->m_statJob = KIO::mostLocalUrl(d->m_url, flags);
00559         d->m_statJob->ui()->setWindow( widget() ? widget()->topLevelWidget() : 0 );
00560         connect(d->m_statJob, SIGNAL(result(KJob*)), this, SLOT(_k_slotStatJobFinished(KJob*)));
00561         return true;
00562     } else {
00563         d->openRemoteFile();
00564         return true;
00565     }
00566 }
00567 
00568 bool ReadOnlyPart::openFile()
00569 {
00570     kWarning(1000) << "Default implementation of ReadOnlyPart::openFile called!"
00571                    << metaObject()->className() << "should reimplement either openUrl or openFile.";
00572     return false;
00573 }
00574 
00575 bool ReadOnlyPartPrivate::openLocalFile()
00576 {
00577     Q_Q(ReadOnlyPart);
00578     emit q->started( 0 );
00579     m_bTemp = false;
00580     // set the mimetype only if it was not already set (for example, by the host application)
00581     if (m_arguments.mimeType().isEmpty()) {
00582         // get the mimetype of the file
00583         // using findByUrl() to avoid another string -> url conversion
00584         KMimeType::Ptr mime = KMimeType::findByUrl(m_url, 0, true /* local file*/);
00585         if (mime) {
00586             m_arguments.setMimeType(mime->name());
00587             m_bAutoDetectedMime = true;
00588         }
00589     }
00590     const bool ret = q->openFile();
00591     if (ret) {
00592         emit q->setWindowCaption(m_url.prettyUrl());
00593         emit q->completed();
00594     } else {
00595         emit q->canceled(QString());
00596     }
00597     return ret;
00598 }
00599 
00600 void ReadOnlyPartPrivate::openRemoteFile()
00601 {
00602     Q_Q(ReadOnlyPart);
00603     m_bTemp = true;
00604     // Use same extension as remote file. This is important for mimetype-determination (e.g. koffice)
00605     QString fileName = m_url.fileName();
00606     QFileInfo fileInfo(fileName);
00607     QString ext = fileInfo.completeSuffix();
00608     QString extension;
00609     if (!ext.isEmpty() && m_url.query().isNull()) // not if the URL has a query, e.g. cgi.pl?something
00610         extension = '.'+ext; // keep the '.'
00611     KTemporaryFile tempFile;
00612     tempFile.setSuffix(extension);
00613     tempFile.setAutoRemove(false);
00614     tempFile.open();
00615     m_file = tempFile.fileName();
00616 
00617     KUrl destURL;
00618     destURL.setPath( m_file );
00619     KIO::JobFlags flags = m_showProgressInfo ? KIO::DefaultFlags : KIO::HideProgressInfo;
00620     flags |= KIO::Overwrite;
00621     m_job = KIO::file_copy(m_url, destURL, 0600, flags);
00622     m_job->ui()->setWindow(q->widget() ? q->widget()->topLevelWidget() : 0);
00623     emit q->started(m_job);
00624     QObject::connect(m_job, SIGNAL(result(KJob*)), q, SLOT(_k_slotJobFinished(KJob*)));
00625     QObject::connect(m_job, SIGNAL(mimetype(KIO::Job*, QString)),
00626                      q, SLOT(_k_slotGotMimeType(KIO::Job*,QString)));
00627 }
00628 
00629 void ReadOnlyPart::abortLoad()
00630 {
00631     Q_D(ReadOnlyPart);
00632 
00633     if ( d->m_statJob ) {
00634         //kDebug(1000) << "Aborting job" << d->m_statJob;
00635         d->m_statJob->kill();
00636         d->m_statJob = 0;
00637     }
00638     if ( d->m_job ) {
00639         //kDebug(1000) << "Aborting job" << d->m_job;
00640         d->m_job->kill();
00641         d->m_job = 0;
00642     }
00643 }
00644 
00645 bool ReadOnlyPart::closeUrl()
00646 {
00647     Q_D(ReadOnlyPart);
00648 
00649     abortLoad(); //just in case
00650 
00651     d->m_arguments = KParts::OpenUrlArguments();
00652 
00653     if ( d->m_bTemp )
00654     {
00655         QFile::remove( d->m_file );
00656         d->m_bTemp = false;
00657     }
00658     // It always succeeds for a read-only part,
00659     // but the return value exists for reimplementations
00660     // (e.g. pressing cancel for a modified read-write part)
00661     return true;
00662 }
00663 
00664 void ReadOnlyPartPrivate::_k_slotStatJobFinished(KJob * job)
00665 {
00666     Q_ASSERT(job == m_statJob);
00667     m_statJob = 0;
00668 
00669     // We could emit canceled on error, but we haven't even emitted started yet,
00670     // this could maybe confuse some apps? So for now we'll just fallback to KIO::get
00671     // and error again. Well, maybe this even helps with wrong stat results.
00672     if (!job->error()) {
00673         const KUrl localUrl = static_cast<KIO::StatJob*>(job)->mostLocalUrl();
00674         if (localUrl.isLocalFile()) {
00675             m_file = localUrl.toLocalFile();
00676             (void)openLocalFile();
00677             return;
00678         }
00679     }
00680     openRemoteFile();
00681 }
00682 
00683 void ReadOnlyPartPrivate::_k_slotJobFinished( KJob * job )
00684 {
00685     Q_Q(ReadOnlyPart);
00686 
00687     assert( job == m_job );
00688     m_job = 0;
00689     if (job->error())
00690         emit q->canceled( job->errorString() );
00691     else
00692     {
00693         if ( q->openFile() ) {
00694             emit q->setWindowCaption( m_url.prettyUrl() );
00695             emit q->completed();
00696         } else emit q->canceled(QString());
00697     }
00698 }
00699 
00700 void ReadOnlyPartPrivate::_k_slotGotMimeType(KIO::Job *job, const QString &mime)
00701 {
00702     kDebug(1000) << mime;
00703     Q_ASSERT(job == m_job); Q_UNUSED(job)
00704     // set the mimetype only if it was not already set (for example, by the host application)
00705     if (m_arguments.mimeType().isEmpty()) {
00706         m_arguments.setMimeType(mime);
00707         m_bAutoDetectedMime = true;
00708     }
00709 }
00710 
00711 void ReadOnlyPart::guiActivateEvent( GUIActivateEvent * event )
00712 {
00713     Q_D(ReadOnlyPart);
00714 
00715     if (event->activated())
00716     {
00717         if (!d->m_url.isEmpty())
00718         {
00719             kDebug(1000) << d->m_url;
00720             emit setWindowCaption( d->m_url.prettyUrl() );
00721         } else emit setWindowCaption( "" );
00722     }
00723 }
00724 
00725 bool ReadOnlyPart::openStream( const QString& mimeType, const KUrl& url )
00726 {
00727     Q_D(ReadOnlyPart);
00728 
00729     OpenUrlArguments args = d->m_arguments;
00730     if ( !closeUrl() )
00731         return false;
00732     d->m_arguments = args;
00733     d->m_url = url;
00734     return doOpenStream( mimeType );
00735 }
00736 
00737 bool ReadOnlyPart::writeStream( const QByteArray& data )
00738 {
00739     return doWriteStream( data );
00740 }
00741 
00742 bool ReadOnlyPart::closeStream()
00743 {
00744     return doCloseStream();
00745 }
00746 
00747 BrowserExtension* ReadOnlyPart::browserExtension() const
00748 {
00749     return findChild<KParts::BrowserExtension *>();
00750 }
00751 
00752 void KParts::ReadOnlyPart::setArguments(const OpenUrlArguments& arguments)
00753 {
00754     Q_D(ReadOnlyPart);
00755     d->m_arguments = arguments;
00756     d->m_bAutoDetectedMime = arguments.mimeType().isEmpty();
00757 }
00758 
00759 OpenUrlArguments KParts::ReadOnlyPart::arguments() const
00760 {
00761     Q_D(const ReadOnlyPart);
00762     return d->m_arguments;
00763 }
00764 
00766 
00767 
00768 ReadWritePart::ReadWritePart( QObject *parent )
00769     : ReadOnlyPart( *new ReadWritePartPrivate(this), parent )
00770 {
00771 }
00772 
00773 ReadWritePart::~ReadWritePart()
00774 {
00775     // parent destructor will delete temp file
00776     // we can't call our own closeUrl() here, because
00777     // "cancel" wouldn't cancel anything. We have to assume
00778     // the app called closeUrl() before destroying us.
00779 }
00780 
00781 void ReadWritePart::setReadWrite( bool readwrite )
00782 {
00783     Q_D(ReadWritePart);
00784 
00785     // Perhaps we should check isModified here and issue a warning if true
00786     d->m_bReadWrite = readwrite;
00787 }
00788 
00789 void ReadWritePart::setModified( bool modified )
00790 {
00791     Q_D(ReadWritePart);
00792 
00793     kDebug(1000) << "setModified(" << (modified ? "true" : "false") << ")";
00794     if ( !d->m_bReadWrite && modified )
00795     {
00796         kError(1000) << "Can't set a read-only document to 'modified' !" << endl;
00797         return;
00798     }
00799     d->m_bModified = modified;
00800 }
00801 
00802 void ReadWritePart::setModified()
00803 {
00804     setModified( true );
00805 }
00806 
00807 bool ReadWritePart::queryClose()
00808 {
00809     Q_D(ReadWritePart);
00810 
00811     if ( !isReadWrite() || !isModified() )
00812         return true;
00813 
00814     QString docName = url().fileName();
00815     if (docName.isEmpty()) docName = i18n( "Untitled" );
00816 
00817     QWidget *parentWidget=widget();
00818     if(!parentWidget) parentWidget=QApplication::activeWindow();
00819 
00820     int res = KMessageBox::warningYesNoCancel( parentWidget,
00821                                                i18n( "The document \"%1\" has been modified.\n"
00822                                                      "Do you want to save your changes or discard them?" ,  docName ),
00823                                                i18n( "Close Document" ), KStandardGuiItem::save(), KStandardGuiItem::discard() );
00824 
00825     bool abortClose=false;
00826     bool handled=false;
00827 
00828     switch(res) {
00829     case KMessageBox::Yes :
00830         sigQueryClose(&handled,&abortClose);
00831         if (!handled)
00832         {
00833             if (d->m_url.isEmpty())
00834             {
00835                 KUrl url = KFileDialog::getSaveUrl(KUrl(), QString(), parentWidget);
00836                 if (url.isEmpty())
00837                     return false;
00838 
00839                 saveAs( url );
00840             }
00841             else
00842             {
00843                 save();
00844             }
00845         } else if (abortClose) return false;
00846         return waitSaveComplete();
00847     case KMessageBox::No :
00848         return true;
00849     default : // case KMessageBox::Cancel :
00850         return false;
00851     }
00852 }
00853 
00854 bool ReadWritePart::closeUrl()
00855 {
00856     abortLoad(); //just in case
00857     if ( isReadWrite() && isModified() )
00858     {
00859         if (!queryClose())
00860             return false;
00861     }
00862     // Not modified => ok and delete temp file.
00863     return ReadOnlyPart::closeUrl();
00864 }
00865 
00866 bool ReadWritePart::closeUrl( bool promptToSave )
00867 {
00868     return promptToSave ? closeUrl() : ReadOnlyPart::closeUrl();
00869 }
00870 
00871 bool ReadWritePart::save()
00872 {
00873     Q_D(ReadWritePart);
00874 
00875     d->m_saveOk = false;
00876     if ( d->m_file.isEmpty() ) // document was created empty
00877         d->prepareSaving();
00878     if( saveFile() )
00879         return saveToUrl();
00880     else
00881         emit canceled(QString());
00882     return false;
00883 }
00884 
00885 bool ReadWritePart::saveAs( const KUrl & kurl )
00886 {
00887     Q_D(ReadWritePart);
00888 
00889     if (!kurl.isValid())
00890     {
00891         kError(1000) << "saveAs: Malformed URL " << kurl.url() << endl;
00892         return false;
00893     }
00894     d->m_duringSaveAs = true;
00895     d->m_originalURL = d->m_url;
00896     d->m_originalFilePath = d->m_file;
00897     d->m_url = kurl; // Store where to upload in saveToURL
00898     d->prepareSaving();
00899     bool result = save(); // Save local file and upload local file
00900     if (result) {
00901         emit setWindowCaption( d->m_url.prettyUrl() );
00902     } else {
00903         d->m_url = d->m_originalURL;
00904         d->m_file = d->m_originalFilePath;
00905         d->m_duringSaveAs = false;
00906         d->m_originalURL = KUrl();
00907         d->m_originalFilePath.clear();
00908     }
00909 
00910     return result;
00911 }
00912 
00913 // Set m_file correctly for m_url
00914 void ReadWritePartPrivate::prepareSaving()
00915 {
00916     // Local file
00917     if ( m_url.isLocalFile() )
00918     {
00919         if ( m_bTemp ) // get rid of a possible temp file first
00920         {              // (happens if previous url was remote)
00921             QFile::remove( m_file );
00922             m_bTemp = false;
00923         }
00924         m_file = m_url.toLocalFile();
00925     }
00926     else
00927     { // Remote file
00928         // We haven't saved yet, or we did but locally - provide a temp file
00929         if ( m_file.isEmpty() || !m_bTemp )
00930         {
00931             KTemporaryFile tempFile;
00932             tempFile.setAutoRemove(false);
00933             tempFile.open();
00934             m_file = tempFile.fileName();
00935             m_bTemp = true;
00936         }
00937         // otherwise, we already had a temp file
00938     }
00939 }
00940 
00941 bool ReadWritePart::saveToUrl()
00942 {
00943     Q_D(ReadWritePart);
00944 
00945     if ( d->m_url.isLocalFile() )
00946     {
00947         setModified( false );
00948         emit completed();
00949         // if m_url is a local file there won't be a temp file -> nothing to remove
00950         assert( !d->m_bTemp );
00951         d->m_saveOk = true;
00952         d->m_duringSaveAs = false;
00953         d->m_originalURL = KUrl();
00954         d->m_originalFilePath.clear();
00955         return true; // Nothing to do
00956     }
00957     else
00958     {
00959         if (d->m_uploadJob)
00960         {
00961             QFile::remove(d->m_uploadJob->srcUrl().toLocalFile());
00962             d->m_uploadJob->kill();
00963             d->m_uploadJob = 0;
00964         }
00965         KTemporaryFile *tempFile = new KTemporaryFile();
00966         tempFile->open();
00967         QString uploadFile = tempFile->fileName();
00968         delete tempFile;
00969         KUrl uploadUrl;
00970         uploadUrl.setPath( uploadFile );
00971         // Create hardlink
00972         if (::link(QFile::encodeName(d->m_file), QFile::encodeName(uploadFile)) != 0)
00973         {
00974             // Uh oh, some error happened.
00975             return false;
00976         }
00977         d->m_uploadJob = KIO::file_move( uploadUrl, d->m_url, -1, KIO::Overwrite );
00978         d->m_uploadJob->ui()->setWindow( widget() ? widget()->topLevelWidget() : 0 );
00979         connect( d->m_uploadJob, SIGNAL( result( KJob * ) ), this, SLOT( _k_slotUploadFinished (KJob *) ) );
00980         return true;
00981     }
00982 }
00983 
00984 void ReadWritePartPrivate::_k_slotUploadFinished( KJob * )
00985 {
00986     Q_Q(ReadWritePart);
00987 
00988     if (m_uploadJob->error())
00989     {
00990         QFile::remove(m_uploadJob->srcUrl().toLocalFile());
00991         QString error = m_uploadJob->errorString();
00992         m_uploadJob = 0;
00993         if (m_duringSaveAs) {
00994             m_url = m_originalURL;
00995             m_file = m_originalFilePath;
00996         }
00997         emit q->canceled( error );
00998     }
00999     else
01000     {
01001         KUrl dirUrl( m_url );
01002         dirUrl.setPath( dirUrl.directory() );
01003         ::org::kde::KDirNotify::emitFilesAdded( dirUrl.url() );
01004 
01005         m_uploadJob = 0;
01006         q->setModified( false );
01007         emit q->completed();
01008         m_saveOk = true;
01009     }
01010     m_duringSaveAs = false;
01011     m_originalURL = KUrl();
01012     m_originalFilePath.clear();
01013     if (m_waitForSave) {
01014         m_eventLoop.quit();
01015     }
01016 }
01017 
01018 bool ReadWritePart::isReadWrite() const
01019 {
01020     Q_D(const ReadWritePart);
01021 
01022     return d->m_bReadWrite;
01023 }
01024 
01025 bool ReadWritePart::isModified() const
01026 {
01027     Q_D(const ReadWritePart);
01028 
01029     return d->m_bModified;
01030 }
01031 
01032 bool ReadWritePart::waitSaveComplete()
01033 {
01034     Q_D(ReadWritePart);
01035 
01036     if (!d->m_uploadJob)
01037         return d->m_saveOk;
01038 
01039     d->m_waitForSave = true;
01040 
01041     d->m_eventLoop.exec(QEventLoop::ExcludeUserInputEvents);
01042 
01043     d->m_waitForSave = false;
01044 
01045     return d->m_saveOk;
01046 }
01047 
01049 
01050 class KParts::OpenUrlArgumentsPrivate : public QSharedData
01051 {
01052 public:
01053     OpenUrlArgumentsPrivate()
01054         : reload(false),
01055           actionRequestedByUser(true),
01056           xOffset(0),
01057           yOffset(0),
01058           mimeType(),
01059           metaData()
01060     {}
01061     bool reload;
01062     bool actionRequestedByUser;
01063     int xOffset;
01064     int yOffset;
01065     QString mimeType;
01066     QMap<QString, QString> metaData;
01067 };
01068 
01069 KParts::OpenUrlArguments::OpenUrlArguments()
01070     : d(new OpenUrlArgumentsPrivate)
01071 {
01072 }
01073 
01074 KParts::OpenUrlArguments::OpenUrlArguments(const OpenUrlArguments &other)
01075     : d(other.d)
01076 {
01077 }
01078 
01079 KParts::OpenUrlArguments & KParts::OpenUrlArguments::operator=( const OpenUrlArguments &other)
01080 {
01081     d = other.d;
01082     return *this;
01083 }
01084 
01085 KParts::OpenUrlArguments::~OpenUrlArguments()
01086 {
01087 }
01088 
01089 bool KParts::OpenUrlArguments::reload() const
01090 {
01091     return d->reload;
01092 }
01093 
01094 void KParts::OpenUrlArguments::setReload(bool b)
01095 {
01096     d->reload = b;
01097 }
01098 
01099 int KParts::OpenUrlArguments::xOffset() const
01100 {
01101     return d->xOffset;
01102 }
01103 
01104 void KParts::OpenUrlArguments::setXOffset(int x)
01105 {
01106     d->xOffset = x;
01107 }
01108 
01109 int KParts::OpenUrlArguments::yOffset() const
01110 {
01111     return d->yOffset;
01112 }
01113 
01114 void KParts::OpenUrlArguments::setYOffset(int y)
01115 {
01116     d->yOffset = y;
01117 }
01118 
01119 QString KParts::OpenUrlArguments::mimeType() const
01120 {
01121     return d->mimeType;
01122 }
01123 
01124 void KParts::OpenUrlArguments::setMimeType(const QString& mime)
01125 {
01126     d->mimeType = mime;
01127 }
01128 
01129 QMap<QString, QString> & KParts::OpenUrlArguments::metaData()
01130 {
01131     return d->metaData;
01132 }
01133 
01134 const QMap<QString, QString> & KParts::OpenUrlArguments::metaData() const
01135 {
01136     return d->metaData;
01137 }
01138 
01139 bool KParts::OpenUrlArguments::actionRequestedByUser() const
01140 {
01141     return d->actionRequestedByUser;
01142 }
01143 
01144 void KParts::OpenUrlArguments::setActionRequestedByUser(bool userRequested)
01145 {
01146     d->actionRequestedByUser = userRequested;
01147 }
01148 
01149 #include "part.moc"

KParts

Skip menu "KParts"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Modules
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.7.5
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal