lib Library API Documentation

koDocument.cc

00001 /* This file is part of the KDE project 00002 Copyright (C) 1998, 1999 Torben Weis <weis@kde.org> 00003 Copyright (C) 2000, 2001 David Faure <david@mandrakesoft.com> 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 #ifdef HAVE_CONFIG_H 00022 #include <config.h> 00023 #endif 00024 00025 #include <assert.h> 00026 #include <unistd.h> 00027 00028 #include <qbuffer.h> 00029 00030 #include <koDocument.h> 00031 #include <koDocument_p.h> 00032 #include <KoDocumentIface.h> 00033 #include <koDocumentChild.h> 00034 #include <koView.h> 00035 #include <koMainWindow.h> 00036 #include <koStoreDevice.h> 00037 #include <koFilterManager.h> 00038 #include <koDocumentInfo.h> 00039 #include <kprinter.h> 00040 00041 #include <kio/netaccess.h> 00042 #include <kio/job.h> 00043 #include <kparts/partmanager.h> 00044 #include <klocale.h> 00045 #include <kmimetype.h> 00046 #include <kapplication.h> 00047 #include <kdebug.h> 00048 #include <kmessagebox.h> 00049 #include <kdeversion.h> 00050 #include <kfileitem.h> 00051 #if ! KDE_IS_VERSION(3,1,90) 00052 #include <kdebugclasses.h> 00053 #endif 00054 00055 #include <qfile.h> 00056 #include <qmap.h> 00057 #include <qpainter.h> 00058 #include <qtimer.h> 00059 #include <qimage.h> 00060 #include <kiconloader.h> 00061 #include <qdir.h> 00062 #include <qfileinfo.h> 00063 #include <qcursor.h> 00064 00065 // Define the protocol used here for embedded documents' URL 00066 // This used to "store" but KURL didn't like it, 00067 // so let's simply make it "tar" ! 00068 #define STORE_PROTOCOL "tar" 00069 // The internal path is a hack to make KURL happy and still pass 00070 // some kind of relative path to KoDocumentChild 00071 #define INTERNAL_PROTOCOL "intern" 00072 #define INTERNAL_PREFIX "intern:/" 00073 // Warning, keep it sync in koStore.cc and koDocumentChild.cc 00074 00075 QPtrList<KoDocument> *KoDocument::s_documentList=0L; 00076 00077 using namespace std; 00078 class KoViewWrapperWidget; 00079 00080 /********************************************************** 00081 * 00082 * KoDocument 00083 * 00084 **********************************************************/ 00085 00086 const int KoDocument::s_defaultAutoSave = 300; // 5 minutes 00087 00088 class KoDocument::Private 00089 { 00090 public: 00091 Private() : 00092 m_dcopObject( 0L ), 00093 filterManager( 0L ), 00094 m_specialOutputFlag( 0 ), 00095 m_isImporting( false ), m_isExporting( false ), 00096 m_numOperations( 0 ), 00097 modifiedAfterAutosave( false ), 00098 m_autosaving( false ), 00099 m_shouldCheckAutoSaveFile( true ), 00100 m_autoErrorHandlingEnabled( true ), 00101 m_backupFile( true ), 00102 m_backupPath( QString::null ), 00103 m_doNotSaveExtDoc( false ), 00104 m_current( false ), 00105 m_storeInternal( false ), 00106 m_initDocFlags( KoDocument::InitDocAppStarting ) 00107 { 00108 m_confirmNonNativeSave[0] = true; 00109 m_confirmNonNativeSave[1] = true; 00110 } 00111 00112 QPtrList<KoView> m_views; 00113 QPtrList<KoDocumentChild> m_children; 00114 QPtrList<KoMainWindow> m_shells; 00115 QValueList<QDomDocument> m_viewBuildDocuments; 00116 00117 KoViewWrapperWidget *m_wrapperWidget; 00118 KoDocumentIface * m_dcopObject; 00119 KoDocumentInfo *m_docInfo; 00120 00121 KoFilterManager * filterManager; // The filter-manager to use when loading/saving [for the options] 00122 00123 QCString mimeType; // The actual mimetype of the document 00124 QCString outputMimeType; // The mimetype to use when saving 00125 bool m_confirmNonNativeSave [2]; // used to pop up a dialog when saving for the 00126 // first time if the file is in a foreign format 00127 // (Save/Save As, Export) 00128 int m_specialOutputFlag; // See KoFileDialog in koMainWindow.cc 00129 bool m_isImporting, m_isExporting; // File --> Import/Export vs File --> Open/Save 00130 00131 QTimer m_autoSaveTimer; 00132 QString lastErrorMessage; // see openFile() 00133 int m_autoSaveDelay; // in seconds, 0 to disable. 00134 int m_numOperations; 00135 bool modifiedAfterAutosave; 00136 bool m_bSingleViewMode; 00137 bool m_autosaving; 00138 bool m_shouldCheckAutoSaveFile; // usually true 00139 bool m_autoErrorHandlingEnabled; // usually true 00140 bool m_backupFile; 00141 QString m_backupPath; 00142 bool m_doNotSaveExtDoc; // makes it possible to save only internally stored child documents 00143 bool m_current; 00144 bool m_storeInternal; // Store this doc internally even if url is external 00145 InitDocFlags m_initDocFlags; 00146 }; 00147 00148 // Used in singleViewMode 00149 class KoViewWrapperWidget : public QWidget 00150 { 00151 public: 00152 KoViewWrapperWidget( QWidget *parent, const char *name ) 00153 : QWidget( parent, name ) 00154 { 00155 KGlobal::locale()->insertCatalogue("koffice"); 00156 // Tell the iconloader about share/apps/koffice/icons 00157 KGlobal::iconLoader()->addAppDir("koffice"); 00158 m_view = 0L; 00159 // Avoid warning from KParts - we'll have the KoView as focus proxy anyway 00160 setFocusPolicy( ClickFocus ); 00161 } 00162 00163 virtual ~KoViewWrapperWidget() { 00164 setFocusProxy( 0 ); // to prevent a crash due to clearFocus (#53466) 00165 } 00166 00167 virtual void resizeEvent( QResizeEvent * ) 00168 { 00169 QObject *wid = child( 0, "QWidget" ); 00170 if ( wid ) 00171 static_cast<QWidget *>(wid)->setGeometry( 0, 0, width(), height() ); 00172 } 00173 00174 virtual void childEvent( QChildEvent *ev ) 00175 { 00176 if ( ev->type() == QEvent::ChildInserted ) 00177 resizeEvent( 0L ); 00178 } 00179 00180 // Called by openFile() 00181 void setKoView( KoView * view ) { 00182 m_view = view; 00183 setFocusProxy( m_view ); 00184 } 00185 KoView * koView() const { return m_view; } 00186 private: 00187 KoView* m_view; 00188 }; 00189 00190 KoBrowserExtension::KoBrowserExtension( KoDocument * doc, const char * name ) 00191 : KParts::BrowserExtension( doc, name ) 00192 { 00193 emit enableAction( "print", true ); 00194 } 00195 00196 void KoBrowserExtension::print() 00197 { 00198 KoDocument * doc = static_cast<KoDocument *>( parent() ); 00199 KoViewWrapperWidget * wrapper = static_cast<KoViewWrapperWidget *>( doc->widget() ); 00200 KoView * view = wrapper->koView(); 00201 // TODO remove code duplication (KoMainWindow), by moving this to KoView 00202 KPrinter printer; 00203 // ### TODO: apply global koffice settings here 00204 view->setupPrinter( printer ); 00205 if ( printer.setup( view ) ) 00206 view->print( printer ); 00207 } 00208 00209 KoDocument::KoDocument( QWidget * parentWidget, const char *widgetName, QObject* parent, const char* name, bool singleViewMode ) 00210 : KParts::ReadWritePart( parent, name ) 00211 { 00212 if(s_documentList==0L) 00213 s_documentList=new QPtrList<KoDocument>; 00214 s_documentList->append(this); 00215 00216 d = new Private; 00217 m_bEmpty = TRUE; 00218 connect( &d->m_autoSaveTimer, SIGNAL( timeout() ), this, SLOT( slotAutoSave() ) ); 00219 setAutoSave( s_defaultAutoSave ); 00220 d->m_bSingleViewMode = singleViewMode; 00221 00222 00223 // the parent setting *always* overrides! (Simon) 00224 if ( parent ) 00225 { 00226 if ( parent->inherits( "KoDocument" ) ) 00227 d->m_bSingleViewMode = ((KoDocument *)parent)->isSingleViewMode(); 00228 else if ( parent->inherits( "KParts::Part" ) ) 00229 d->m_bSingleViewMode = true; 00230 } 00231 00232 if ( singleViewMode ) 00233 { 00234 d->m_wrapperWidget = new KoViewWrapperWidget( parentWidget, widgetName ); 00235 setWidget( d->m_wrapperWidget ); 00236 kdDebug(30003) << "creating KoBrowserExtension" << endl; 00237 (void) new KoBrowserExtension( this ); // ## only if embedded into a browser? 00238 } 00239 00240 d->m_docInfo = new KoDocumentInfo( this, "document info" ); 00241 00242 m_pageLayout.ptWidth = 0; 00243 m_pageLayout.ptHeight = 0; 00244 m_pageLayout.ptTop = 0; 00245 m_pageLayout.ptBottom = 0; 00246 m_pageLayout.ptLeft = 0; 00247 m_pageLayout.ptRight = 0; 00248 00249 // A way to 'fix' the job's window, since we have no widget known to KParts 00250 if ( !singleViewMode ) 00251 connect( this, SIGNAL( started( KIO::Job* ) ), SLOT( slotStarted( KIO::Job* ) ) ); 00252 } 00253 00254 KoDocument::~KoDocument() 00255 { 00256 d->m_autoSaveTimer.stop(); 00257 00258 QPtrListIterator<KoDocumentChild> childIt( d->m_children ); 00259 for (; childIt.current(); ++childIt ) 00260 disconnect( childIt.current(), SIGNAL( destroyed() ), 00261 this, SLOT( slotChildDestroyed() ) ); 00262 00263 // Tell our views that the document is already destroyed and 00264 // that they shouldn't try to access it. 00265 QPtrListIterator<KoView> vIt( d->m_views ); 00266 for (; vIt.current(); ++vIt ) 00267 vIt.current()->setDocumentDeleted(); 00268 00269 d->m_children.setAutoDelete( true ); 00270 d->m_children.clear(); 00271 00272 d->m_shells.setAutoDelete( true ); 00273 d->m_shells.clear(); 00274 00275 delete d->m_dcopObject; 00276 delete d->filterManager; 00277 delete d; 00278 s_documentList->removeRef(this); 00279 // last one? 00280 if(s_documentList->isEmpty()) { 00281 delete s_documentList; 00282 s_documentList=0; 00283 } 00284 } 00285 00286 bool KoDocument::isSingleViewMode() const 00287 { 00288 return d->m_bSingleViewMode; 00289 } 00290 00291 bool KoDocument::isEmbedded() const 00292 { 00293 return dynamic_cast<KoDocument *>( parent() ) != 0; 00294 } 00295 00296 KoView *KoDocument::createView( QWidget *parent, const char *name ) 00297 { 00298 KoView *view=createViewInstance(parent, name); 00299 addView(view); 00300 return view; 00301 } 00302 00303 bool KoDocument::exp0rt( const KURL & _url ) 00304 { 00305 bool ret; 00306 00307 d->m_isExporting = true; 00308 00309 // 00310 // Preserve a lot of state here because we need to restore it in order to 00311 // be able to fake a File --> Export. Can't do this in saveFile() because, 00312 // for a start, KParts has already set m_url and m_file and because we need 00313 // to restore the modified flag etc. and don't want to put a load on anyone 00314 // reimplementing saveFile() (Note: import() and export() will remain 00315 // non-virtual). 00316 // 00317 KURL oldURL = m_url; 00318 QString oldFile = m_file; 00319 00320 bool wasModified = isModified (); 00321 QCString oldMimeType = mimeType (); 00322 00323 00324 // save... 00325 ret = saveAs( _url ); 00326 00327 00328 // 00329 // This is sooooo hacky :( 00330 // Hopefully we will restore enough state. 00331 // 00332 kdDebug(30003) << "Restoring KoDocument state to before export" << endl; 00333 00334 // always restore m_url & m_file because KParts has changed them 00335 // (regardless of failure or success) 00336 m_url = oldURL; 00337 m_file = oldFile; 00338 00339 // on successful export we need to restore modified etc. too 00340 // on failed export, mimetype/modified hasn't changed anyway 00341 if (ret) 00342 { 00343 setModified (wasModified); 00344 d->mimeType = oldMimeType; 00345 } 00346 00347 00348 d->m_isExporting = false; 00349 00350 return ret; 00351 } 00352 00353 bool KoDocument::saveFile() 00354 { 00355 kdDebug(30003) << "KoDocument::saveFile() doc='" << url().url() <<"'"<< endl; 00356 if ( !kapp->inherits( "KoApplication" ) ) 00357 { 00358 d->lastErrorMessage = i18n( "Internal error: not a KOffice application, saving not allowed." ); 00359 return false; 00360 } 00361 00362 QCString _native_format = nativeFormatMimeType(); 00363 // The output format is set by koMainWindow, and by openFile 00364 QCString outputMimeType = d->outputMimeType; 00365 Q_ASSERT( !outputMimeType.isEmpty() ); 00366 if ( outputMimeType.isEmpty() ) 00367 outputMimeType = _native_format; 00368 00369 QApplication::setOverrideCursor( waitCursor ); 00370 00371 if ( backupFile() ) { 00372 KIO::UDSEntry entry; 00373 #if KDE_IS_VERSION(3,1,90) 00374 if ( KIO::NetAccess::stat( url(), entry, shells().current() ) ) { // this file exists => backup 00375 #else 00376 if ( KIO::NetAccess::stat( url(), entry ) ) { // this file exists => backup 00377 #endif 00378 emit sigStatusBarMessage( i18n("Making backup...") ); 00379 KURL backup; 00380 if ( d->m_backupPath.isEmpty()) 00381 backup = url(); 00382 else 00383 backup = d->m_backupPath +"/"+url().fileName(); 00384 backup.setPath( backup.path() + QString::fromLatin1("~") ); 00385 KFileItem item( entry, url() ); 00386 Q_ASSERT( item.name() == url().fileName() ); 00387 #if KDE_IS_VERSION(3,1,90) 00388 KIO::NetAccess::file_copy( url(), backup, item.permissions(), true /*overwrite*/, false /*resume*/, shells().current() ); 00389 #else 00390 KIO::NetAccess::del( backup ); // Copy does not remove existing destination file 00391 KIO::NetAccess::copy( url(), backup ); 00392 // Not network transparent. 00393 if ( backup.isLocalFile() ) 00394 ::chmod( QFile::encodeName( backup.path() ), item.permissions() ); 00395 #endif 00396 } 00397 } 00398 00399 emit sigStatusBarMessage( i18n("Saving...") ); 00400 bool ret = false; 00401 bool suppressErrorDialog = false; 00402 if ( outputMimeType != _native_format ) { 00403 kdDebug(30003) << "Saving to format " << outputMimeType << " in " << m_file << endl; 00404 // Not native format : save using export filter 00405 if ( !d->filterManager ) 00406 d->filterManager = new KoFilterManager( this ); 00407 00408 KoFilter::ConversionStatus status = d->filterManager->exp0rt( m_file, outputMimeType ); 00409 ret = status == KoFilter::OK; 00410 suppressErrorDialog = (status == KoFilter::UserCancelled || status == KoFilter::BadConversionGraph ); 00411 } else { 00412 // Native format => normal save 00413 ret = saveNativeFormat( m_file ); 00414 } 00415 00416 if ( ret ) { 00417 removeAutoSaveFiles(); 00418 // Restart the autosave timer 00419 // (we don't want to autosave again 2 seconds after a real save) 00420 setAutoSave( d->m_autoSaveDelay ); 00421 } 00422 00423 QApplication::restoreOverrideCursor(); 00424 if ( !ret ) 00425 { 00426 if ( !suppressErrorDialog ) 00427 { 00428 if ( d->lastErrorMessage.isEmpty() ) 00429 KMessageBox::error( 0L, i18n( "Could not save\n%1" ).arg( m_file ) ); 00430 else if ( d->lastErrorMessage != "USER_CANCELED" ) 00431 { 00432 KMessageBox::error( 0L, i18n( "Could not save %1\nReason: %2" ).arg( m_file).arg( d->lastErrorMessage ) ); 00433 } 00434 } 00435 00436 // couldn't save file so this new URL is invalid 00437 // FIXME: we should restore the current document's true URL instead of 00438 // setting it to nothing otherwise anything that depends on the URL 00439 // being correct will not work (i.e. the document will be called 00440 // "Untitled" which may not be true) 00441 // 00442 // Update: now the URL is restored in KoMainWindow but really, this 00443 // should still be fixed in KoDocument/KParts (ditto for m_file). 00444 // We still resetURL() here since we may or may not have been called 00445 // by KoMainWindow - Clarence 00446 resetURL(); 00447 } 00448 00449 if ( ret ) 00450 { 00451 d->mimeType = outputMimeType; 00452 setConfirmNonNativeSave ( isExporting (), false ); 00453 } 00454 emit sigClearStatusBarMessage(); 00455 00456 return ret; 00457 } 00458 00459 QCString KoDocument::mimeType() const 00460 { 00461 return d->mimeType; 00462 } 00463 00464 void KoDocument::setMimeType( const QCString & mimeType ) 00465 { 00466 d->mimeType = mimeType; 00467 } 00468 00469 void KoDocument::setOutputMimeType( const QCString & mimeType, int specialOutputFlag ) 00470 { 00471 d->outputMimeType = mimeType; 00472 d->m_specialOutputFlag = specialOutputFlag; 00473 } 00474 00475 QCString KoDocument::outputMimeType() const 00476 { 00477 return d->outputMimeType; 00478 } 00479 00480 int KoDocument::specialOutputFlag() const 00481 { 00482 return d->m_specialOutputFlag; 00483 } 00484 00485 bool KoDocument::confirmNonNativeSave( const bool exporting ) const 00486 { 00487 // "exporting ? 1 : 0" is different from "exporting" because a bool is 00488 // usually implemented like an "int", not "unsigned : 1" 00489 return d->m_confirmNonNativeSave [ exporting ? 1 : 0 ]; 00490 } 00491 00492 void KoDocument::setConfirmNonNativeSave( const bool exporting, const bool on ) 00493 { 00494 d->m_confirmNonNativeSave [ exporting ? 1 : 0] = on; 00495 } 00496 00497 bool KoDocument::isImporting() const 00498 { 00499 return d->m_isImporting; 00500 } 00501 00502 bool KoDocument::isExporting() const 00503 { 00504 return d->m_isExporting; 00505 } 00506 00507 void KoDocument::setCheckAutoSaveFile( bool b ) 00508 { 00509 d->m_shouldCheckAutoSaveFile = b; 00510 } 00511 00512 void KoDocument::setAutoErrorHandlingEnabled( bool b ) 00513 { 00514 d->m_autoErrorHandlingEnabled = b; 00515 } 00516 00517 bool KoDocument::isAutoErrorHandlingEnabled() 00518 { 00519 return d->m_autoErrorHandlingEnabled; 00520 } 00521 00522 void KoDocument::slotAutoSave() 00523 { 00524 //kdDebug(30003)<<"Autosave : modifiedAfterAutosave "<<d->modifiedAfterAutosave<<endl; 00525 if ( isModified() && d->modifiedAfterAutosave ) 00526 { 00527 connect( this, SIGNAL( sigProgress( int ) ), shells().current(), SLOT( slotProgress( int ) ) ); 00528 emit sigStatusBarMessage( i18n("Autosaving...") ); 00529 d->m_autosaving = true; 00530 bool ret = saveNativeFormat( autoSaveFile( m_file ) ); 00531 setModified( true ); 00532 if ( ret ) 00533 d->modifiedAfterAutosave=false; 00534 d->m_autosaving = false; 00535 emit sigClearStatusBarMessage(); 00536 disconnect( this, SIGNAL( sigProgress( int ) ), shells().current(), SLOT( slotProgress( int ) ) ); 00537 // Not enabled due to i18n freeze. 00538 //if ( !ret ) 00539 // emit sigStatusBarMessage( i18n("Error during autosave! Partition full?") ); 00540 } 00541 } 00542 00543 KAction *KoDocument::action( const QDomElement &element ) const 00544 { 00545 // First look in the document itself 00546 KAction* act = KParts::ReadWritePart::action( element ); 00547 if ( act ) 00548 return act; 00549 00550 Q_ASSERT( d->m_bSingleViewMode ); 00551 // Then look in the first view (this is for the single view mode) 00552 if ( !d->m_views.isEmpty() ) 00553 return d->m_views.getFirst()->action( element ); 00554 else 00555 return 0L; 00556 } 00557 00558 QDomDocument KoDocument::domDocument() const 00559 { 00560 // When embedded into e.g. konqueror, we want the view's GUI (hopefully a reduced one) 00561 // to be used. 00562 Q_ASSERT( d->m_bSingleViewMode ); 00563 if ( d->m_views.isEmpty() ) 00564 return QDomDocument(); 00565 else 00566 return d->m_views.getFirst()->domDocument(); 00567 } 00568 00569 void KoDocument::setManager( KParts::PartManager *manager ) 00570 { 00571 KParts::ReadWritePart::setManager( manager ); 00572 if ( d->m_bSingleViewMode && d->m_views.count() == 1 ) 00573 d->m_views.getFirst()->setPartManager( manager ); 00574 00575 if ( manager ) 00576 { 00577 QPtrListIterator<KoDocumentChild> it( d->m_children ); 00578 for (; it.current(); ++it ) 00579 if ( it.current()->document() ) 00580 manager->addPart( it.current()->document(), false ); 00581 } 00582 } 00583 00584 void KoDocument::setReadWrite( bool readwrite ) 00585 { 00586 KParts::ReadWritePart::setReadWrite( readwrite ); 00587 00588 QPtrListIterator<KoView> vIt( d->m_views ); 00589 for (; vIt.current(); ++vIt ) 00590 vIt.current()->updateReadWrite( readwrite ); 00591 00592 QPtrListIterator<KoDocumentChild> dIt( d->m_children ); 00593 for (; dIt.current(); ++dIt ) 00594 if ( dIt.current()->document() ) 00595 dIt.current()->document()->setReadWrite( readwrite ); 00596 00597 setAutoSave( d->m_autoSaveDelay ); 00598 } 00599 00600 void KoDocument::setAutoSave( int delay ) 00601 { 00602 d->m_autoSaveDelay = delay; 00603 if ( isReadWrite() && !isEmbedded() && d->m_autoSaveDelay > 0 ) 00604 d->m_autoSaveTimer.start( d->m_autoSaveDelay * 1000 ); 00605 else 00606 d->m_autoSaveTimer.stop(); 00607 } 00608 00609 void KoDocument::addView( KoView *view ) 00610 { 00611 if ( !view ) 00612 return; 00613 00614 d->m_views.append( view ); 00615 view->updateReadWrite( isReadWrite() ); 00616 } 00617 00618 void KoDocument::removeView( KoView *view ) 00619 { 00620 d->m_views.removeRef( view ); 00621 } 00622 00623 const QPtrList<KoView>& KoDocument::views() const 00624 { 00625 return d->m_views; 00626 } 00627 00628 int KoDocument::viewCount() const 00629 { 00630 return d->m_views.count(); 00631 } 00632 00633 void KoDocument::insertChild( KoDocumentChild *child ) 00634 { 00635 setModified( true ); 00636 00637 d->m_children.append( child ); 00638 00639 connect( child, SIGNAL( changed( KoChild * ) ), 00640 this, SLOT( slotChildChanged( KoChild * ) ) ); 00641 connect( child, SIGNAL( destroyed() ), 00642 this, SLOT( slotChildDestroyed() ) ); 00643 00644 // It may be that insertChild is called without the KoDocumentChild 00645 // having a KoDocument attached, yet. This happens for example 00646 // when KPresenter loads a document with embedded objects. For those 00647 // KPresenterChild objects are allocated and insertChild is called. 00648 // Later in loadChildren() KPresenter iterates over the child list 00649 // and calls loadDocument for each child. That's exactly where we 00650 // will try to do what we cannot do now: Register the child document 00651 // at the partmanager (Simon) 00652 if ( manager() && !isSingleViewMode() && child->document() ) 00653 manager()->addPart( child->document(), false ); 00654 } 00655 00656 void KoDocument::slotChildChanged( KoChild *c ) 00657 { 00658 assert( c->inherits( "KoDocumentChild" ) ); 00659 emit childChanged( static_cast<KoDocumentChild *>( c ) ); 00660 } 00661 00662 void KoDocument::slotChildDestroyed() 00663 { 00664 setModified( true ); 00665 00666 const KoDocumentChild *child = static_cast<const KoDocumentChild *>( sender() ); 00667 d->m_children.removeRef( child ); 00668 } 00669 00670 const QPtrList<KoDocumentChild>& KoDocument::children() const 00671 { 00672 return d->m_children; 00673 } 00674 00675 KParts::Part *KoDocument::hitTest( QWidget *widget, const QPoint &globalPos ) 00676 { 00677 QPtrListIterator<KoView> it( d->m_views ); 00678 for (; it.current(); ++it ) 00679 if ( (QWidget *)it.current() == widget ) 00680 { 00681 QPoint canvasPos( it.current()->canvas()->mapFromGlobal( globalPos ) ); 00682 canvasPos.rx() += it.current()->canvasXOffset(); 00683 canvasPos.ry() += it.current()->canvasYOffset(); 00684 00685 KParts::Part *part = it.current()->hitTest( canvasPos ); 00686 if ( part ) 00687 return part; 00688 } 00689 00690 return 0L; 00691 } 00692 00693 KoDocument *KoDocument::hitTest( const QPoint &pos, const QWMatrix &matrix ) 00694 { 00695 QPtrListIterator<KoDocumentChild> it( d->m_children ); 00696 for (; it.current(); ++it ) 00697 { 00698 KoDocument *doc = it.current()->hitTest( pos, matrix ); 00699 if ( doc ) 00700 return doc; 00701 } 00702 00703 return this; 00704 } 00705 00706 KoDocumentChild *KoDocument::child( KoDocument *doc ) 00707 { 00708 QPtrListIterator<KoDocumentChild> it( d->m_children ); 00709 for (; it.current(); ++it ) 00710 if ( it.current()->document() == doc ) 00711 return it.current(); 00712 00713 return 0L; 00714 } 00715 00716 KoDocumentInfo *KoDocument::documentInfo() const 00717 { 00718 return d->m_docInfo; 00719 } 00720 00721 void KoDocument::setViewBuildDocument( KoView *view, const QDomDocument &doc ) 00722 { 00723 if ( d->m_views.find( view ) == -1 ) 00724 return; 00725 00726 uint viewIdx = d->m_views.at(); 00727 00728 if ( d->m_viewBuildDocuments.count() == viewIdx ) 00729 d->m_viewBuildDocuments.append( doc ); 00730 else if ( d->m_viewBuildDocuments.count() > viewIdx ) 00731 d->m_viewBuildDocuments[ viewIdx ] = doc; 00732 } 00733 00734 QDomDocument KoDocument::viewBuildDocument( KoView *view ) 00735 { 00736 QDomDocument res; 00737 00738 if ( d->m_views.find( view ) == -1 ) 00739 return res; 00740 00741 uint viewIdx = d->m_views.at(); 00742 00743 if ( viewIdx >= d->m_viewBuildDocuments.count() ) 00744 return res; 00745 00746 res = d->m_viewBuildDocuments[ viewIdx ]; 00747 00748 // make this entry empty. otherwise we get a segfault in QMap ;-( 00749 d->m_viewBuildDocuments[ viewIdx ] = QDomDocument(); 00750 00751 return res; 00752 } 00753 00754 void KoDocument::paintEverything( QPainter &painter, const QRect &rect, bool transparent, KoView *view, double zoomX, double zoomY ) 00755 { 00756 paintContent( painter, rect, transparent, zoomX, zoomY ); 00757 paintChildren( painter, rect, view, zoomX, zoomY ); 00758 } 00759 00760 void KoDocument::paintChildren( QPainter &painter, const QRect &/*rect*/, KoView *view, double zoomX, double zoomY ) 00761 { 00762 QPtrListIterator<KoDocumentChild> it( d->m_children ); 00763 for (; it.current(); ++it ) 00764 { 00765 // #### todo: paint only if child is visible inside rect 00766 painter.save(); 00767 paintChild( it.current(), painter, view, zoomX, zoomY ); 00768 painter.restore(); 00769 } 00770 } 00771 00772 void KoDocument::paintChild( KoDocumentChild *child, QPainter &painter, KoView *view, double zoomX, double zoomY ) 00773 { 00774 if ( child->isDeleted() ) 00775 return; 00776 00777 // QRegion rgn = painter.clipRegion(); 00778 00779 child->transform( painter ); 00780 child->document()->paintEverything( painter, child->contentRect(), child->isTransparent(), view, zoomX, zoomY ); 00781 00782 if ( view && view->partManager() ) 00783 { 00784 // ### do we need to apply zoomX and zoomY here ? 00785 KParts::PartManager *manager = view->partManager(); 00786 00787 painter.scale( 1.0 / child->xScaling(), 1.0 / child->yScaling() ); 00788 00789 int w = int( (double)child->contentRect().width() * child->xScaling() ); 00790 int h = int( (double)child->contentRect().height() * child->yScaling() ); 00791 if ( ( manager->selectedPart() == (KParts::Part *)child->document() && 00792 manager->selectedWidget() == (QWidget *)view ) || 00793 ( manager->activePart() == (KParts::Part *)child->document() && 00794 manager->activeWidget() == (QWidget *)view ) ) 00795 { 00796 // painter.setClipRegion( rgn ); 00797 painter.setClipping( FALSE ); 00798 00799 painter.setPen( black ); 00800 painter.fillRect( -5, -5, w + 10, 5, white ); 00801 painter.fillRect( -5, h, w + 10, 5, white ); 00802 painter.fillRect( -5, -5, 5, h + 10, white ); 00803 painter.fillRect( w, -5, 5, h + 10, white ); 00804 painter.fillRect( -5, -5, w + 10, 5, BDiagPattern ); 00805 painter.fillRect( -5, h, w + 10, 5, BDiagPattern ); 00806 painter.fillRect( -5, -5, 5, h + 10, BDiagPattern ); 00807 painter.fillRect( w, -5, 5, h + 10, BDiagPattern ); 00808 00809 if ( manager->selectedPart() == (KParts::Part *)child->document() && 00810 manager->selectedWidget() == (QWidget *)view ) 00811 { 00812 QColor color; 00813 if ( view->koDocument() == this ) 00814 color = black; 00815 else 00816 color = gray; 00817 painter.fillRect( -5, -5, 5, 5, color ); 00818 painter.fillRect( -5, h, 5, 5, color ); 00819 painter.fillRect( w, h, 5, 5, color ); 00820 painter.fillRect( w, -5, 5, 5, color ); 00821 painter.fillRect( w / 2 - 3, -5, 5, 5, color ); 00822 painter.fillRect( w / 2 - 3, h, 5, 5, color ); 00823 painter.fillRect( -5, h / 2 - 3, 5, 5, color ); 00824 painter.fillRect( w, h / 2 - 3, 5, 5, color ); 00825 } 00826 00827 painter.setClipping( TRUE ); 00828 } 00829 } 00830 } 00831 00832 bool KoDocument::isModified() 00833 { 00834 if ( KParts::ReadWritePart::isModified() ) 00835 { 00836 //kdDebug(30003)<<k_funcinfo<<" Modified doc='"<<url().url()<<"' extern="<<isStoredExtern()<<endl; 00837 return true; 00838 } 00839 // Then go through internally stored children (considdered to be part of this doc) 00840 QPtrListIterator<KoDocumentChild> it = children(); 00841 for (; it.current(); ++it ) 00842 { 00843 if ( !it.current()->isStoredExtern() && !it.current()->isDeleted() ) 00844 { 00845 KoDocument *doc = it.current()->document(); 00846 if ( doc && doc->isModified() ) 00847 return true; 00848 } 00849 } 00850 return false; 00851 } 00852 00853 bool KoDocument::saveChildren( KoStore* _store ) 00854 { 00855 //kdDebug(30003)<<k_funcinfo<<" checking children of doc='"<<url().url()<<"'"<<endl; 00856 int i = 0; 00857 QPtrListIterator<KoDocumentChild> it( children() ); 00858 for( ; it.current(); ++it ) { 00859 KoDocument* childDoc = it.current()->document(); 00860 if (childDoc && !it.current()->isDeleted()) 00861 { 00862 if ( !childDoc->isStoredExtern() ) 00863 { 00864 //kdDebug(30003) << "KoDocument::saveChildren internal url: /" << i << endl; 00865 if ( !childDoc->saveToStore( _store, QString::number( i++ ) ) ) 00866 return FALSE; 00867 00868 if (!isExporting ()) 00869 childDoc->setModified( false ); 00870 } 00871 //else kdDebug(30003)<<k_funcinfo<<" external (don't save) url:" << childDoc->url().url()<<endl; 00872 } 00873 } 00874 return true; 00875 } 00876 00877 bool KoDocument::saveExternalChildren() 00878 { 00879 if ( d->m_doNotSaveExtDoc ) 00880 { 00881 //kdDebug(30003)<<k_funcinfo<<" Don't save external docs in doc='"<<url().url()<<"'"<<endl; 00882 d->m_doNotSaveExtDoc = false; 00883 return true; 00884 } 00885 00886 //kdDebug(30003)<<k_funcinfo<<" checking children of doc='"<<url().url()<<"'"<<endl; 00887 KoDocument *doc; 00888 KoDocumentChild *ch; 00889 QPtrListIterator<KoDocumentChild> it = children(); 00890 for (; (ch = it.current()); ++it ) 00891 { 00892 if ( !ch->isDeleted() ) 00893 { 00894 doc = ch->document(); 00895 if ( doc->isStoredExtern() && doc->isModified() ) 00896 { 00897 kdDebug(30003)<<" save external doc='"<<url().url()<<"'"<<endl; 00898 doc->setDoNotSaveExtDoc(); // Only save doc + it's internal children 00899 if ( !doc->save() ) 00900 return false; // error 00901 } 00902 //kdDebug(30003)<<k_funcinfo<<" not modified doc='"<<url().url()<<"'"<<endl; 00903 // save possible external docs inside doc 00904 if ( !doc->saveExternalChildren() ) 00905 return false; 00906 } 00907 } 00908 return true; 00909 } 00910 00911 bool KoDocument::saveNativeFormat( const QString & _file ) 00912 { 00913 QString file( _file ); 00914 d->lastErrorMessage = QString::null; 00915 //kdDebug(30003) << "Saving to store" << endl; 00916 00917 KoStore::Backend backend = KoStore::Auto; 00918 if ( d->m_specialOutputFlag == SaveAsKOffice1dot1 ) 00919 { 00920 kdDebug(30003) << "Saving as KOffice-1.1 format, using a tar.gz" << endl; 00921 backend = KoStore::Tar; // KOffice-1.0/1.1 used tar.gz for the native mimetype 00923 } 00924 else if ( d->m_specialOutputFlag == SaveAsDirectoryStore ) 00925 { 00926 backend = KoStore::Directory; 00927 kdDebug(30003) << "Saving as uncompressed XML, using directory store." << endl; 00928 } 00929 00930 kdDebug(30003) << "KoDocument::saveNativeFormat nativeFormatMimeType=" << nativeFormatMimeType() << endl; 00931 KoStore* store = KoStore::createStore( file, KoStore::Write, nativeFormatMimeType(), backend ); 00932 if ( store->bad() ) 00933 { 00934 d->lastErrorMessage = i18n( "Couldn't open the file for saving" ); // more details needed? 00935 delete store; 00936 return false; 00937 } 00938 00939 // Save internal children first since they might get a new url 00940 if ( !saveChildren( store ) ) 00941 { 00942 if ( d->lastErrorMessage.isEmpty() ) 00943 d->lastErrorMessage = i18n( "Error while saving embedded documents" ); // more details needed 00944 delete store; 00945 return false; 00946 } 00947 00948 kdDebug(30003) << "Saving root" << endl; 00949 if ( store->open( "root" ) ) 00950 { 00951 KoStoreDevice dev( store ); 00952 if ( !saveToStream( &dev ) ) 00953 { 00954 kdDebug(30003) << "saveToStream failed" << endl; 00955 delete store; 00956 return false; 00957 } 00958 if ( !store->close() ) 00959 return false; 00960 } 00961 else 00962 { 00963 d->lastErrorMessage = i18n( "Not able to write 'maindoc.xml'." ); 00964 delete store; 00965 return false; 00966 } 00967 if ( store->open( "documentinfo.xml" ) ) 00968 { 00969 QDomDocument doc = d->m_docInfo->save(); 00970 KoStoreDevice dev( store ); 00971 00972 QCString s = doc.toCString(); // this is already Utf8! 00973 (void)dev.writeBlock( s.data(), s.size()-1 ); 00974 (void)store->close(); 00975 } 00976 if ( store->open( "preview.png" ) ) 00977 { 00978 savePreview( store ); 00979 (void)store->close(); 00980 } 00981 00982 bool ret = completeSaving( store ); 00983 kdDebug(30003) << "Saving done of url: " << url().url() << endl; 00984 delete store; 00985 00986 if ( !saveExternalChildren() ) 00987 { 00988 return false; 00989 } 00990 return ret; 00991 } 00992 00993 bool KoDocument::saveToStream( QIODevice * dev ) 00994 { 00995 QDomDocument doc = saveXML(); 00996 // Save to buffer 00997 QCString s = doc.toCString(); // utf8 already 00998 // Important: don't use s.length() here. It's slow, and dangerous (in case of a '\0' somewhere) 00999 // The -1 is because we don't want to write the final \0. 01000 int nwritten = dev->writeBlock( s.data(), s.size()-1 ); 01001 if ( nwritten != (int)s.size()-1 ) 01002 kdWarning(30003) << "KoDocument::saveToStream wrote " << nwritten << " - expected " << s.size()-1 << endl; 01003 return nwritten == (int)s.size()-1; 01004 } 01005 01006 bool KoDocument::saveToStore( KoStore* _store, const QString & _path ) 01007 { 01008 kdDebug(30003) << "Saving document to store " << _path << endl; 01009 01010 // Use the path as the internal url 01011 if ( _path.startsWith( STORE_PROTOCOL ) ) 01012 m_url = KURL( _path ); 01013 else // ugly hack to pass a relative URI 01014 m_url = KURL( INTERNAL_PREFIX + _path ); 01015 01016 // To make the children happy cd to the correct directory 01017 _store->pushDirectory(); 01018 _store->enterDirectory( _path ); 01019 01020 // Save childen first since they might get a new url 01021 if ( !saveChildren( _store ) ) 01022 return false; 01023 01024 // In the current directory we're the king :-) 01025 if ( _store->open( "root" ) ) 01026 { 01027 KoStoreDevice dev( _store ); 01028 if ( !saveToStream( &dev ) ) 01029 { 01030 _store->close(); 01031 return false; 01032 } 01033 if ( !_store->close() ) 01034 return false; 01035 } 01036 01037 if ( !completeSaving( _store ) ) 01038 return false; 01039 01040 // Now that we're done leave the directory again 01041 _store->popDirectory(); 01042 01043 kdDebug(30003) << "Saved document to store" << endl; 01044 01045 return true; 01046 } 01047 01048 void KoDocument::savePreview( KoStore* store ) 01049 { 01050 QPixmap pix = generatePreview(QSize(256, 256)); 01051 // Reducing to 8bpp reduces file sizes quite a lot. 01052 QImageIO imageIO; 01053 imageIO.setImage( pix.convertToImage().convertDepth(8, Qt::AvoidDither | Qt::DiffuseDither) ); 01054 01055 // NOTE: we cannot use QDataStream, as it is not 1:1 01056 QByteArray imageData; 01057 QBuffer buffer(imageData); 01058 buffer.open(IO_WriteOnly); 01059 imageIO.setIODevice(&buffer); 01060 imageIO.setFormat("PNG"); 01061 imageIO.write(); 01062 buffer.close(); 01063 01064 store->write( imageData ); 01065 } 01066 01067 QPixmap KoDocument::generatePreview( const QSize& size ) 01068 { 01069 double docWidth, docHeight; 01070 int pixmapSize = QMAX(size.width(), size.height()); 01071 01072 if (m_pageLayout.ptWidth > 1.0) { 01073 docWidth = m_pageLayout.ptWidth / 72 * QPaintDevice::x11AppDpiX(); 01074 docHeight = m_pageLayout.ptHeight / 72 * QPaintDevice::x11AppDpiX(); 01075 01076 } else { 01077 // If we don't have a page layout, just draw the top left hand corner 01078 docWidth = 500.0; 01079 docHeight = 500.0; 01080 } 01081 01082 double ratio = docWidth / docHeight; 01083 01084 QPixmap pix; 01085 int previewWidth, previewHeight; 01086 if (ratio > 1.0) 01087 { 01088 previewWidth = (int) pixmapSize; 01089 previewHeight = (int) (pixmapSize / ratio); 01090 } 01091 else 01092 { 01093 previewWidth = (int) (pixmapSize * ratio); 01094 previewHeight = (int) pixmapSize; 01095 } 01096 01097 pix.resize((int)docWidth, (int)docHeight); 01098 01099 pix.fill( QColor( 245, 245, 245 ) ); 01100 01101 QRect rc(0, 0, pix.width(), pix.height()); 01102 01103 QPainter p; 01104 p.begin(&pix); 01105 paintEverything(p, rc, false); 01106 p.end(); 01107 01108 pix.convertFromImage(pix.convertToImage().smoothScale(previewWidth, previewHeight)); 01109 01110 return pix; 01111 } 01112 01113 QString KoDocument::autoSaveFile( const QString & path ) const 01114 { 01115 // Using the extension allows to avoid relying on the mime magic when opening 01116 KMimeType::Ptr mime = KMimeType::mimeType( nativeFormatMimeType() ); 01117 QString extension = mime->property( "X-KDE-NativeExtension" ).toString(); 01118 if ( path.isEmpty() ) 01119 { 01120 // Never saved? Use a temp file in $HOME then 01121 // Yes, two open unnamed docs will overwrite each other's autosave file, 01122 // but hmm, we can only do something if that's in the same process anyway... 01123 QString ret = QDir::homeDirPath() + "/." + QString::fromLatin1(instance()->instanceName()) + ".autosave" + extension; 01124 return ret; 01125 } 01126 else 01127 { 01128 KURL url( path ); 01129 Q_ASSERT( url.isLocalFile() ); 01130 QString dir = url.directory(false); 01131 QString filename = url.fileName(); 01132 return dir + "." + filename + ".autosave" + extension; 01133 } 01134 } 01135 01136 bool KoDocument::checkAutoSaveFile() 01137 { 01138 QString asf = autoSaveFile( QString::null ); // the one in $HOME 01139 //kdDebug(30003) << "asf=" << asf << endl; 01140 if ( QFile::exists( asf ) ) 01141 { 01142 QDateTime date = QFileInfo(asf).lastModified(); 01143 QString dateStr = date.toString(Qt::LocalDate); 01144 int res = KMessageBox::warningYesNoCancel( 01145 0, i18n( "An autosaved file for an unnamed document exists in %1.\nThis file is dated %2\nDo you want to open it?" ) 01146 .arg(asf).arg( dateStr) ); 01147 switch(res) { 01148 case KMessageBox::Yes : { 01149 KURL url; 01150 url.setPath( asf ); 01151 bool ret = openURL( url ); 01152 if ( ret ) 01153 resetURL(); 01154 return ret; 01155 } 01156 case KMessageBox::No : 01157 unlink( QFile::encodeName( asf ) ); 01158 return false; 01159 default: // Cancel 01160 return false; 01161 } 01162 } 01163 return false; 01164 } 01165 01166 bool KoDocument::import( const KURL & _url ) 01167 { 01168 bool ret; 01169 01170 kdDebug (30003) << "KoDocument::import url=" << _url.url() << endl; 01171 d->m_isImporting = true; 01172 01173 // open... 01174 ret = openURL (_url); 01175 01176 // reset m_url & m_file (kindly? set by KParts::openURL()) to simulate a 01177 // File --> Import 01178 if (ret) 01179 { 01180 kdDebug (30003) << "KoDocument::import success, resetting url" << endl; 01181 resetURL (); 01182 setTitleModified (); 01183 } 01184 01185 d->m_isImporting = false; 01186 01187 return ret; 01188 } 01189 01190 bool KoDocument::openURL( const KURL & _url ) 01191 { 01192 kdDebug(30003) << "KoDocument::openURL url=" << _url.url() << endl; 01193 d->lastErrorMessage = QString::null; 01194 01195 // Reimplemented, to add a check for autosave files and to improve error reporting 01196 if ( !_url.isValid() ) 01197 { 01198 d->lastErrorMessage = i18n( "Malformed URL\n%1" ).arg( _url.url() ); // ## used anywhere ? 01199 return false; 01200 } 01201 if ( !closeURL() ) 01202 return false; 01203 KURL url( _url ); 01204 bool autosaveOpened = false; 01205 if ( url.isLocalFile() && d->m_shouldCheckAutoSaveFile ) 01206 { 01207 QString file = url.path(); 01208 QString asf = autoSaveFile( file ); 01209 if ( QFile::exists( asf ) ) 01210 { 01211 //kdDebug(30003) << "KoDocument::openURL asf=" << asf << endl; 01212 // ## TODO compare timestamps ? 01213 int res = KMessageBox::warningYesNoCancel( 0, 01214 i18n( "An autosaved file exists for this document.\nDo you want to open it instead?" )); 01215 switch(res) { 01216 case KMessageBox::Yes : 01217 url.setPath( asf ); 01218 autosaveOpened = true; 01219 break; 01220 case KMessageBox::No : 01221 unlink( QFile::encodeName( asf ) ); 01222 break; 01223 default: // Cancel 01224 return false; 01225 } 01226 } 01227 } 01228 bool ret = KParts::ReadWritePart::openURL( url ); 01229 01230 if ( autosaveOpened ) 01231 resetURL(); // Force save to act like 'Save As' 01232 else 01233 { 01234 // We have no koffice shell when we are being embedded as a readonly part. 01235 //if ( d->m_shells.isEmpty() ) 01236 // kdWarning(30003) << "KoDocument::openURL no shell yet !" << endl; 01237 // Add to recent actions list in our shells 01238 QPtrListIterator<KoMainWindow> it( d->m_shells ); 01239 for (; it.current(); ++it ) 01240 it.current()->addRecentURL( _url ); 01241 } 01242 return ret; 01243 } 01244 01245 bool KoDocument::openFile() 01246 { 01247 //kdDebug(30003) << "KoDocument::openFile for " << m_file << endl; 01248 if ( ! QFile::exists(m_file) ) 01249 { 01250 QApplication::restoreOverrideCursor(); 01251 if ( d->m_autoErrorHandlingEnabled ) 01252 // Maybe offer to create a new document with that name ? 01253 KMessageBox::error(0L, i18n("The file %1 doesn't exist.").arg(m_file) ); 01254 return false; 01255 } 01256 01257 QApplication::setOverrideCursor( waitCursor ); 01258 01259 if ( d->m_bSingleViewMode && !d->m_views.isEmpty() ) 01260 { 01261 // We already had a view (this happens when doing reload in konqueror) 01262 KoView* v = d->m_views.first(); 01263 removeView( v ); 01264 delete v; 01265 Q_ASSERT( d->m_views.isEmpty() ); 01266 } 01267 01268 d->m_specialOutputFlag = 0; 01269 QCString _native_format = nativeFormatMimeType(); 01270 01271 KURL u; 01272 u.setPath( m_file ); 01273 QString typeName = KMimeType::findByURL( u, 0, true )->name(); 01274 01275 // Allow to open backup files, don't keep the mimetype application/x-trash. 01276 if ( typeName == "application/x-trash" ) 01277 { 01278 QString path = u.path(); 01279 QStringList patterns = KMimeType::mimeType( typeName )->patterns(); 01280 // Find the extension that makes it a backup file, and remove it 01281 for( QStringList::Iterator it = patterns.begin(); it != patterns.end(); ++it ) { 01282 QString ext = *it; 01283 if ( !ext.isEmpty() && ext[0] == '*' ) 01284 { 01285 ext.remove(0, 1); 01286 if ( path.endsWith( ext ) ) { 01287 path.truncate( path.length() - ext.length() ); 01288 break; 01289 } 01290 } 01291 } 01292 typeName = KMimeType::findByPath( path, 0, true )->name(); 01293 } 01294 01295 // Special case for flat XML files (e.g. using directory store) 01296 if ( u.fileName() == "maindoc.xml" || typeName == "inode/directory" ) 01297 { 01298 typeName = _native_format; // Hmm, what if it's from another app? ### Check mimetype 01299 d->m_specialOutputFlag = SaveAsDirectoryStore; 01300 kdDebug(30003) << "KoDocument::openFile loading maindoc.xml, using directory store for " << m_file << endl; 01301 } 01302 kdDebug(30003) << "KoDocument::openFile " << m_file << " type:" << typeName << endl; 01303 01304 QString importedFile = m_file; 01305 01306 if ( typeName == KMimeType::defaultMimeType() ) { 01307 kdError(30003) << "No mimetype found for " << m_file << endl; 01308 QApplication::restoreOverrideCursor(); 01309 if ( d->m_autoErrorHandlingEnabled ) 01310 KMessageBox::error( 0L, i18n( "Could not open\n%1" ).arg( url().prettyURL( 0, KURL::StripFileProtocol ) ) ); 01311 return false; 01312 } 01313 01314 if ( typeName.latin1() != _native_format ) { 01315 if ( !d->filterManager ) 01316 d->filterManager = new KoFilterManager( this ); 01317 KoFilter::ConversionStatus status; 01318 importedFile = d->filterManager->import( m_file, status ); 01319 if ( status != KoFilter::OK ) 01320 { 01321 QApplication::restoreOverrideCursor(); 01322 if ( status != KoFilter::UserCancelled && 01323 status != KoFilter::BadConversionGraph && 01324 d->m_autoErrorHandlingEnabled ) 01325 // Any way of passing a better error message from the filter? 01326 KMessageBox::error( 0L, i18n( "Could not open\n%1" ).arg( url().prettyURL( 0, KURL::StripFileProtocol ) ) ); 01327 01328 return false; 01329 } 01330 kdDebug(30003) << "KoDocument::openFile - importedFile '" << importedFile 01331 << "', status: " << static_cast<int>( status ) << endl; 01332 } 01333 01334 QApplication::restoreOverrideCursor(); 01335 01336 bool ok = true; 01337 01338 if (!importedFile.isEmpty()) // Something to load (tmp or native file) ? 01339 { 01340 // The filter, if any, has been applied. It's all native format now. 01341 if ( !loadNativeFormat( importedFile ) ) 01342 { 01343 ok = false; 01344 if ( d->m_autoErrorHandlingEnabled ) 01345 { 01346 if ( d->lastErrorMessage.isEmpty() ) 01347 KMessageBox::error( 0L, i18n( "Could not open\n%1" ).arg( url().prettyURL( 0, KURL::StripFileProtocol ) ) ); 01348 else if ( d->lastErrorMessage != "USER_CANCELED" ) 01349 KMessageBox::error( 0L, i18n( "Could not open %1\nReason: %2" ).arg( url().prettyURL( 0, KURL::StripFileProtocol )).arg( d->lastErrorMessage ) ); 01350 } 01351 } 01352 } 01353 01354 if ( importedFile != m_file ) 01355 { 01356 // We opened a temporary file (result of an import filter) 01357 // Set document URL to empty - we don't want to save in /tmp ! 01358 // But only if in readwrite mode (no saving problem otherwise) 01359 // -- 01360 // But this isn't true at all. If this is the result of an 01361 // import, then importedFile=temporary_file.kwd and 01362 // m_file/m_url=foreignformat.ext so m_url is correct! 01363 // So don't resetURL() or else the caption won't be set when 01364 // foreign files are opened (an annoying bug). 01365 // - Clarence 01366 // 01367 #if 0 01368 if ( isReadWrite() ) 01369 resetURL(); 01370 #endif 01371 01372 // remove temp file - uncomment this to debug import filters 01373 if(!importedFile.isEmpty()) 01374 unlink( QFile::encodeName(importedFile) ); 01375 } 01376 01377 if ( ok && d->m_bSingleViewMode ) 01378 { 01379 // See addClient below 01380 KXMLGUIFactory* guiFactory = factory(); 01381 if( guiFactory ) // 0L when splitting views in konq, for some reason 01382 guiFactory->removeClient( this ); 01383 01384 KoView *view = createView( d->m_wrapperWidget ); 01385 d->m_wrapperWidget->setKoView( view ); 01386 view->show(); 01387 01388 // Ok, now we have a view, so action() and domDocument() will work as expected 01389 // -> rebuild GUI 01390 if ( guiFactory ) 01391 guiFactory->addClient( this ); 01392 } 01393 01394 if ( ok ) 01395 { 01396 d->mimeType = typeName.latin1 (); 01397 01398 d->outputMimeType = d->mimeType; 01399 01400 const bool needConfirm = (d->mimeType != _native_format); 01401 setConfirmNonNativeSave ( false, needConfirm ); 01402 setConfirmNonNativeSave ( true, needConfirm ); 01403 } 01404 01405 return ok; 01406 } 01407 01408 bool KoDocument::loadNativeFormat( const QString & file ) 01409 { 01410 if ( !QFileInfo( file).isFile () ) 01411 { 01412 d->lastErrorMessage = i18n( "%1 is not a file." ).arg(file); 01413 return false; 01414 } 01415 01416 QApplication::setOverrideCursor( waitCursor ); 01417 01418 kdDebug(30003) << "KoDocument::loadNativeFormat( " << file << " )" << endl; 01419 01420 QFile in; 01421 bool isRawXML = false; 01422 if ( d->m_specialOutputFlag != SaveAsDirectoryStore ) // Don't try to open a directory ;) 01423 { 01424 in.setName(file); 01425 if ( !in.open( IO_ReadOnly ) ) 01426 { 01427 QApplication::restoreOverrideCursor(); 01428 d->lastErrorMessage = i18n( "Couldn't open the file for reading (check read permissions)." ); 01429 return false; 01430 } 01431 01432 // Try to find out whether it is a mime multi part file 01433 char buf[5]; 01434 if ( in.readBlock( buf, 4 ) < 4 ) 01435 { 01436 QApplication::restoreOverrideCursor(); 01437 in.close(); 01438 d->lastErrorMessage = i18n( "Couldn't read the beginning of the file." ); 01439 return false; 01440 } 01441 isRawXML = (strncasecmp( buf, "<?xm", 4 ) == 0); 01442 //kdDebug(30003) << "PATTERN=" << buf << endl; 01443 } 01444 // Is it plain XML? 01445 if ( isRawXML ) 01446 { 01447 in.at(0); 01448 QString errorMsg; 01449 int errorLine; 01450 int errorColumn; 01451 QDomDocument doc; 01452 bool res; 01453 if ( doc.setContent( &in , &errorMsg, &errorLine, &errorColumn ) ) 01454 { 01455 res = loadXML( &in, doc ); 01456 if ( res ) 01457 res = completeLoading( 0L ); 01458 } 01459 else 01460 { 01461 kdError (30003) << "Parsing Error! Aborting! (in KoDocument::loadNativeFormat (QFile))" << endl 01462 << " Line: " << errorLine << " Column: " << errorColumn << endl 01463 << " Message: " << errorMsg << endl; 01464 d->lastErrorMessage = i18n( "parsing error in the main document at line %1, column %2\nError message: %3" ) 01465 .arg( errorLine ).arg( errorColumn ).arg( i18n ( "QXml", errorMsg.utf8() ) ); 01466 res=false; 01467 } 01468 01469 QApplication::restoreOverrideCursor(); 01470 in.close(); 01471 m_bEmpty = false; 01472 return res; 01473 } else 01474 { // It's a koffice store (tar.gz, zip, directory, etc.) 01475 in.close(); 01476 KoStore::Backend backend = (d->m_specialOutputFlag == SaveAsDirectoryStore) ? KoStore::Directory : KoStore::Auto; 01477 KoStore * store = KoStore::createStore( file, KoStore::Read, "", backend ); 01478 01479 if ( store->bad() ) 01480 { 01481 d->lastErrorMessage = i18n( "Not a valid KOffice file." ); 01482 delete store; 01483 QApplication::restoreOverrideCursor(); 01484 return false; 01485 } 01486 01487 if ( store->open( "root" ) ) 01488 { 01489 QString errorMsg; 01490 int errorLine; 01491 int errorColumn; 01492 QDomDocument doc; 01493 if ( !doc.setContent( store->device(), &errorMsg, &errorLine, &errorColumn ) ) 01494 { 01495 kdError (30003) << "Parsing Error! Aborting! (in KoDocument::loadNativeFormat (KoStore))" << endl 01496 << " Line: " << errorLine << " Column: " << errorColumn << endl 01497 << " Message: " << errorMsg << endl; 01498 d->lastErrorMessage = i18n( "parsing error in the main document at line %1, column %2\nError message: %3" ) 01499 .arg( errorLine ).arg( errorColumn ).arg( i18n ( errorMsg.utf8() ) ); 01500 delete store; 01501 QApplication::restoreOverrideCursor(); 01502 return false; 01503 } 01504 if ( !loadXML( store->device(), doc ) ) 01505 { 01506 delete store; 01507 QApplication::restoreOverrideCursor(); 01508 return false; 01509 } 01510 store->close(); 01511 } else 01512 { 01513 kdError(30003) << "ERROR: No maindoc.xml" << endl; 01514 d->lastErrorMessage = i18n( "Invalid document: no file 'maindoc.xml'." ); 01515 delete store; 01516 QApplication::restoreOverrideCursor(); 01517 return false; 01518 } 01519 01520 if ( !loadChildren( store ) ) 01521 { 01522 kdError(30003) << "ERROR: Could not load children" << endl; 01523 // Proceed nonetheless 01524 #if 0 01525 if ( d->lastErrorMessage.isEmpty() ) 01526 d->lastErrorMessage = i18n( "Couldn't load embedded objects." ); 01527 delete store; 01528 QApplication::restoreOverrideCursor(); 01529 return false; 01530 #endif 01531 } 01532 if ( store->open( "documentinfo.xml" ) ) 01533 { 01534 QDomDocument doc; 01535 doc.setContent( store->device() ); 01536 d->m_docInfo->load( doc ); 01537 store->close(); 01538 } 01539 else 01540 { 01541 //kdDebug( 30003 ) << "cannot open document info" << endl; 01542 delete d->m_docInfo; 01543 d->m_docInfo = new KoDocumentInfo( this, "document info" ); 01544 } 01545 01546 bool res = completeLoading( store ); 01547 delete store; 01548 QApplication::restoreOverrideCursor(); 01549 m_bEmpty = false; 01550 return res; 01551 } 01552 } 01553 01554 bool KoDocument::loadFromStore( KoStore* _store, const QString& url ) 01555 { 01556 if ( _store->open( url ) ) 01557 { 01558 QDomDocument doc; 01559 doc.setContent( _store->device() ); 01560 if ( !loadXML( _store->device(), doc ) ) 01561 { 01562 _store->close(); 01563 return false; 01564 } 01565 _store->close(); 01566 } 01567 01568 _store->pushDirectory(); 01569 // Store as document URL 01570 if ( url.startsWith( STORE_PROTOCOL ) ) 01571 m_url = KURL( url ); 01572 else { 01573 m_url = KURL( INTERNAL_PREFIX + url ); 01574 _store->enterDirectory( url ); 01575 } 01576 01577 if ( !loadChildren( _store ) ) 01578 { 01579 kdError(30003) << "ERROR: Could not load children" << endl; 01580 #if 0 01581 return false; 01582 #endif 01583 } 01584 01585 bool result = completeLoading( _store ); 01586 01587 // Restore the "old" path 01588 _store->popDirectory(); 01589 01590 return result; 01591 } 01592 01593 bool KoDocument::isInOperation() 01594 { 01595 return d->m_numOperations > 0; 01596 } 01597 01598 void KoDocument::emitBeginOperation() 01599 { 01600 01601 /* if we're already in an operation, don't send the signal again */ 01602 if (!isInOperation()) 01603 emit sigBeginOperation(); 01604 d->m_numOperations++; 01605 } 01606 01607 void KoDocument::emitEndOperation() 01608 { 01609 d->m_numOperations--; 01610 01611 /* don't end the operation till we've cleared all the nested operations */ 01612 if (d->m_numOperations == 0) 01613 emit sigEndOperation(); 01614 else if (d->m_numOperations < 0) 01615 /* ignore 'end' calls with no matching 'begin' call */ 01616 d->m_numOperations = 0; 01617 } 01618 01619 01620 bool KoDocument::isStoredExtern() 01621 { 01622 return !storeInternal() && hasExternURL(); 01623 } 01624 01625 void KoDocument::setModified( bool mod ) 01626 { 01627 //kdDebug(30003)<<k_funcinfo<<" url:" << m_url.path() << endl; 01628 //kdDebug(30003)<<k_funcinfo<<" mod="<<mod<<" MParts mod="<<KParts::ReadWritePart::isModified()<<" isModified="<<isModified()<<endl; 01629 01630 d->modifiedAfterAutosave=mod; 01631 if ( isAutosaving() ) // ignore setModified calls due to autosaving 01632 return; 01633 if ( mod == KParts::ReadWritePart::isModified() ) 01634 return; 01635 01636 KParts::ReadWritePart::setModified( mod ); 01637 01638 if ( mod ) 01639 m_bEmpty = FALSE; 01640 01641 // This influences the title 01642 setTitleModified(); 01643 } 01644 01645 void KoDocument::setDoNotSaveExtDoc( bool on ) 01646 { 01647 d->m_doNotSaveExtDoc = on; 01648 } 01649 01650 int KoDocument::queryCloseDia() 01651 { 01652 //kdDebug(30003)<<k_funcinfo<<endl; 01653 01654 QString name; 01655 if ( documentInfo() ) 01656 { 01657 name = documentInfo()->title(); 01658 } 01659 if ( name.isEmpty() ) 01660 name = url().fileName(); 01661 01662 if ( name.isEmpty() ) 01663 name = i18n( "Untitled" ); 01664 01665 int res = KMessageBox::warningYesNoCancel( 0L, 01666 i18n( "<p>The document <b>'%1'</b> has been modified.</p><p>Do you want to save it?</p>" ).arg(name)); 01667 01668 switch(res) 01669 { 01670 case KMessageBox::Yes : 01671 setDoNotSaveExtDoc(); // Let save() only save myself and my internal docs 01672 save(); // NOTE: External files always in native format. ###TODO: Handle non-native format 01673 setModified( false ); // Now when queryClose() is called by closeEvent it won't do anything. 01674 break; 01675 case KMessageBox::No : 01676 removeAutoSaveFiles(); 01677 setModified( false ); // Now when queryClose() is called by closeEvent it won't do anything. 01678 break; 01679 default : // case KMessageBox::Cancel : 01680 return res; // cancels the rest of the files 01681 } 01682 return res; 01683 } 01684 01685 int KoDocument::queryCloseExternalChildren() 01686 { 01687 //kdDebug(30003)<<k_funcinfo<<" checking for children in: "<<url().url()<<endl; 01688 setDoNotSaveExtDoc(false); 01689 QPtrListIterator<KoDocumentChild> it( children() ); 01690 for (; it.current(); ++it ) 01691 { 01692 if ( !it.current()->isDeleted() ) 01693 { 01694 KoDocument *doc = it.current()->document(); 01695 if ( doc ) 01696 { 01697 if ( doc->isStoredExtern() ) //###TODO: Handle non-native mimetype docs 01698 { 01699 if ( doc->isModified() ) 01700 { 01701 kdDebug(30003)<<k_funcinfo<<" found modified child: "<<doc->url().url()<<" extern="<<doc->isStoredExtern()<<endl; 01702 if ( doc->queryCloseDia() == KMessageBox::Cancel ) 01703 return KMessageBox::Cancel; 01704 } 01705 } 01706 if ( doc->queryCloseExternalChildren() == KMessageBox::Cancel ) 01707 return KMessageBox::Cancel; 01708 } 01709 } 01710 } 01711 return KMessageBox::Ok; 01712 } 01713 01714 void KoDocument::setTitleModified( const QString caption, bool mod ) 01715 { 01716 //kdDebug(30003)<<k_funcinfo<<" url: "<<url().url()<<" caption: "<<caption<<" mod: "<<mod<<endl; 01717 KoDocument *doc = dynamic_cast<KoDocument *>( parent() ); 01718 if ( doc ) 01719 { 01720 doc->setTitleModified( caption, mod ); 01721 return; 01722 } 01723 // we must be root doc so update caption in all related windows 01724 QPtrListIterator<KoMainWindow> it( d->m_shells ); 01725 for (; it.current(); ++it ) 01726 { 01727 it.current()->updateCaption( caption, mod ); 01728 it.current()->updateReloadFileAction(this); 01729 } 01730 } 01731 01732 void KoDocument::setTitleModified() 01733 { 01734 //kdDebug(30003)<<k_funcinfo<<" url: "<<url().url()<<" extern: "<<isStoredExtern()<<" current: "<<d->m_current<<endl; 01735 KoDocument *doc = dynamic_cast<KoDocument *>( parent() ); 01736 QString caption; 01737 if ( (url().isEmpty() || isStoredExtern()) && d->m_current ) 01738 { 01739 // Get caption from document info (title(), in about page) 01740 if ( documentInfo() ) 01741 { 01742 KoDocumentInfoPage * page = documentInfo()->page( QString::fromLatin1("about") ); 01743 if (page) 01744 caption = static_cast<KoDocumentInfoAbout *>(page)->title(); 01745 } 01746 if ( caption.isEmpty() ) 01747 caption = url().prettyURL( 0, KURL::StripFileProtocol ); // Fall back to document URL 01748 01749 //kdDebug(30003)<<k_funcinfo<<" url: "<<url().url()<<" caption: "<<caption<<endl; 01750 if ( doc ) 01751 { 01752 doc->setTitleModified( caption, isModified() ); 01753 return; 01754 } 01755 else 01756 { 01757 // we must be root doc so update caption in all related windows 01758 setTitleModified( caption, isModified() ); 01759 return; 01760 } 01761 } 01762 if ( doc ) 01763 { 01764 // internal doc or not current doc, so pass on the buck 01765 doc->setTitleModified(); 01766 } 01767 } 01768 01769 bool KoDocument::loadChildren( KoStore* ) 01770 { 01771 return true; 01772 } 01773 01774 bool KoDocument::completeLoading( KoStore* ) 01775 { 01776 return true; 01777 } 01778 01779 bool KoDocument::completeSaving( KoStore* ) 01780 { 01781 return true; 01782 } 01783 01784 QDomDocument KoDocument::createDomDocument( const QString& tagName, const QString& version ) const 01785 { 01786 return createDomDocument( instance()->instanceName(), tagName, version ); 01787 } 01788 01789 //static 01790 QDomDocument KoDocument::createDomDocument( const QString& appName, const QString& tagName, const QString& version ) 01791 { 01792 QDomImplementation impl; 01793 QString url = QString("http://www.koffice.org/DTD/%1-%1.dtd").arg(appName).arg(version); 01794 QDomDocumentType dtype = impl.createDocumentType( tagName, 01795 QString("-//KDE//DTD %1 %1//EN").arg(appName).arg(version), 01796 url ); 01797 // The namespace URN doesn't need to include the version number. 01798 QString namespaceURN = QString("http://www.koffice.org/DTD/%1").arg(appName); 01799 QDomDocument doc = impl.createDocument( namespaceURN, tagName, dtype ); 01800 doc.insertBefore( doc.createProcessingInstruction( "xml", "version=\"1.0\" encoding=\"UTF-8\"" ), doc.documentElement() ); 01801 return doc; 01802 } 01803 01804 QDomDocument KoDocument::saveXML() 01805 { 01806 kdError(30003) << "KoDocument::saveXML not implemented" << endl; 01807 d->lastErrorMessage = i18n( "Internal error: saveXML not implemented" ); 01808 return QDomDocument(); 01809 } 01810 01811 KService::Ptr KoDocument::nativeService() 01812 { 01813 if ( !m_nativeService ) 01814 m_nativeService = readNativeService( instance() ); 01815 01816 return m_nativeService; 01817 } 01818 01819 QCString KoDocument::nativeFormatMimeType() const 01820 { 01821 KService::Ptr service = const_cast<KoDocument *>(this)->nativeService(); 01822 if ( !service ) 01823 return QCString(); 01824 return service->property( "X-KDE-NativeMimeType" ).toString().latin1(); 01825 } 01826 01827 //static 01828 KService::Ptr KoDocument::readNativeService( KInstance *instance ) 01829 { 01830 QString instname = instance ? instance->instanceName() : kapp->instanceName(); 01831 01832 // The new way is: we look for a foopart.desktop in the kde_services dir. 01833 QString servicepartname = instname + "part.desktop"; 01834 KService::Ptr service = KService::serviceByDesktopPath( servicepartname ); 01835 if ( service ) 01836 kdDebug(30003) << servicepartname << " found." << endl; 01837 if ( !service ) 01838 { 01839 // The old way is kept as fallback for compatibility, but in theory this is really never used anymore. 01840 01841 // Try by path first, so that we find the global one (which has the native mimetype) 01842 // even if the user created a kword.desktop in ~/.kde/share/applnk or any subdir of it. 01843 // If he created it under ~/.kde/share/applnk/Office/ then no problem anyway. 01844 service = KService::serviceByDesktopPath( QString::fromLatin1("Office/%1.desktop").arg(instname) ); 01845 } 01846 if ( !service ) 01847 service = KService::serviceByDesktopName( instname ); 01848 01849 #if KDE_IS_VERSION( 3, 1, 90 ) 01850 // workaround for 3.2-beta bug fixed in 3.2-final 01851 if ( !service ) 01852 service = KService::serviceByStorageId( QString::fromLatin1( "kde-" ) + instname ); 01853 #endif 01854 01855 if ( !service ) 01856 return service; // not found 01857 01858 // found, check that it's good 01859 if ( service->property( "X-KDE-NativeMimeType" ).toString().isEmpty() ) 01860 { 01861 // It may be that the servicetype "KOfficePart" is missing, which leads to this property not being known 01862 if ( KServiceType::serviceType( "KOfficePart" ) == 0L ) 01863 kdError(30003) << "The serviceType KOfficePart is missing. Check that you have a kofficepart.desktop file in the share/servicetypes directory." << endl; 01864 else if ( instname != "koshell" ) // hack for koshell 01865 kdWarning(30003) << service->desktopEntryPath() << ": no X-KDE-NativeMimeType entry!" << endl; 01866 } 01867 01868 return service; 01869 } 01870 01871 QCString KoDocument::readNativeFormatMimeType( KInstance *instance ) 01872 { 01873 KService::Ptr service = readNativeService( instance ); 01874 if ( !service ) 01875 return QCString(); 01876 return service->property( "X-KDE-NativeMimeType" ).toString().latin1(); 01877 } 01878 01879 void KoDocument::addShell( KoMainWindow *shell ) 01880 { 01881 if ( d->m_shells.findRef( shell ) == -1 ) 01882 { 01883 //kdDebug(30003) << "addShell: shell " << (void*)shell << " added to doc " << this << endl; 01884 d->m_shells.append( shell ); 01885 } 01886 } 01887 01888 void KoDocument::removeShell( KoMainWindow *shell ) 01889 { 01890 //kdDebug(30003) << "removeShell: shell " << (void*)shell << " removed from doc " << this << endl; 01891 d->m_shells.removeRef( shell ); 01892 } 01893 01894 const QPtrList<KoMainWindow>& KoDocument::shells() const 01895 { 01896 return d->m_shells; 01897 } 01898 01899 int KoDocument::shellCount() const 01900 { 01901 return d->m_shells.count(); 01902 } 01903 01904 DCOPObject * KoDocument::dcopObject() 01905 { 01906 if ( !d->m_dcopObject ) 01907 d->m_dcopObject = new KoDocumentIface( this ); 01908 return d->m_dcopObject; 01909 } 01910 01911 QCString KoDocument::dcopObjectId() const 01912 { 01913 return const_cast<KoDocument *>(this)->dcopObject()->objId(); 01914 } 01915 01916 void KoDocument::setErrorMessage( const QString& errMsg ) 01917 { 01918 d->lastErrorMessage = errMsg; 01919 } 01920 01921 bool KoDocument::isAutosaving() // BIC: add const 01922 { 01923 return d->m_autosaving; 01924 } 01925 01926 void KoDocument::removeAutoSaveFiles() 01927 { 01928 // Eliminate any auto-save file 01929 QString asf = autoSaveFile( m_file ); // the one in the current dir 01930 if ( QFile::exists( asf ) ) 01931 unlink( QFile::encodeName( asf ) ); 01932 asf = autoSaveFile( QString::null ); // and the one in $HOME 01933 if ( QFile::exists( asf ) ) 01934 unlink( QFile::encodeName( asf ) ); 01935 } 01936 01937 void KoDocument::setBackupFile( bool _b ) 01938 { 01939 d->m_backupFile = _b; 01940 } 01941 01942 bool KoDocument::backupFile()const 01943 { 01944 return d->m_backupFile; 01945 } 01946 01947 01948 void KoDocument::setBackupPath( const QString & _path) 01949 { 01950 d->m_backupPath = _path; 01951 } 01952 01953 QString KoDocument::backupPath()const 01954 { 01955 return d->m_backupPath; 01956 } 01957 01958 void KoDocument::setCurrent( bool on ) 01959 { 01960 //kdDebug(30003)<<k_funcinfo<<" url: "<<url().url()<<" set to: "<<on<<endl; 01961 KoDocument *doc = dynamic_cast<KoDocument *>( parent() ); 01962 if ( doc ) 01963 { 01964 if ( !isStoredExtern() ) 01965 { 01966 // internal doc so set next external to current (for safety) 01967 doc->setCurrent( true ); 01968 return; 01969 } 01970 // only externally stored docs shall have file name in title 01971 d->m_current = on; 01972 if ( !on ) 01973 { 01974 doc->setCurrent( true ); // let my next external parent take over 01975 return; 01976 } 01977 doc->forceCurrent( false ); // everybody else should keep off 01978 } 01979 else 01980 d->m_current = on; 01981 01982 setTitleModified(); 01983 } 01984 01985 void KoDocument::forceCurrent( bool on ) 01986 { 01987 //kdDebug(30003)<<k_funcinfo<<" url: "<<url().url()<<" force to: "<<on<<endl; 01988 d->m_current = on; 01989 KoDocument *doc = dynamic_cast<KoDocument *>( parent() ); 01990 if ( doc ) 01991 { 01992 doc->forceCurrent( false ); 01993 } 01994 } 01995 01996 bool KoDocument::isCurrent() const 01997 { 01998 return d->m_current; 01999 } 02000 02001 bool KoDocument::storeInternal() const 02002 { 02003 return d->m_storeInternal; 02004 } 02005 02006 void KoDocument::setStoreInternal( bool i ) 02007 { 02008 d->m_storeInternal = i; 02009 //kdDebug(30003)<<k_funcinfo<<"="<<d->m_storeInternal<<" doc: "<<url().url()<<endl; 02010 } 02011 02012 bool KoDocument::hasExternURL() 02013 { 02014 return !url().protocol().isEmpty() && url().protocol() != STORE_PROTOCOL && url().protocol() != INTERNAL_PROTOCOL; 02015 } 02016 02017 KoDocument::InitDocFlags KoDocument::initDocFlags() const 02018 { 02019 return d->m_initDocFlags; 02020 } 02021 02022 void KoDocument::setInitDocFlags( InitDocFlags flags ) 02023 { 02024 d->m_initDocFlags = flags; 02025 } 02026 02027 void KoDocument::slotStarted( KIO::Job* job ) 02028 { 02029 if ( job ) 02030 { 02031 job->setWindow( d->m_shells.current() ); 02032 } 02033 } 02034 02035 #include "koDocument_p.moc" 02036 #include "koDocument.moc"
KDE Logo
This file is part of the documentation for lib Library Version 1.3.3.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Fri Sep 24 18:22:23 2004 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003