kparts Library API Documentation

part.cpp

00001 /* This file is part of the KDE project
00002    Copyright (C) 1999 Simon Hausmann <hausmann@kde.org>
00003              (C) 1999 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., 59 Temple Place - Suite 330,
00018    Boston, MA 02111-1307, USA.
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 
00043 #include <stdio.h>
00044 #include <unistd.h>
00045 #include <assert.h>
00046 #include <kdebug.h>
00047 
00048 template class QPtrList<KXMLGUIClient>;
00049 
00050 using namespace KParts;
00051 
00052 namespace KParts
00053 {
00054 
00055 class PartBasePrivate
00056 {
00057 public:
00058   PartBasePrivate()
00059   {
00060       m_pluginLoadingMode = PartBase::LoadPlugins;
00061   }
00062   ~PartBasePrivate()
00063   {
00064   }
00065   PartBase::PluginLoadingMode m_pluginLoadingMode;
00066 };
00067 
00068 class PartPrivate
00069 {
00070 public:
00071   PartPrivate()
00072   {
00073     m_bSelectable = true;
00074   }
00075   ~PartPrivate()
00076   {
00077   }
00078 
00079   bool m_bSelectable;
00080 };
00081 }
00082 
00083 PartBase::PartBase()
00084 {
00085   d = new PartBasePrivate;
00086   m_obj = 0L;
00087 }
00088 
00089 PartBase::~PartBase()
00090 {
00091   delete d;
00092 }
00093 
00094 void PartBase::setPartObject( QObject *obj )
00095 {
00096   m_obj = obj;
00097 }
00098 
00099 QObject *PartBase::partObject() const
00100 {
00101   return m_obj;
00102 }
00103 
00104 void PartBase::setInstance( KInstance *inst )
00105 {
00106   setInstance( inst, true );
00107 }
00108 
00109 void PartBase::setInstance( KInstance *inst, bool bLoadPlugins )
00110 {
00111   KXMLGUIClient::setInstance( inst );
00112   KGlobal::locale()->insertCatalogue( inst->instanceName() );
00113   // install 'instancename'data resource type
00114   KGlobal::dirs()->addResourceType( inst->instanceName() + "data",
00115                                     KStandardDirs::kde_default( "data" )
00116                                     + QString::fromLatin1( inst->instanceName() ) + '/' );
00117   if ( bLoadPlugins )
00118     loadPlugins( m_obj, this, instance() );
00119 }
00120 
00121 void PartBase::loadPlugins( QObject *parent, KXMLGUIClient *parentGUIClient, KInstance *instance )
00122 {
00123   if( d->m_pluginLoadingMode != DoNotLoadPlugins )
00124     Plugin::loadPlugins( parent, parentGUIClient, instance, d->m_pluginLoadingMode == LoadPlugins );
00125 }
00126 
00127 void PartBase::setPluginLoadingMode( PluginLoadingMode loadingMode )
00128 {
00129     d->m_pluginLoadingMode = loadingMode;
00130 }
00131 
00132 Part::Part( QObject *parent, const char* name )
00133  : QObject( parent, name )
00134 {
00135   d = new PartPrivate;
00136   m_widget = 0L;
00137   m_manager = 0L;
00138   PartBase::setPartObject( this );
00139 }
00140 
00141 Part::~Part()
00142 {
00143   kdDebug(1000) << "Part::~Part " << this << endl;
00144 
00145   if ( m_widget )
00146   {
00147     // We need to disconnect first, to avoid calling it !
00148     disconnect( m_widget, SIGNAL( destroyed() ),
00149                 this, SLOT( slotWidgetDestroyed() ) );
00150   }
00151 
00152   if ( m_manager )
00153     m_manager->removePart(this);
00154 
00155   if ( m_widget )
00156   {
00157     kdDebug(1000) << "deleting widget " << m_widget << " " << m_widget->name() << endl;
00158     delete (QWidget*) m_widget;
00159   }
00160 
00161   delete d;
00162 }
00163 
00164 void Part::embed( QWidget * parentWidget )
00165 {
00166   if ( widget() )
00167     widget()->reparent( parentWidget, 0, QPoint( 0, 0 ), true );
00168 }
00169 
00170 QWidget *Part::widget()
00171 {
00172   return m_widget;
00173 }
00174 
00175 void Part::setManager( PartManager *manager )
00176 {
00177   m_manager = manager;
00178 }
00179 
00180 PartManager *Part::manager() const
00181 {
00182   return m_manager;
00183 }
00184 
00185 Part *Part::hitTest( QWidget *widget, const QPoint & )
00186 {
00187   if ( (QWidget *)m_widget != widget )
00188     return 0L;
00189 
00190   return this;
00191 }
00192 
00193 void Part::setWidget( QWidget *widget )
00194 {
00195   assert ( !m_widget ); // otherwise we get two connects
00196   m_widget = widget;
00197   connect( m_widget, SIGNAL( destroyed() ),
00198            this, SLOT( slotWidgetDestroyed() ) );
00199 
00200   // Tell the actionCollection() which widget its
00201   //  action shortcuts should be connected to.
00202   actionCollection()->setWidget( widget );
00203 
00204   // Since KParts objects are XML-based, shortcuts should
00205   //  be connected to the widget when the XML settings
00206   //  are processed, rather than on KAction construction.
00207   actionCollection()->setAutoConnectShortcuts( false );
00208 }
00209 
00210 void Part::setSelectable( bool selectable )
00211 {
00212   d->m_bSelectable = selectable;
00213 }
00214 
00215 bool Part::isSelectable() const
00216 {
00217   return d->m_bSelectable;
00218 }
00219 
00220 void Part::customEvent( QCustomEvent *event )
00221 {
00222   if ( PartActivateEvent::test( event ) )
00223   {
00224     partActivateEvent( (PartActivateEvent *)event );
00225     return;
00226   }
00227 
00228   if ( PartSelectEvent::test( event ) )
00229   {
00230     partSelectEvent( (PartSelectEvent *)event );
00231     return;
00232   }
00233 
00234   if ( GUIActivateEvent::test( event ) )
00235   {
00236     guiActivateEvent( (GUIActivateEvent *)event );
00237     return;
00238   }
00239 
00240   QObject::customEvent( event );
00241 }
00242 
00243 void Part::partActivateEvent( PartActivateEvent * )
00244 {
00245 }
00246 
00247 void Part::partSelectEvent( PartSelectEvent * )
00248 {
00249 }
00250 
00251 void Part::guiActivateEvent( GUIActivateEvent * )
00252 {
00253 }
00254 
00255 QWidget *Part::hostContainer( const QString &containerName )
00256 {
00257   if ( !factory() )
00258     return 0L;
00259 
00260   return factory()->container( containerName, this );
00261 }
00262 
00263 void Part::slotWidgetDestroyed()
00264 {
00265   kdDebug(1000) << "KPart::slotWidgetDestroyed(), deleting part " << name() << endl;
00266   m_widget = 0;
00267   delete this;
00268 }
00269 
00271 
00272 namespace KParts
00273 {
00274 
00275 class ReadOnlyPartPrivate
00276 {
00277 public:
00278   ReadOnlyPartPrivate()
00279   {
00280     m_job = 0L;
00281     m_uploadJob = 0L;
00282     m_showProgressInfo = true;
00283     m_saveOk = false;
00284     m_waitForSave = false;
00285     m_duringSaveAs = false;
00286   }
00287   ~ReadOnlyPartPrivate()
00288   {
00289   }
00290 
00291   KIO::FileCopyJob * m_job;
00292   KIO::FileCopyJob * m_uploadJob;
00293   KURL m_originalURL;
00294   bool m_showProgressInfo : 1;
00295   bool m_saveOk : 1;
00296   bool m_waitForSave : 1;
00297   bool m_duringSaveAs : 1;
00298 };
00299 
00300 }
00301 
00302 ReadOnlyPart::ReadOnlyPart( QObject *parent, const char *name )
00303  : Part( parent, name ), m_bTemp( false )
00304 {
00305   d = new ReadOnlyPartPrivate;
00306 }
00307 
00308 ReadOnlyPart::~ReadOnlyPart()
00309 {
00310   ReadOnlyPart::closeURL();
00311   delete d;
00312 }
00313 
00314 void ReadOnlyPart::setProgressInfoEnabled( bool show )
00315 {
00316   d->m_showProgressInfo = show;
00317 }
00318 
00319 bool ReadOnlyPart::isProgressInfoEnabled() const
00320 {
00321   return d->m_showProgressInfo;
00322 }
00323 
00324 #ifndef KDE_NO_COMPAT
00325 void ReadOnlyPart::showProgressInfo( bool show )
00326 {
00327   d->m_showProgressInfo = show;
00328 }
00329 #endif
00330 
00331 bool ReadOnlyPart::openURL( const KURL &url )
00332 {
00333   if ( !url.isValid() )
00334     return false;
00335   if ( !closeURL() )
00336     return false;
00337   m_url = url;
00338   if ( m_url.isLocalFile() )
00339   {
00340     emit started( 0 );
00341     m_file = m_url.path();
00342     bool ret = openFile();
00343     if (ret)
00344     {
00345         emit completed();
00346         emit setWindowCaption( m_url.prettyURL() );
00347     };
00348     return ret;
00349   }
00350   else
00351   {
00352     m_bTemp = true;
00353     // Use same extension as remote file. This is important for mimetype-determination (e.g. koffice)
00354     QString fileName = url.fileName();
00355     QFileInfo fileInfo(fileName);
00356     QString ext = fileInfo.extension();
00357     QString extension;
00358     if ( !ext.isEmpty() && url.query().isNull() ) // not if the URL has a query, e.g. cgi.pl?something
00359         extension = "."+ext; // keep the '.'
00360     KTempFile tempFile( QString::null, extension );
00361     m_file = tempFile.name();
00362 
00363     KURL destURL;
00364     destURL.setPath( m_file );
00365     d->m_job = KIO::file_copy( m_url, destURL, 0600, true, false, d->m_showProgressInfo );
00366     d->m_job->setWindow( widget() ? widget()->topLevelWidget() : 0 );
00367     emit started( d->m_job );
00368     connect( d->m_job, SIGNAL( result( KIO::Job * ) ), this, SLOT( slotJobFinished ( KIO::Job * ) ) );
00369     return true;
00370   }
00371 }
00372 
00373 void ReadOnlyPart::abortLoad()
00374 {
00375   if ( d->m_job )
00376   {
00377     //kdDebug(1000) << "Aborting job " << d->m_job << endl;
00378     d->m_job->kill();
00379     d->m_job = 0;
00380   }
00381 }
00382 
00383 bool ReadOnlyPart::closeURL()
00384 {
00385   abortLoad(); //just in case
00386 
00387   if ( m_bTemp )
00388   {
00389     unlink( QFile::encodeName(m_file) );
00390     m_bTemp = false;
00391   }
00392   // It always succeeds for a read-only part,
00393   // but the return value exists for reimplementations
00394   // (e.g. pressing cancel for a modified read-write part)
00395   return true;
00396 }
00397 
00398 void ReadOnlyPart::slotJobFinished( KIO::Job * job )
00399 {
00400   kdDebug(1000) << "ReadOnlyPart::slotJobFinished" << endl;
00401   assert( job == d->m_job );
00402   d->m_job = 0;
00403   if (job->error())
00404     emit canceled( job->errorString() );
00405   else
00406   {
00407     if ( openFile() )
00408       emit setWindowCaption( m_url.prettyURL() );
00409     emit completed();
00410   }
00411 }
00412 
00413 void ReadOnlyPart::guiActivateEvent( GUIActivateEvent * event )
00414 {
00415   if (event->activated())
00416   {
00417     if (!m_url.isEmpty())
00418     {
00419       kdDebug(1000) << "ReadOnlyPart::guiActivateEvent -> " << m_url.prettyURL() << endl;
00420       emit setWindowCaption( m_url.prettyURL() );
00421     } else emit setWindowCaption( "" );
00422   }
00423 }
00424 
00425 bool ReadOnlyPart::openStream( const QString& mimeType, const KURL& url )
00426 {
00427     if ( !closeURL() )
00428         return false;
00429     m_url = url;
00430     return doOpenStream( mimeType );
00431 }
00432 
00433 bool ReadOnlyPart::writeStream( const QByteArray& data )
00434 {
00435     return doWriteStream( data );
00436 }
00437 
00438 bool ReadOnlyPart::closeStream()
00439 {
00440     return doCloseStream();
00441 }
00442 
00444 
00445 ReadWritePart::ReadWritePart( QObject *parent, const char *name )
00446  : ReadOnlyPart( parent, name ), m_bModified( false ), m_bClosing( false )
00447 {
00448   m_bReadWrite = true;
00449 }
00450 
00451 ReadWritePart::~ReadWritePart()
00452 {
00453   // parent destructor will delete temp file
00454   // we can't call our own closeURL() here, because
00455   // "cancel" wouldn't cancel anything. We have to assume
00456   // the app called closeURL() before destroying us.
00457 }
00458 
00459 void ReadWritePart::setReadWrite( bool readwrite )
00460 {
00461   // Perhaps we should check isModified here and issue a warning if true
00462   m_bReadWrite = readwrite;
00463 }
00464 
00465 void ReadWritePart::setModified( bool modified )
00466 {
00467   kdDebug(1000) << "ReadWritePart::setModified( " << (modified ? "true" : "false") << ")" << endl;
00468   if ( !m_bReadWrite && modified )
00469   {
00470       kdError(1000) << "Can't set a read-only document to 'modified' !" << endl;
00471       return;
00472   }
00473   m_bModified = modified;
00474 }
00475 
00476 void ReadWritePart::setModified()
00477 {
00478   setModified( true );
00479 }
00480 
00481 bool ReadWritePart::queryClose()
00482 {
00483   if ( !isReadWrite() || !isModified() )
00484     return true;
00485 
00486   QString docName = url().fileName();
00487   if (docName.isEmpty()) docName = i18n( "Untitled" );
00488 
00489   int res = KMessageBox::warningYesNoCancel( widget(),
00490           i18n( "The document \"%1\" has been modified.\n"
00491                 "Do you want to save it?" ).arg( docName ),
00492           i18n( "Save Document?" ), KStdGuiItem::save(), KStdGuiItem::discard() );
00493 
00494   bool abortClose=false;
00495   bool handled=false;
00496 
00497   switch(res) {
00498   case KMessageBox::Yes :
00499     sigQueryClose(&handled,&abortClose);
00500     if (!handled)
00501     {
00502       if (m_url.isEmpty())
00503       {
00504           KURL url = KFileDialog::getSaveURL();
00505           if (url.isEmpty())
00506             return false;
00507 
00508           saveAs( url );
00509       }
00510       else
00511       {
00512           save();
00513       }
00514     } else if (abortClose) return false;
00515     return waitSaveComplete();
00516   case KMessageBox::No :
00517     return true;
00518   default : // case KMessageBox::Cancel :
00519     return false;
00520   }
00521 }
00522 
00523 bool ReadWritePart::closeURL()
00524 {
00525   abortLoad(); //just in case
00526   if ( isReadWrite() && isModified() )
00527   {
00528     if (!queryClose())
00529        return false;
00530   }
00531   // Not modified => ok and delete temp file.
00532   return ReadOnlyPart::closeURL();
00533 }
00534 
00535 bool ReadWritePart::closeURL( bool promptToSave )
00536 {
00537   return promptToSave ? closeURL() : ReadOnlyPart::closeURL();
00538 }
00539 
00540 bool ReadWritePart::save()
00541 {
00542   d->m_saveOk = false;
00543   if( saveFile() )
00544     return saveToURL();
00545   return false;
00546 }
00547 
00548 bool ReadWritePart::saveAs( const KURL & kurl )
00549 {
00550   if (!kurl.isValid())
00551   {
00552       kdError(1000) << "saveAs: Malformed URL" << kurl.url() << endl;
00553       return false;
00554   }
00555   d->m_duringSaveAs = true;
00556   d->m_originalURL = m_url;
00557   m_url = kurl; // Store where to upload in saveToURL
00558   // Local file
00559   if ( m_url.isLocalFile() )
00560   {
00561     if ( m_bTemp ) // get rid of a possible temp file first
00562     {              // (happens if previous url was remote)
00563       unlink( QFile::encodeName(m_file) );
00564       m_bTemp = false;
00565     }
00566     m_file = m_url.path();
00567   }
00568   else
00569   { // Remote file
00570     // We haven't saved yet, or we did but locally - provide a temp file
00571     if ( m_file.isEmpty() || !m_bTemp )
00572     {
00573       KTempFile tempFile;
00574       m_file = tempFile.name();
00575       m_bTemp = true;
00576     }
00577     // otherwise, we already had a temp file
00578   }
00579   bool result = save(); // Save local file and upload local file
00580   if (result)
00581     emit setWindowCaption( m_url.prettyURL() );
00582   else
00583   {  
00584     m_url = d->m_originalURL;    
00585     d->m_duringSaveAs = false;
00586     d->m_originalURL = KURL();
00587   }
00588       
00589   return result;    
00590 }
00591 
00592 bool ReadWritePart::saveToURL()
00593 {
00594   if ( m_url.isLocalFile() )
00595   {
00596     setModified( false );
00597     emit completed();
00598     // if m_url is a local file there won't be a temp file -> nothing to remove
00599     assert( !m_bTemp );
00600     d->m_saveOk = true;
00601     d->m_duringSaveAs = false;
00602     d->m_originalURL = KURL();
00603     return true; // Nothing to do
00604   }
00605   else
00606   {
00607     if (d->m_uploadJob)
00608     {
00609        unlink(QFile::encodeName(d->m_uploadJob->srcURL().path()));
00610        d->m_uploadJob->kill();
00611        d->m_uploadJob = 0;
00612     }
00613     KTempFile tempFile;
00614     QString uploadFile = tempFile.name();
00615     tempFile.unlink();
00616     // Create hardlink
00617     if (::link(QFile::encodeName(m_file), QFile::encodeName(uploadFile)) != 0)
00618     {
00619        // Uh oh, some error happened.
00620        return false;
00621     }
00622     d->m_uploadJob = KIO::file_move( uploadFile, m_url, -1, true /*overwrite*/ );
00623     d->m_uploadJob->setWindow( widget() ? widget()->topLevelWidget() : 0 );
00624     connect( d->m_uploadJob, SIGNAL( result( KIO::Job * ) ), this, SLOT( slotUploadFinished (KIO::Job *) ) );
00625     return true;
00626   }
00627 }
00628 
00629 void ReadWritePart::slotUploadFinished( KIO::Job * )
00630 {
00631   if (d->m_uploadJob->error())
00632   {
00633     unlink(QFile::encodeName(d->m_uploadJob->srcURL().path()));
00634     QString error = d->m_uploadJob->errorString();
00635     d->m_uploadJob = 0;
00636     if (d->m_duringSaveAs)
00637       m_url = d->m_originalURL;
00638     emit canceled( error );
00639   }
00640   else
00641   {
00642     d->m_uploadJob = 0;
00643     setModified( false );
00644     emit completed();
00645     d->m_saveOk = true;
00646   }
00647   d->m_duringSaveAs = false;
00648   d->m_originalURL = KURL();
00649   if (d->m_waitForSave)
00650   {
00651      qApp->exit_loop();
00652   }
00653 }
00654 
00655 // Trolls: Nothing to see here, please step away.
00656 void qt_enter_modal( QWidget *widget );
00657 void qt_leave_modal( QWidget *widget );
00658 
00659 bool ReadWritePart::waitSaveComplete()
00660 {
00661   if (!d->m_uploadJob)
00662      return d->m_saveOk;
00663 
00664   d->m_waitForSave = true;
00665 
00666   QWidget dummy(0,0,WType_Dialog | WShowModal);
00667   dummy.setFocusPolicy( QWidget::NoFocus );
00668   qt_enter_modal(&dummy);
00669   qApp->enter_loop();
00670   qt_leave_modal(&dummy);
00671 
00672   d->m_waitForSave = false;
00673 
00674   return d->m_saveOk;
00675 }
00676 
00677 #include "part.moc"
00678 
00679 // vim:sw=2:ts=8:et
KDE Logo
This file is part of the documentation for kparts Library Version 3.2.3.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed Aug 4 05:27:01 2004 by doxygen 1.3.4 written by Dimitri van Heesch, © 1997-2003