• Skip to content
  • Skip to link menu
KDE 3.5 API Reference
  • KDE API Reference
  • API Reference
  • Sitemap
  • Contact Us
 

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 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 <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   // install 'instancename'data resource type
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     // We need to disconnect first, to avoid calling it !
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 ); // otherwise we get two connects
00197   m_widget = widget;
00198   connect( m_widget, SIGNAL( destroyed() ),
00199            this, SLOT( slotWidgetDestroyed() ) );
00200 
00201   // Tell the actionCollection() which widget its
00202   //  action shortcuts should be connected to.
00203   actionCollection()->setWidget( widget );
00204 
00205   // Since KParts objects are XML-based, shortcuts should
00206   //  be connected to the widget when the XML settings
00207   //  are processed, rather than on KAction construction.
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; // for saveAs
00295   QString m_originalFilePath; // for saveAs
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     // Use same extension as remote file. This is important for mimetype-determination (e.g. koffice)
00356     QString fileName = url.fileName();
00357     QFileInfo fileInfo(fileName);
00358     QString ext = fileInfo.extension();
00359     QString extension;
00360     if ( !ext.isEmpty() && url.query().isNull() ) // not if the URL has a query, e.g. cgi.pl?something
00361         extension = "."+ext; // keep the '.'
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     //kdDebug(1000) << "Aborting job " << d->m_job << endl;
00380     d->m_job->kill();
00381     d->m_job = 0;
00382   }
00383 }
00384 
00385 bool ReadOnlyPart::closeURL()
00386 {
00387   abortLoad(); //just in case
00388 
00389   if ( m_bTemp )
00390   {
00391     unlink( QFile::encodeName(m_file) );
00392     m_bTemp = false;
00393   }
00394   // It always succeeds for a read-only part,
00395   // but the return value exists for reimplementations
00396   // (e.g. pressing cancel for a modified read-write part)
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   // parent destructor will delete temp file
00456   // we can't call our own closeURL() here, because
00457   // "cancel" wouldn't cancel anything. We have to assume
00458   // the app called closeURL() before destroying us.
00459 }
00460 
00461 void ReadWritePart::setReadWrite( bool readwrite )
00462 {
00463   // Perhaps we should check isModified here and issue a warning if true
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 : // case KMessageBox::Cancel :
00521     return false;
00522   }
00523 }
00524 
00525 bool ReadWritePart::closeURL()
00526 {
00527   abortLoad(); //just in case
00528   if ( isReadWrite() && isModified() )
00529   {
00530     if (!queryClose())
00531        return false;
00532   }
00533   // Not modified => ok and delete temp file.
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() ) // document was created empty
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; // Store where to upload in saveToURL
00565   prepareSaving();
00566   bool result = save(); // Save local file and upload local file
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 // Set m_file correctly for m_url
00582 void ReadWritePart::prepareSaving()
00583 {
00584   // Local file
00585   if ( m_url.isLocalFile() )
00586   {
00587     if ( m_bTemp ) // get rid of a possible temp file first
00588     {              // (happens if previous url was remote)
00589       unlink( QFile::encodeName(m_file) );
00590       m_bTemp = false;
00591     }
00592     m_file = m_url.path();
00593   }
00594   else
00595   { // Remote file
00596     // We haven't saved yet, or we did but locally - provide a temp file
00597     if ( m_file.isEmpty() || !m_bTemp )
00598     {
00599       KTempFile tempFile;
00600       m_file = tempFile.name();
00601       m_bTemp = true;
00602     }
00603     // otherwise, we already had a temp file
00604   }
00605 }
00606 
00607 bool ReadWritePart::saveToURL()
00608 {
00609   if ( m_url.isLocalFile() )
00610   {
00611     setModified( false );
00612     emit completed();
00613     // if m_url is a local file there won't be a temp file -> nothing to remove
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; // Nothing to do
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     // Create hardlink
00635     if (::link(QFile::encodeName(m_file), QFile::encodeName(uploadFile)) != 0)
00636     {
00637        // Uh oh, some error happened.
00638        return false;
00639     }
00640     d->m_uploadJob = KIO::file_move( uploadUrl, m_url, -1, true /*overwrite*/ );
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 // Trolls: Nothing to see here, please step away.
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 // vim:sw=2:ts=8:et

KParts

Skip menu "KParts"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

API Reference

Skip menu "API Reference"
  • dcop
  • DNSSD
  • interfaces
  • Kate
  • kconf_update
  • KDECore
  • KDED
  • kdefx
  • KDEsu
  • kdeui
  • KDocTools
  • KHTML
  • KImgIO
  • KInit
  • kio
  • kioslave
  • KJS
  • KNewStuff
  • KParts
  • KUtils
Generated for API Reference by doxygen 1.5.9
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal