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.5.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Fri Mar 11 11:47:41 2005 by doxygen 1.3.9.1 written by Dimitri van Heesch, © 1997-2003