00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include <kparts/part.h>
00022 #include <kparts/event.h>
00023 #include <kparts/plugin.h>
00024 #include <kparts/mainwindow.h>
00025 #include <kparts/partmanager.h>
00026
00027 #include <qapplication.h>
00028 #include <qfile.h>
00029 #include <qpoint.h>
00030 #include <qpointarray.h>
00031 #include <qpainter.h>
00032 #include <qtextstream.h>
00033 #include <qfileinfo.h>
00034
00035 #include <kinstance.h>
00036 #include <klocale.h>
00037 #include <ktempfile.h>
00038 #include <kmessagebox.h>
00039 #include <kio/job.h>
00040 #include <kstandarddirs.h>
00041 #include <kfiledialog.h>
00042 #include <kdirnotify_stub.h>
00043
00044 #include <stdio.h>
00045 #include <unistd.h>
00046 #include <assert.h>
00047 #include <kdebug.h>
00048
00049 template class QPtrList<KXMLGUIClient>;
00050
00051 using namespace KParts;
00052
00053 namespace KParts
00054 {
00055
00056 class PartBasePrivate
00057 {
00058 public:
00059 PartBasePrivate()
00060 {
00061 m_pluginLoadingMode = PartBase::LoadPlugins;
00062 }
00063 ~PartBasePrivate()
00064 {
00065 }
00066 PartBase::PluginLoadingMode m_pluginLoadingMode;
00067 };
00068
00069 class PartPrivate
00070 {
00071 public:
00072 PartPrivate()
00073 {
00074 m_bSelectable = true;
00075 }
00076 ~PartPrivate()
00077 {
00078 }
00079
00080 bool m_bSelectable;
00081 };
00082 }
00083
00084 PartBase::PartBase()
00085 {
00086 d = new PartBasePrivate;
00087 m_obj = 0L;
00088 }
00089
00090 PartBase::~PartBase()
00091 {
00092 delete d;
00093 }
00094
00095 void PartBase::setPartObject( QObject *obj )
00096 {
00097 m_obj = obj;
00098 }
00099
00100 QObject *PartBase::partObject() const
00101 {
00102 return m_obj;
00103 }
00104
00105 void PartBase::setInstance( KInstance *inst )
00106 {
00107 setInstance( inst, true );
00108 }
00109
00110 void PartBase::setInstance( KInstance *inst, bool bLoadPlugins )
00111 {
00112 KXMLGUIClient::setInstance( inst );
00113 KGlobal::locale()->insertCatalogue( inst->instanceName() );
00114
00115 KGlobal::dirs()->addResourceType( inst->instanceName() + "data",
00116 KStandardDirs::kde_default( "data" )
00117 + QString::fromLatin1( inst->instanceName() ) + '/' );
00118 if ( bLoadPlugins )
00119 loadPlugins( m_obj, this, instance() );
00120 }
00121
00122 void PartBase::loadPlugins( QObject *parent, KXMLGUIClient *parentGUIClient, KInstance *instance )
00123 {
00124 if( d->m_pluginLoadingMode != DoNotLoadPlugins )
00125 Plugin::loadPlugins( parent, parentGUIClient, instance, d->m_pluginLoadingMode == LoadPlugins );
00126 }
00127
00128 void PartBase::setPluginLoadingMode( PluginLoadingMode loadingMode )
00129 {
00130 d->m_pluginLoadingMode = loadingMode;
00131 }
00132
00133 Part::Part( QObject *parent, const char* name )
00134 : QObject( parent, name )
00135 {
00136 d = new PartPrivate;
00137 m_widget = 0L;
00138 m_manager = 0L;
00139 PartBase::setPartObject( this );
00140 }
00141
00142 Part::~Part()
00143 {
00144 kdDebug(1000) << "Part::~Part " << this << endl;
00145
00146 if ( m_widget )
00147 {
00148
00149 disconnect( m_widget, SIGNAL( destroyed() ),
00150 this, SLOT( slotWidgetDestroyed() ) );
00151 }
00152
00153 if ( m_manager )
00154 m_manager->removePart(this);
00155
00156 if ( m_widget )
00157 {
00158 kdDebug(1000) << "deleting widget " << m_widget << " " << m_widget->name() << endl;
00159 delete (QWidget*) m_widget;
00160 }
00161
00162 delete d;
00163 }
00164
00165 void Part::embed( QWidget * parentWidget )
00166 {
00167 if ( widget() )
00168 widget()->reparent( parentWidget, 0, QPoint( 0, 0 ), true );
00169 }
00170
00171 QWidget *Part::widget()
00172 {
00173 return m_widget;
00174 }
00175
00176 void Part::setManager( PartManager *manager )
00177 {
00178 m_manager = manager;
00179 }
00180
00181 PartManager *Part::manager() const
00182 {
00183 return m_manager;
00184 }
00185
00186 Part *Part::hitTest( QWidget *widget, const QPoint & )
00187 {
00188 if ( (QWidget *)m_widget != widget )
00189 return 0L;
00190
00191 return this;
00192 }
00193
00194 void Part::setWidget( QWidget *widget )
00195 {
00196 assert ( !m_widget );
00197 m_widget = widget;
00198 connect( m_widget, SIGNAL( destroyed() ),
00199 this, SLOT( slotWidgetDestroyed() ) );
00200
00201
00202
00203 actionCollection()->setWidget( widget );
00204
00205
00206
00207
00208 actionCollection()->setAutoConnectShortcuts( false );
00209 }
00210
00211 void Part::setSelectable( bool selectable )
00212 {
00213 d->m_bSelectable = selectable;
00214 }
00215
00216 bool Part::isSelectable() const
00217 {
00218 return d->m_bSelectable;
00219 }
00220
00221 void Part::customEvent( QCustomEvent *event )
00222 {
00223 if ( PartActivateEvent::test( event ) )
00224 {
00225 partActivateEvent( (PartActivateEvent *)event );
00226 return;
00227 }
00228
00229 if ( PartSelectEvent::test( event ) )
00230 {
00231 partSelectEvent( (PartSelectEvent *)event );
00232 return;
00233 }
00234
00235 if ( GUIActivateEvent::test( event ) )
00236 {
00237 guiActivateEvent( (GUIActivateEvent *)event );
00238 return;
00239 }
00240
00241 QObject::customEvent( event );
00242 }
00243
00244 void Part::partActivateEvent( PartActivateEvent * )
00245 {
00246 }
00247
00248 void Part::partSelectEvent( PartSelectEvent * )
00249 {
00250 }
00251
00252 void Part::guiActivateEvent( GUIActivateEvent * )
00253 {
00254 }
00255
00256 QWidget *Part::hostContainer( const QString &containerName )
00257 {
00258 if ( !factory() )
00259 return 0L;
00260
00261 return factory()->container( containerName, this );
00262 }
00263
00264 void Part::slotWidgetDestroyed()
00265 {
00266 kdDebug(1000) << "KPart::slotWidgetDestroyed(), deleting part " << name() << endl;
00267 m_widget = 0;
00268 delete this;
00269 }
00270
00272
00273 namespace KParts
00274 {
00275
00276 class ReadOnlyPartPrivate
00277 {
00278 public:
00279 ReadOnlyPartPrivate()
00280 {
00281 m_job = 0L;
00282 m_uploadJob = 0L;
00283 m_showProgressInfo = true;
00284 m_saveOk = false;
00285 m_waitForSave = false;
00286 m_duringSaveAs = false;
00287 }
00288 ~ReadOnlyPartPrivate()
00289 {
00290 }
00291
00292 KIO::FileCopyJob * m_job;
00293 KIO::FileCopyJob * m_uploadJob;
00294 KURL m_originalURL;
00295 QString m_originalFilePath;
00296 bool m_showProgressInfo : 1;
00297 bool m_saveOk : 1;
00298 bool m_waitForSave : 1;
00299 bool m_duringSaveAs : 1;
00300 };
00301
00302 }
00303
00304 ReadOnlyPart::ReadOnlyPart( QObject *parent, const char *name )
00305 : Part( parent, name ), m_bTemp( false )
00306 {
00307 d = new ReadOnlyPartPrivate;
00308 }
00309
00310 ReadOnlyPart::~ReadOnlyPart()
00311 {
00312 ReadOnlyPart::closeURL();
00313 delete d;
00314 }
00315
00316 void ReadOnlyPart::setProgressInfoEnabled( bool show )
00317 {
00318 d->m_showProgressInfo = show;
00319 }
00320
00321 bool ReadOnlyPart::isProgressInfoEnabled() const
00322 {
00323 return d->m_showProgressInfo;
00324 }
00325
00326 #ifndef KDE_NO_COMPAT
00327 void ReadOnlyPart::showProgressInfo( bool show )
00328 {
00329 d->m_showProgressInfo = show;
00330 }
00331 #endif
00332
00333 bool ReadOnlyPart::openURL( const KURL &url )
00334 {
00335 if ( !url.isValid() )
00336 return false;
00337 if ( !closeURL() )
00338 return false;
00339 m_url = url;
00340 if ( m_url.isLocalFile() )
00341 {
00342 emit started( 0 );
00343 m_file = m_url.path();
00344 bool ret = openFile();
00345 if (ret)
00346 {
00347 emit completed();
00348 emit setWindowCaption( m_url.prettyURL() );
00349 };
00350 return ret;
00351 }
00352 else
00353 {
00354 m_bTemp = true;
00355
00356 QString fileName = url.fileName();
00357 QFileInfo fileInfo(fileName);
00358 QString ext = fileInfo.extension();
00359 QString extension;
00360 if ( !ext.isEmpty() && url.query().isNull() )
00361 extension = "."+ext;
00362 KTempFile tempFile( QString::null, extension );
00363 m_file = tempFile.name();
00364
00365 KURL destURL;
00366 destURL.setPath( m_file );
00367 d->m_job = KIO::file_copy( m_url, destURL, 0600, true, false, d->m_showProgressInfo );
00368 d->m_job->setWindow( widget() ? widget()->topLevelWidget() : 0 );
00369 emit started( d->m_job );
00370 connect( d->m_job, SIGNAL( result( KIO::Job * ) ), this, SLOT( slotJobFinished ( KIO::Job * ) ) );
00371 return true;
00372 }
00373 }
00374
00375 void ReadOnlyPart::abortLoad()
00376 {
00377 if ( d->m_job )
00378 {
00379
00380 d->m_job->kill();
00381 d->m_job = 0;
00382 }
00383 }
00384
00385 bool ReadOnlyPart::closeURL()
00386 {
00387 abortLoad();
00388
00389 if ( m_bTemp )
00390 {
00391 unlink( QFile::encodeName(m_file) );
00392 m_bTemp = false;
00393 }
00394
00395
00396
00397 return true;
00398 }
00399
00400 void ReadOnlyPart::slotJobFinished( KIO::Job * job )
00401 {
00402 kdDebug(1000) << "ReadOnlyPart::slotJobFinished" << endl;
00403 assert( job == d->m_job );
00404 d->m_job = 0;
00405 if (job->error())
00406 emit canceled( job->errorString() );
00407 else
00408 {
00409 if ( openFile() )
00410 emit setWindowCaption( m_url.prettyURL() );
00411 emit completed();
00412 }
00413 }
00414
00415 void ReadOnlyPart::guiActivateEvent( GUIActivateEvent * event )
00416 {
00417 if (event->activated())
00418 {
00419 if (!m_url.isEmpty())
00420 {
00421 kdDebug(1000) << "ReadOnlyPart::guiActivateEvent -> " << m_url.prettyURL() << endl;
00422 emit setWindowCaption( m_url.prettyURL() );
00423 } else emit setWindowCaption( "" );
00424 }
00425 }
00426
00427 bool ReadOnlyPart::openStream( const QString& mimeType, const KURL& url )
00428 {
00429 if ( !closeURL() )
00430 return false;
00431 m_url = url;
00432 return doOpenStream( mimeType );
00433 }
00434
00435 bool ReadOnlyPart::writeStream( const QByteArray& data )
00436 {
00437 return doWriteStream( data );
00438 }
00439
00440 bool ReadOnlyPart::closeStream()
00441 {
00442 return doCloseStream();
00443 }
00444
00446
00447 ReadWritePart::ReadWritePart( QObject *parent, const char *name )
00448 : ReadOnlyPart( parent, name ), m_bModified( false ), m_bClosing( false )
00449 {
00450 m_bReadWrite = true;
00451 }
00452
00453 ReadWritePart::~ReadWritePart()
00454 {
00455
00456
00457
00458
00459 }
00460
00461 void ReadWritePart::setReadWrite( bool readwrite )
00462 {
00463
00464 m_bReadWrite = readwrite;
00465 }
00466
00467 void ReadWritePart::setModified( bool modified )
00468 {
00469 kdDebug(1000) << "ReadWritePart::setModified( " << (modified ? "true" : "false") << ")" << endl;
00470 if ( !m_bReadWrite && modified )
00471 {
00472 kdError(1000) << "Can't set a read-only document to 'modified' !" << endl;
00473 return;
00474 }
00475 m_bModified = modified;
00476 }
00477
00478 void ReadWritePart::setModified()
00479 {
00480 setModified( true );
00481 }
00482
00483 bool ReadWritePart::queryClose()
00484 {
00485 if ( !isReadWrite() || !isModified() )
00486 return true;
00487
00488 QString docName = url().fileName();
00489 if (docName.isEmpty()) docName = i18n( "Untitled" );
00490
00491 int res = KMessageBox::warningYesNoCancel( widget(),
00492 i18n( "The document \"%1\" has been modified.\n"
00493 "Do you want to save your changes or discard them?" ).arg( docName ),
00494 i18n( "Close Document" ), KStdGuiItem::save(), KStdGuiItem::discard() );
00495
00496 bool abortClose=false;
00497 bool handled=false;
00498
00499 switch(res) {
00500 case KMessageBox::Yes :
00501 sigQueryClose(&handled,&abortClose);
00502 if (!handled)
00503 {
00504 if (m_url.isEmpty())
00505 {
00506 KURL url = KFileDialog::getSaveURL();
00507 if (url.isEmpty())
00508 return false;
00509
00510 saveAs( url );
00511 }
00512 else
00513 {
00514 save();
00515 }
00516 } else if (abortClose) return false;
00517 return waitSaveComplete();
00518 case KMessageBox::No :
00519 return true;
00520 default :
00521 return false;
00522 }
00523 }
00524
00525 bool ReadWritePart::closeURL()
00526 {
00527 abortLoad();
00528 if ( isReadWrite() && isModified() )
00529 {
00530 if (!queryClose())
00531 return false;
00532 }
00533
00534 return ReadOnlyPart::closeURL();
00535 }
00536
00537 bool ReadWritePart::closeURL( bool promptToSave )
00538 {
00539 return promptToSave ? closeURL() : ReadOnlyPart::closeURL();
00540 }
00541
00542 bool ReadWritePart::save()
00543 {
00544 d->m_saveOk = false;
00545 if ( m_file.isEmpty() )
00546 prepareSaving();
00547 if( saveFile() )
00548 return saveToURL();
00549 else
00550 emit canceled(QString::null);
00551 return false;
00552 }
00553
00554 bool ReadWritePart::saveAs( const KURL & kurl )
00555 {
00556 if (!kurl.isValid())
00557 {
00558 kdError(1000) << "saveAs: Malformed URL " << kurl.url() << endl;
00559 return false;
00560 }
00561 d->m_duringSaveAs = true;
00562 d->m_originalURL = m_url;
00563 d->m_originalFilePath = m_file;
00564 m_url = kurl;
00565 prepareSaving();
00566 bool result = save();
00567 if (result)
00568 emit setWindowCaption( m_url.prettyURL() );
00569 else
00570 {
00571 m_url = d->m_originalURL;
00572 m_file = d->m_originalFilePath;
00573 d->m_duringSaveAs = false;
00574 d->m_originalURL = KURL();
00575 d->m_originalFilePath = QString::null;
00576 }
00577
00578 return result;
00579 }
00580
00581
00582 void ReadWritePart::prepareSaving()
00583 {
00584
00585 if ( m_url.isLocalFile() )
00586 {
00587 if ( m_bTemp )
00588 {
00589 unlink( QFile::encodeName(m_file) );
00590 m_bTemp = false;
00591 }
00592 m_file = m_url.path();
00593 }
00594 else
00595 {
00596
00597 if ( m_file.isEmpty() || !m_bTemp )
00598 {
00599 KTempFile tempFile;
00600 m_file = tempFile.name();
00601 m_bTemp = true;
00602 }
00603
00604 }
00605 }
00606
00607 bool ReadWritePart::saveToURL()
00608 {
00609 if ( m_url.isLocalFile() )
00610 {
00611 setModified( false );
00612 emit completed();
00613
00614 assert( !m_bTemp );
00615 d->m_saveOk = true;
00616 d->m_duringSaveAs = false;
00617 d->m_originalURL = KURL();
00618 d->m_originalFilePath = QString::null;
00619 return true;
00620 }
00621 else
00622 {
00623 if (d->m_uploadJob)
00624 {
00625 unlink(QFile::encodeName(d->m_uploadJob->srcURL().path()));
00626 d->m_uploadJob->kill();
00627 d->m_uploadJob = 0;
00628 }
00629 KTempFile tempFile;
00630 QString uploadFile = tempFile.name();
00631 KURL uploadUrl;
00632 uploadUrl.setPath( uploadFile );
00633 tempFile.unlink();
00634
00635 if (::link(QFile::encodeName(m_file), QFile::encodeName(uploadFile)) != 0)
00636 {
00637
00638 return false;
00639 }
00640 d->m_uploadJob = KIO::file_move( uploadUrl, m_url, -1, true );
00641 d->m_uploadJob->setWindow( widget() ? widget()->topLevelWidget() : 0 );
00642 connect( d->m_uploadJob, SIGNAL( result( KIO::Job * ) ), this, SLOT( slotUploadFinished (KIO::Job *) ) );
00643 return true;
00644 }
00645 }
00646
00647 void ReadWritePart::slotUploadFinished( KIO::Job * )
00648 {
00649 if (d->m_uploadJob->error())
00650 {
00651 unlink(QFile::encodeName(d->m_uploadJob->srcURL().path()));
00652 QString error = d->m_uploadJob->errorString();
00653 d->m_uploadJob = 0;
00654 if (d->m_duringSaveAs) {
00655 m_url = d->m_originalURL;
00656 m_file = d->m_originalFilePath;
00657 }
00658 emit canceled( error );
00659 }
00660 else
00661 {
00662 KDirNotify_stub allDirNotify("*", "KDirNotify*");
00663 KURL dirUrl( m_url );
00664 dirUrl.setPath( dirUrl.directory() );
00665 allDirNotify.FilesAdded( dirUrl );
00666
00667 d->m_uploadJob = 0;
00668 setModified( false );
00669 emit completed();
00670 d->m_saveOk = true;
00671 }
00672 d->m_duringSaveAs = false;
00673 d->m_originalURL = KURL();
00674 d->m_originalFilePath = QString::null;
00675 if (d->m_waitForSave)
00676 {
00677 qApp->exit_loop();
00678 }
00679 }
00680
00681
00682 void qt_enter_modal( QWidget *widget );
00683 void qt_leave_modal( QWidget *widget );
00684
00685 bool ReadWritePart::waitSaveComplete()
00686 {
00687 if (!d->m_uploadJob)
00688 return d->m_saveOk;
00689
00690 d->m_waitForSave = true;
00691
00692 QWidget dummy(0,0,WType_Dialog | WShowModal);
00693 dummy.setFocusPolicy( QWidget::NoFocus );
00694 qt_enter_modal(&dummy);
00695 qApp->enter_loop();
00696 qt_leave_modal(&dummy);
00697
00698 d->m_waitForSave = false;
00699
00700 return d->m_saveOk;
00701 }
00702
00703 #include "part.moc"
00704
00705