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 <qfile.h>
00028 #include <qpoint.h>
00029 #include <qpointarray.h>
00030 #include <qpainter.h>
00031 #include <qtextstream.h>
00032 
00033 #include <kinstance.h>
00034 #include <klocale.h>
00035 #include <ktempfile.h>
00036 #include <kmessagebox.h>
00037 #include <kio/job.h>
00038 #include <kstandarddirs.h>
00039 #include <kfiledialog.h>
00040 
00041 #include <stdio.h>
00042 #include <unistd.h>
00043 #include <assert.h>
00044 #include <kdebug.h>
00045 
00046 template class QPtrList<KXMLGUIClient>;
00047 
00048 using namespace KParts;
00049 
00050 namespace KParts
00051 {
00052 
00053 class PartBasePrivate
00054 {
00055 public:
00056   PartBasePrivate()
00057   {
00058       m_pluginLoadingMode = PartBase::LoadPlugins;
00059   }
00060   ~PartBasePrivate()
00061   {
00062   }
00063   PartBase::PluginLoadingMode m_pluginLoadingMode;
00064 };
00065 
00066 class PartPrivate
00067 {
00068 public:
00069   PartPrivate()
00070   {
00071     m_bSelectable = true;
00072   }
00073   ~PartPrivate()
00074   {
00075   }
00076 
00077   bool m_bSelectable;
00078 };
00079 };
00080 
00081 PartBase::PartBase()
00082 {
00083   d = new PartBasePrivate;
00084   m_obj = 0L;
00085 }
00086 
00087 PartBase::~PartBase()
00088 {
00089   delete d;
00090 }
00091 
00092 void PartBase::setPartObject( QObject *obj )
00093 {
00094   m_obj = obj;
00095 }
00096 
00097 QObject *PartBase::partObject() const
00098 {
00099   return m_obj;
00100 }
00101 
00102 void PartBase::setInstance( KInstance *inst )
00103 {
00104   setInstance( inst, true );
00105 }
00106 
00107 void PartBase::setInstance( KInstance *inst, bool bLoadPlugins )
00108 {
00109   KXMLGUIClient::setInstance( inst );
00110   KGlobal::locale()->insertCatalogue( inst->instanceName() );
00111   // install 'instancename'data resource type
00112   KGlobal::dirs()->addResourceType( inst->instanceName() + "data",
00113                                     KStandardDirs::kde_default( "data" )
00114                                     + QString::fromLatin1( inst->instanceName() ) + '/' );
00115   if ( bLoadPlugins )
00116     loadPlugins( m_obj, this, instance() );
00117 }
00118 
00119 void PartBase::loadPlugins( QObject *parent, KXMLGUIClient *parentGUIClient, KInstance *instance )
00120 {
00121   if( d->m_pluginLoadingMode != DoNotLoadPlugins )
00122     Plugin::loadPlugins( parent, parentGUIClient, instance, d->m_pluginLoadingMode == LoadPlugins );
00123 }
00124 
00125 void PartBase::setPluginLoadingMode( PluginLoadingMode loadingMode )
00126 {
00127     d->m_pluginLoadingMode = loadingMode;
00128 }
00129 
00130 Part::Part( QObject *parent, const char* name )
00131  : QObject( parent, name )
00132 {
00133   d = new PartPrivate;
00134   m_widget = 0L;
00135   m_manager = 0L;
00136   PartBase::setPartObject( this );
00137 }
00138 
00139 Part::~Part()
00140 {
00141   kdDebug(1000) << "Part::~Part " << this << endl;
00142 
00143   if ( m_widget )
00144   {
00145     // We need to disconnect first, to avoid calling it !
00146     disconnect( m_widget, SIGNAL( destroyed() ),
00147                 this, SLOT( slotWidgetDestroyed() ) );
00148   }
00149 
00150   if ( m_manager )
00151     m_manager->removePart(this);
00152 
00153   if ( m_widget )
00154   {
00155     kdDebug(1000) << "deleting widget " << m_widget << " " << m_widget->name() << endl;
00156     delete (QWidget*) m_widget;
00157   }
00158 
00159   delete d;
00160 }
00161 
00162 void Part::embed( QWidget * parentWidget )
00163 {
00164   if ( widget() )
00165     widget()->reparent( parentWidget, 0, QPoint( 0, 0 ), true );
00166 }
00167 
00168 QWidget *Part::widget()
00169 {
00170   return m_widget;
00171 }
00172 
00173 void Part::setManager( PartManager *manager )
00174 {
00175   m_manager = manager;
00176 }
00177 
00178 PartManager *Part::manager() const
00179 {
00180   return m_manager;
00181 }
00182 
00183 Part *Part::hitTest( QWidget *widget, const QPoint & )
00184 {
00185   if ( (QWidget *)m_widget != widget )
00186     return 0L;
00187 
00188   return this;
00189 }
00190 
00191 void Part::setWidget( QWidget *widget )
00192 {
00193   assert ( !m_widget ); // otherwise we get two connects
00194   m_widget = widget;
00195   connect( m_widget, SIGNAL( destroyed() ),
00196            this, SLOT( slotWidgetDestroyed() ) );
00197 
00198   // Tell the actionCollection() which widget its
00199   //  action shortcuts should be connected to.
00200   actionCollection()->setWidget( widget );
00201 
00202   // Since KParts objects are XML-based, shortcuts should
00203   //  be connected to the widget when the XML settings
00204   //  are processed, rather than on KAction construction.
00205   actionCollection()->setAutoConnectShortcuts( false );
00206 }
00207 
00208 void Part::setSelectable( bool selectable )
00209 {
00210   d->m_bSelectable = selectable;
00211 }
00212 
00213 bool Part::isSelectable() const
00214 {
00215   return d->m_bSelectable;
00216 }
00217 
00218 void Part::customEvent( QCustomEvent *event )
00219 {
00220   if ( PartActivateEvent::test( event ) )
00221   {
00222     partActivateEvent( (PartActivateEvent *)event );
00223     return;
00224   }
00225 
00226   if ( PartSelectEvent::test( event ) )
00227   {
00228     partSelectEvent( (PartSelectEvent *)event );
00229     return;
00230   }
00231 
00232   if ( GUIActivateEvent::test( event ) )
00233   {
00234     guiActivateEvent( (GUIActivateEvent *)event );
00235     return;
00236   }
00237 
00238   QObject::customEvent( event );
00239 }
00240 
00241 void Part::partActivateEvent( PartActivateEvent * )
00242 {
00243 }
00244 
00245 void Part::partSelectEvent( PartSelectEvent * )
00246 {
00247 }
00248 
00249 void Part::guiActivateEvent( GUIActivateEvent * )
00250 {
00251 }
00252 
00253 QWidget *Part::hostContainer( const QString &containerName )
00254 {
00255   if ( !factory() )
00256     return 0L;
00257 
00258   return factory()->container( containerName, this );
00259 }
00260 
00261 void Part::slotWidgetDestroyed()
00262 {
00263   kdDebug(1000) << "KPart::slotWidgetDestroyed(), deleting part " << name() << endl;
00264   m_widget = 0;
00265   delete this;
00266 }
00267 
00269 
00270 namespace KParts
00271 {
00272 
00273 class ReadOnlyPartPrivate
00274 {
00275 public:
00276   ReadOnlyPartPrivate()
00277   {
00278     m_job = 0L;
00279     m_showProgressInfo = true;
00280   }
00281   ~ReadOnlyPartPrivate()
00282   {
00283   }
00284 
00285   KIO::FileCopyJob * m_job;
00286   bool m_showProgressInfo;
00287 };
00288 
00289 };
00290 
00291 ReadOnlyPart::ReadOnlyPart( QObject *parent, const char *name )
00292  : Part( parent, name ), m_bTemp( false )
00293 {
00294   d = new ReadOnlyPartPrivate;
00295 }
00296 
00297 ReadOnlyPart::~ReadOnlyPart()
00298 {
00299   ReadOnlyPart::closeURL();
00300   delete d;
00301 }
00302 
00303 void ReadOnlyPart::setProgressInfoEnabled( bool show )
00304 {
00305   d->m_showProgressInfo = show;
00306 }
00307 
00308 bool ReadOnlyPart::isProgressInfoEnabled() const
00309 {
00310   return d->m_showProgressInfo;
00311 }
00312 
00313 #ifndef KDE_NO_COMPAT
00314 void ReadOnlyPart::showProgressInfo( bool show )
00315 {
00316   d->m_showProgressInfo = show;
00317 }
00318 #endif
00319 
00320 bool ReadOnlyPart::openURL( const KURL &url )
00321 {
00322   if ( url.isMalformed() )
00323     return false;
00324   if ( !closeURL() )
00325     return false;
00326   m_url = url;
00327   emit setWindowCaption( m_url.prettyURL() );
00328   if ( m_url.isLocalFile() )
00329   {
00330     emit started( 0 );
00331     m_file = m_url.path();
00332     bool ret = openFile();
00333     if (ret)
00334         emit completed();
00335     return ret;
00336   }
00337   else
00338   {
00339     m_bTemp = true;
00340     // Use same extension as remote file. This is important for mimetype-determination (e.g. koffice)
00341     QString extension;
00342     QString fileName = url.fileName();
00343     int extensionPos = fileName.findRev( '.' );
00344     if ( extensionPos != -1 && url.query().isNull() ) // not if the URL has a query, e.g. cgi.pl?something
00345         extension = fileName.mid( extensionPos ); // keep the '.'
00346     KTempFile tempFile( QString::null, extension );
00347     m_file = tempFile.name();
00348 
00349     KURL destURL;
00350     destURL.setPath( m_file );
00351     d->m_job = KIO::file_copy( m_url, destURL, 0600, true, false, d->m_showProgressInfo );
00352     emit started( d->m_job );
00353     connect( d->m_job, SIGNAL( result( KIO::Job * ) ), this, SLOT( slotJobFinished ( KIO::Job * ) ) );
00354     return true;
00355   }
00356 }
00357 
00358 void ReadOnlyPart::abortLoad()
00359 {
00360   if ( d->m_job )
00361   {
00362     //kdDebug(1000) << "Aborting job " << d->m_job << endl;
00363     d->m_job->kill();
00364     d->m_job = 0;
00365   }
00366 }
00367 
00368 bool ReadOnlyPart::closeURL()
00369 {
00370   abortLoad(); //just in case
00371 
00372   if ( m_bTemp )
00373   {
00374     unlink( QFile::encodeName(m_file) );
00375     m_bTemp = false;
00376   }
00377   // It always succeeds for a read-only part,
00378   // but the return value exists for reimplementations
00379   // (e.g. pressing cancel for a modified read-write part)
00380   return true;
00381 }
00382 
00383 void ReadOnlyPart::slotJobFinished( KIO::Job * job )
00384 {
00385   kdDebug(1000) << "ReadOnlyPart::slotJobFinished" << endl;
00386   assert( job == d->m_job );
00387   d->m_job = 0;
00388   if (job->error())
00389     emit canceled( job->errorString() );
00390   else
00391   {
00392     openFile();
00393     emit completed();
00394   }
00395 }
00396 
00397 void ReadOnlyPart::guiActivateEvent( GUIActivateEvent * event )
00398 {
00399   if (event->activated())
00400   {
00401     if (!m_url.isEmpty())
00402     {
00403       kdDebug(1000) << "ReadOnlyPart::guiActivateEvent -> " << m_url.prettyURL() << endl;
00404       emit setWindowCaption( m_url.prettyURL() );
00405     } else emit setWindowCaption( "" );
00406   }
00407 }
00408 
00409 bool ReadOnlyPart::openStream( const QString& mimeType, const KURL& url )
00410 {
00411     if ( !closeURL() )
00412         return false;
00413     m_url = url;
00414     return doOpenStream( mimeType );
00415 }
00416 
00417 bool ReadOnlyPart::writeStream( const QByteArray& data )
00418 {
00419     return doWriteStream( data );
00420 }
00421 
00422 bool ReadOnlyPart::closeStream()
00423 {
00424     return doCloseStream();
00425 }
00426 
00428 
00429 ReadWritePart::ReadWritePart( QObject *parent, const char *name )
00430  : ReadOnlyPart( parent, name ), m_bModified( false ), m_bClosing( false )
00431 {
00432   m_bReadWrite = true;
00433 }
00434 
00435 ReadWritePart::~ReadWritePart()
00436 {
00437   // parent destructor will delete temp file
00438   // we can't call our own closeURL() here, because
00439   // "cancel" wouldn't cancel anything. We have to assume
00440   // the app called closeURL() before destroying us.
00441 }
00442 
00443 void ReadWritePart::setReadWrite( bool readwrite )
00444 {
00445   // Perhaps we should check isModified here and issue a warning if true
00446   m_bReadWrite = readwrite;
00447 }
00448 
00449 void ReadWritePart::setModified( bool modified )
00450 {
00451   kdDebug(1000) << "ReadWritePart::setModified( " << (modified ? "true" : "false") << ")" << endl;
00452   if ( !m_bReadWrite && modified )
00453   {
00454       kdError(1000) << "Can't set a read-only document to 'modified' !" << endl;
00455       return;
00456   }
00457   m_bModified = modified;
00458 }
00459 
00460 void ReadWritePart::setModified()
00461 {
00462   setModified( true );
00463 }
00464 
00465 bool ReadWritePart::closeURL()
00466 {
00467   abortLoad(); //just in case
00468   if ( m_bModified && m_bReadWrite )
00469   {
00470     int res = KMessageBox::warningYesNoCancel( widget(),
00471             i18n( "The document \"%1\" has been modified.\n"
00472                   "Do you want to save it?" ).arg( url().fileName() ),
00473             i18n( "Save Document?" ), KStdGuiItem::save(), KStdGuiItem::discard() );
00474 
00475     switch(res) {
00476     case KMessageBox::Yes :
00477       m_bClosing = true; // remember to clean up the temp file
00478       if (m_url.isEmpty())
00479       {
00480           KURL url = KFileDialog::getSaveURL();
00481           if (url.isEmpty())
00482           {
00483             m_bClosing = false;
00484             return false;
00485           }
00486           return saveAs( url );
00487       }
00488       return save();
00489     case KMessageBox::No :
00490       setModified( false ); // the user isn't interested in the changes, forget them
00491       return true;
00492     default : // case KMessageBox::Cancel :
00493       return false;
00494     }
00495   }
00496   // Not modified => ok and delete temp file.
00497   return ReadOnlyPart::closeURL();
00498 }
00499 
00500 bool ReadWritePart::save()
00501 {
00502   if( saveFile() )
00503     return saveToURL();
00504   m_bClosing = false;
00505   return false;
00506 }
00507 
00508 bool ReadWritePart::saveAs( const KURL & kurl )
00509 {
00510   if (kurl.isMalformed())
00511   {
00512       kdError(1000) << "saveAs: Malformed URL" << kurl.url() << endl;
00513       m_bClosing = false;
00514       return false;
00515   }
00516   m_url = kurl; // Store where to upload in saveToURL
00517   // Local file
00518   if ( m_url.isLocalFile() )
00519   {
00520     if ( m_bTemp ) // get rid of a possible temp file first
00521     {              // (happens if previous url was remote)
00522       unlink( QFile::encodeName(m_file) );
00523       m_bTemp = false;
00524     }
00525     m_file = m_url.path();
00526   }
00527   else
00528   { // Remote file
00529     // We haven't saved yet, or we did but locally - provide a temp file
00530     if ( m_file.isEmpty() || !m_bTemp )
00531     {
00532       KTempFile tempFile;
00533       m_file = tempFile.name();
00534       m_bTemp = true;
00535     }
00536     // otherwise, we already had a temp file
00537   }
00538   emit setWindowCaption( m_url.prettyURL() );
00539   return save(); // Save local file and upload local file
00540 }
00541 
00542 bool ReadWritePart::saveToURL()
00543 {
00544   if ( m_url.isLocalFile() )
00545   {
00546     setModified( false );
00547     emit completed();
00548     // if m_url is a local file there won't be a temp file -> nothing to remove
00549     assert( !m_bTemp );
00550     m_bClosing = false; // no temp file to cleaned up
00551     return true; // Nothing to do
00552   }
00553   else
00554   {
00555     KIO::Job * job = KIO::file_copy( m_file, m_url, -1, true /*overwrite*/ );
00556     connect( job, SIGNAL( result( KIO::Job * ) ), this, SLOT( slotUploadFinished (KIO::Job *) ) );
00557     return true;
00558   }
00559 }
00560 
00561 void ReadWritePart::slotUploadFinished( KIO::Job * job )
00562 {
00563   if (job->error())
00564     emit canceled( job->errorString() );
00565   else
00566   {
00567     setModified( false );
00568     if ( m_bClosing && m_bTemp ) // We're finished with this document -> remove temp file
00569     {
00570       unlink( QFile::encodeName(m_file) );
00571       m_bTemp = false;
00572     }
00573     emit completed();
00574   }
00575   m_bClosing = false; // temp file was cleaned up
00576 }
00577 
00578 #include "part.moc"
00579 
00580 // vim:sw=2:ts=8:et
KDE Logo
This file is part of the documentation for kdelibs Version 3.1.0.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Wed Oct 8 12:21:45 2003 by doxygen 1.2.18 written by Dimitri van Heesch, © 1997-2001