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"
KDE 4.7 API Reference