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