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 Sun Oct 10 18:55:40 2004 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003