lib

KoDocument.cpp

00001 /* This file is part of the KDE project
00002    Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
00003    Copyright (C) 2000-2005 David Faure <faure@kde.org>
00004 
00005    This library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Library General Public
00007    License as published by the Free Software Foundation; either
00008    version 2 of the License, or (at your option) any later version.
00009 
00010    This library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Library General Public License for more details.
00014 
00015    You should have received a copy of the GNU Library General Public License
00016    along with this library; see the file COPYING.LIB.  If not, write to
00017    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00018  * Boston, MA 02110-1301, USA.
00019 */
00020 
00021 #include "KoDocument.h"
00022 
00023 #include "KoDocument_p.h"
00024 #include "KoDocumentIface.h"
00025 #include "KoDocumentChild.h"
00026 #include "KoView.h"
00027 #include "KoMainWindow.h"
00028 #include "KoFilterManager.h"
00029 #include "KoDocumentInfo.h"
00030 #include "KoOasisStyles.h"
00031 #include "KoOasisStore.h"
00032 #include "KoXmlNS.h"
00033 #include "KoOpenPane.h"
00034 
00035 #include <KoStoreDevice.h>
00036 #include <KoXmlWriter.h>
00037 
00038 #include <kapplication.h>
00039 #include <kdebug.h>
00040 #include <kdeversion.h>
00041 #include <kfileitem.h>
00042 #include <kiconloader.h>
00043 #include <kio/job.h>
00044 #include <kio/netaccess.h>
00045 #include <klocale.h>
00046 #include <kmessagebox.h>
00047 #include <kmimetype.h>
00048 #include <kparts/partmanager.h>
00049 #include <kprinter.h>
00050 #include <ksavefile.h>
00051 
00052 #include <qbuffer.h>
00053 #include <qcursor.h>
00054 #include <qdir.h>
00055 #include <qfile.h>
00056 #include <qfileinfo.h>
00057 #include <qimage.h>
00058 #include <qmap.h>
00059 #include <qpainter.h>
00060 #include <qtimer.h>
00061 #include <qxml.h>
00062 #include <qlayout.h>
00063 
00064 #include <config.h>
00065 #include <assert.h>
00066 #include <locale.h>
00067 
00068 
00069 // Define the protocol used here for embedded documents' URL
00070 // This used to "store" but KURL didn't like it,
00071 // so let's simply make it "tar" !
00072 #define STORE_PROTOCOL "tar"
00073 // The internal path is a hack to make KURL happy and still pass
00074 // some kind of relative path to KoDocumentChild
00075 #define INTERNAL_PROTOCOL "intern"
00076 #define INTERNAL_PREFIX "intern:/"
00077 // Warning, keep it sync in koStore.cc and koDocumentChild.cc
00078 
00079 QPtrList<KoDocument> *KoDocument::s_documentList=0L;
00080 
00081 using namespace std;
00082 class KoViewWrapperWidget;
00083 
00084 /**********************************************************
00085  *
00086  * KoDocument
00087  *
00088  **********************************************************/
00089 
00090 const int KoDocument::s_defaultAutoSave = 300; // 5 minutes
00091 
00092 class KoDocument::Private
00093 {
00094 public:
00095     Private() :
00096         m_dcopObject( 0L ),
00097         filterManager( 0L ),
00098         m_specialOutputFlag( 0 ), // default is native format
00099         m_isImporting( false ), m_isExporting( false ),
00100         m_numOperations( 0 ),
00101         modifiedAfterAutosave( false ),
00102         m_autosaving( false ),
00103         m_shouldCheckAutoSaveFile( true ),
00104         m_autoErrorHandlingEnabled( true ),
00105         m_backupFile( true ),
00106         m_backupPath( QString::null ),
00107         m_doNotSaveExtDoc( false ),
00108         m_current( false ),
00109         m_storeInternal( false ),
00110         m_bLoading( false ),
00111         m_startUpWidget( 0 )
00112     {
00113         m_confirmNonNativeSave[0] = true;
00114         m_confirmNonNativeSave[1] = true;
00115         if ( KGlobal::locale()->measureSystem() == KLocale::Imperial ) {
00116             m_unit = KoUnit::U_INCH;
00117         } else {
00118             m_unit = KoUnit::U_CM;
00119         }
00120     }
00121 
00122     QPtrList<KoView> m_views;
00123     QPtrList<KoDocumentChild> m_children;
00124     QPtrList<KoMainWindow> m_shells;
00125     QValueList<QDomDocument> m_viewBuildDocuments;
00126 
00127     KoViewWrapperWidget *m_wrapperWidget;
00128     KoDocumentIface * m_dcopObject;
00129     KoDocumentInfo *m_docInfo;
00130     KoView* hitTestView;
00131 
00132     KoUnit::Unit m_unit;
00133 
00134     KoFilterManager * filterManager; // The filter-manager to use when loading/saving [for the options]
00135 
00136     QCString mimeType; // The actual mimetype of the document
00137     QCString outputMimeType; // The mimetype to use when saving
00138     bool m_confirmNonNativeSave [2]; // used to pop up a dialog when saving for the
00139                                      // first time if the file is in a foreign format
00140                                      // (Save/Save As, Export)
00141     int m_specialOutputFlag; // See KoFileDialog in koMainWindow.cc
00142     bool m_isImporting, m_isExporting; // File --> Import/Export vs File --> Open/Save
00143 
00144     QTimer m_autoSaveTimer;
00145     QString lastErrorMessage; // see openFile()
00146     int m_autoSaveDelay; // in seconds, 0 to disable.
00147     int m_numOperations;
00148     bool modifiedAfterAutosave;
00149     bool m_bSingleViewMode;
00150     bool m_autosaving;
00151     bool m_shouldCheckAutoSaveFile; // usually true
00152     bool m_autoErrorHandlingEnabled; // usually true
00153     bool m_backupFile;
00154     QString m_backupPath;
00155     bool m_doNotSaveExtDoc; // makes it possible to save only internally stored child documents
00156     bool m_current;
00157     bool m_storeInternal; // Store this doc internally even if url is external
00158     bool m_bLoading; // True while loading (openURL is async)
00159 
00160     KoOpenPane* m_startUpWidget;
00161     QString m_templateType;
00162 };
00163 
00164 // Used in singleViewMode
00165 class KoViewWrapperWidget : public QWidget
00166 {
00167 public:
00168     KoViewWrapperWidget( QWidget *parent, const char *name )
00169         : QWidget( parent, name )
00170     {
00171         KGlobal::locale()->insertCatalogue("koffice");
00172         // Tell the iconloader about share/apps/koffice/icons
00173         KGlobal::iconLoader()->addAppDir("koffice");
00174         m_view = 0L;
00175         // Avoid warning from KParts - we'll have the KoView as focus proxy anyway
00176         setFocusPolicy( ClickFocus );
00177     }
00178 
00179     virtual ~KoViewWrapperWidget() {
00180         setFocusProxy( 0 ); // to prevent a crash due to clearFocus (#53466)
00181     }
00182 
00183     virtual void resizeEvent( QResizeEvent * )
00184     {
00185         QObject *wid = child( 0, "QWidget" );
00186         if ( wid )
00187             static_cast<QWidget *>(wid)->setGeometry( 0, 0, width(), height() );
00188     }
00189 
00190     virtual void childEvent( QChildEvent *ev )
00191     {
00192         if ( ev->type() == QEvent::ChildInserted )
00193             resizeEvent( 0L );
00194     }
00195 
00196     // Called by openFile()
00197     void setKoView( KoView * view ) {
00198         m_view = view;
00199         setFocusProxy( m_view );
00200     }
00201     KoView * koView() const { return m_view; }
00202 private:
00203     KoView* m_view;
00204 };
00205 
00206 KoBrowserExtension::KoBrowserExtension( KoDocument * doc, const char * name )
00207     : KParts::BrowserExtension( doc, name )
00208 {
00209     emit enableAction( "print", true );
00210 }
00211 
00212 void KoBrowserExtension::print()
00213 {
00214     KoDocument * doc = static_cast<KoDocument *>( parent() );
00215     KoViewWrapperWidget * wrapper = static_cast<KoViewWrapperWidget *>( doc->widget() );
00216     KoView * view = wrapper->koView();
00217     // TODO remove code duplication (KoMainWindow), by moving this to KoView
00218     KPrinter printer;
00219     // ### TODO: apply global koffice settings here
00220     view->setupPrinter( printer );
00221     if ( printer.setup( view ) )
00222         view->print( printer );
00223 }
00224 
00225 KoDocument::KoDocument( QWidget * parentWidget, const char *widgetName, QObject* parent, const char* name, bool singleViewMode )
00226     : KParts::ReadWritePart( parent, name )
00227 {
00228     if(s_documentList==0L)
00229         s_documentList=new QPtrList<KoDocument>;
00230     s_documentList->append(this);
00231 
00232     d = new Private;
00233     m_bEmpty = TRUE;
00234     connect( &d->m_autoSaveTimer, SIGNAL( timeout() ), this, SLOT( slotAutoSave() ) );
00235     setAutoSave( s_defaultAutoSave );
00236     d->m_bSingleViewMode = singleViewMode;
00237 
00238 
00239     // the parent setting *always* overrides! (Simon)
00240     if ( parent )
00241     {
00242         if ( parent->inherits( "KoDocument" ) )
00243             d->m_bSingleViewMode = ((KoDocument *)parent)->isSingleViewMode();
00244         else if ( parent->inherits( "KParts::Part" ) )
00245             d->m_bSingleViewMode = true;
00246     }
00247 
00248     if ( singleViewMode )
00249     {
00250         d->m_wrapperWidget = new KoViewWrapperWidget( parentWidget, widgetName );
00251         setWidget( d->m_wrapperWidget );
00252         kdDebug(30003) << "creating KoBrowserExtension" << endl;
00253         (void) new KoBrowserExtension( this ); // ## only if embedded into a browser?
00254     }
00255 
00256     d->m_docInfo = new KoDocumentInfo( this, "document info" );
00257 
00258     m_pageLayout.ptWidth = 0;
00259     m_pageLayout.ptHeight = 0;
00260     m_pageLayout.ptTop = 0;
00261     m_pageLayout.ptBottom = 0;
00262     m_pageLayout.ptLeft = 0;
00263     m_pageLayout.ptRight = 0;
00264 
00265     // A way to 'fix' the job's window, since we have no widget known to KParts
00266     if ( !singleViewMode )
00267         connect( this, SIGNAL( started( KIO::Job* ) ), SLOT( slotStarted( KIO::Job* ) ) );
00268 }
00269 
00270 KoDocument::~KoDocument()
00271 {
00272     d->m_autoSaveTimer.stop();
00273 
00274     QPtrListIterator<KoDocumentChild> childIt( d->m_children );
00275     for (; childIt.current(); ++childIt )
00276         disconnect( childIt.current(), SIGNAL( destroyed() ),
00277                     this, SLOT( slotChildDestroyed() ) );
00278 
00279     // Tell our views that the document is already destroyed and
00280     // that they shouldn't try to access it.
00281     QPtrListIterator<KoView> vIt( d->m_views );
00282     for (; vIt.current(); ++vIt )
00283         vIt.current()->setDocumentDeleted();
00284 
00285     delete d->m_startUpWidget;
00286     d->m_startUpWidget = 0;
00287 
00288     d->m_children.setAutoDelete( true );
00289     d->m_children.clear();
00290 
00291     d->m_shells.setAutoDelete( true );
00292     d->m_shells.clear();
00293 
00294     delete d->m_dcopObject;
00295     delete d->filterManager;
00296     delete d;
00297     s_documentList->removeRef(this);
00298     // last one?
00299     if(s_documentList->isEmpty()) {
00300         delete s_documentList;
00301         s_documentList=0;
00302     }
00303 }
00304 
00305 bool KoDocument::isSingleViewMode() const
00306 {
00307     return d->m_bSingleViewMode;
00308 }
00309 
00310 bool KoDocument::isEmbedded() const
00311 {
00312     return dynamic_cast<KoDocument *>( parent() ) != 0;
00313 }
00314 
00315 KoView *KoDocument::createView( QWidget *parent, const char *name )
00316 {
00317     KoView *view=createViewInstance(parent, name);
00318     addView(view);
00319     return view;
00320 }
00321 
00322 bool KoDocument::exp0rt( const KURL & _url )
00323 {
00324     bool ret;
00325 
00326     d->m_isExporting = true;
00327 
00328     //
00329     // Preserve a lot of state here because we need to restore it in order to
00330     // be able to fake a File --> Export.  Can't do this in saveFile() because,
00331     // for a start, KParts has already set m_url and m_file and because we need
00332     // to restore the modified flag etc. and don't want to put a load on anyone
00333     // reimplementing saveFile() (Note: import() and export() will remain
00334     // non-virtual).
00335     //
00336     KURL oldURL = m_url;
00337     QString oldFile = m_file;
00338 
00339     bool wasModified = isModified ();
00340     QCString oldMimeType = mimeType ();
00341 
00342 
00343     // save...
00344     ret = saveAs( _url );
00345 
00346 
00347     //
00348     // This is sooooo hacky :(
00349     // Hopefully we will restore enough state.
00350     //
00351     kdDebug(30003) << "Restoring KoDocument state to before export" << endl;
00352 
00353     // always restore m_url & m_file because KParts has changed them
00354     // (regardless of failure or success)
00355     m_url = oldURL;
00356     m_file = oldFile;
00357 
00358     // on successful export we need to restore modified etc. too
00359     // on failed export, mimetype/modified hasn't changed anyway
00360     if (ret)
00361     {
00362         setModified (wasModified);
00363         d->mimeType = oldMimeType;
00364     }
00365 
00366 
00367     d->m_isExporting = false;
00368 
00369     return ret;
00370 }
00371 
00372 bool KoDocument::saveFile()
00373 {
00374     kdDebug(30003) << "KoDocument::saveFile() doc='" << url().url() <<"'"<< endl;
00375     
00376     // set local again as it can happen that it gets resetted
00377     // so that all saved numbers have a . and not e.g a , as a 
00378     // decimal seperator
00379     setlocale( LC_NUMERIC, "C" );
00380 
00381     // Save it to be able to restore it after a failed save
00382     const bool wasModified = isModified ();
00383 
00384     // The output format is set by koMainWindow, and by openFile
00385     QCString outputMimeType = d->outputMimeType;
00386     //Q_ASSERT( !outputMimeType.isEmpty() ); // happens when using the DCOP method saveAs
00387     if ( outputMimeType.isEmpty() )
00388         outputMimeType = d->outputMimeType = nativeFormatMimeType();
00389 
00390     QApplication::setOverrideCursor( waitCursor );
00391 
00392     if ( backupFile() ) {
00393         if ( url().isLocalFile() )
00394             KSaveFile::backupFile( url().path(), d->m_backupPath );
00395         else {
00396             KIO::UDSEntry entry;
00397             if ( KIO::NetAccess::stat( url(), entry, shells().current() ) ) { // this file exists => backup
00398                 emit sigStatusBarMessage( i18n("Making backup...") );
00399                 KURL backup;
00400                 if ( d->m_backupPath.isEmpty())
00401                     backup = url();
00402                 else
00403                     backup = d->m_backupPath +"/"+url().fileName();
00404                 backup.setPath( backup.path() + QString::fromLatin1("~") );
00405                 KFileItem item( entry, url() );
00406                 Q_ASSERT( item.name() == url().fileName() );
00407                 KIO::NetAccess::file_copy( url(), backup, item.permissions(), true /*overwrite*/, false /*resume*/, shells().current() );
00408             }
00409         }
00410     }
00411 
00412     emit sigStatusBarMessage( i18n("Saving...") );
00413     bool ret = false;
00414     bool suppressErrorDialog = false;
00415     if ( !isNativeFormat( outputMimeType ) ) {
00416         kdDebug(30003) << "Saving to format " << outputMimeType << " in " << m_file << endl;
00417         // Not native format : save using export filter
00418         if ( !d->filterManager )
00419             d->filterManager = new KoFilterManager( this );
00420 
00421         KoFilter::ConversionStatus status = d->filterManager->exp0rt( m_file, outputMimeType );
00422         ret = status == KoFilter::OK;
00423         suppressErrorDialog = (status == KoFilter::UserCancelled || status == KoFilter::BadConversionGraph );
00424     } else {
00425         // Native format => normal save
00426         Q_ASSERT( !m_file.isEmpty() );
00427         ret = saveNativeFormat( m_file );
00428     }
00429 
00430     if ( ret ) {
00431         removeAutoSaveFiles();
00432         // Restart the autosave timer
00433         // (we don't want to autosave again 2 seconds after a real save)
00434         setAutoSave( d->m_autoSaveDelay );
00435     }
00436 
00437     QApplication::restoreOverrideCursor();
00438     if ( !ret )
00439     {
00440         if ( !suppressErrorDialog )
00441         {
00442             showSavingErrorDialog();
00443         }
00444 
00445         // couldn't save file so this new URL is invalid
00446         // FIXME: we should restore the current document's true URL instead of
00447         // setting it to nothing otherwise anything that depends on the URL
00448         // being correct will not work (i.e. the document will be called
00449         // "Untitled" which may not be true)
00450         //
00451         // Update: now the URL is restored in KoMainWindow but really, this
00452         // should still be fixed in KoDocument/KParts (ditto for m_file).
00453         // We still resetURL() here since we may or may not have been called
00454         // by KoMainWindow - Clarence
00455         resetURL();
00456 
00457     // As we did not save, restore the "was modified" status
00458         setModified( wasModified );
00459     }
00460 
00461     if ( ret )
00462     {
00463         d->mimeType = outputMimeType;
00464         setConfirmNonNativeSave ( isExporting (), false );
00465     }
00466     emit sigClearStatusBarMessage();
00467 
00468     return ret;
00469 }
00470 
00471 QCString KoDocument::mimeType() const
00472 {
00473     return d->mimeType;
00474 }
00475 
00476 void KoDocument::setMimeType( const QCString & mimeType )
00477 {
00478     d->mimeType = mimeType;
00479 }
00480 
00481 void KoDocument::setOutputMimeType( const QCString & mimeType, int specialOutputFlag )
00482 {
00483     d->outputMimeType = mimeType;
00484     d->m_specialOutputFlag = specialOutputFlag;
00485 }
00486 
00487 QCString KoDocument::outputMimeType() const
00488 {
00489     return d->outputMimeType;
00490 }
00491 
00492 int KoDocument::specialOutputFlag() const
00493 {
00494     return d->m_specialOutputFlag;
00495 }
00496 
00497 bool KoDocument::confirmNonNativeSave( const bool exporting ) const
00498 {
00499     // "exporting ? 1 : 0" is different from "exporting" because a bool is
00500     // usually implemented like an "int", not "unsigned : 1"
00501     return d->m_confirmNonNativeSave [ exporting ? 1 : 0 ];
00502 }
00503 
00504 void KoDocument::setConfirmNonNativeSave( const bool exporting, const bool on )
00505 {
00506     d->m_confirmNonNativeSave [ exporting ? 1 : 0] = on;
00507 }
00508 
00509 bool KoDocument::wantExportConfirmation() const
00510 {
00511     return true;
00512 }
00513 
00514 bool KoDocument::isImporting() const
00515 {
00516     return d->m_isImporting;
00517 }
00518 
00519 bool KoDocument::isExporting() const
00520 {
00521     return d->m_isExporting;
00522 }
00523 
00524 void KoDocument::setCheckAutoSaveFile( bool b )
00525 {
00526     d->m_shouldCheckAutoSaveFile = b;
00527 }
00528 
00529 void KoDocument::setAutoErrorHandlingEnabled( bool b )
00530 {
00531     d->m_autoErrorHandlingEnabled = b;
00532 }
00533 
00534 bool KoDocument::isAutoErrorHandlingEnabled() const
00535 {
00536     return d->m_autoErrorHandlingEnabled;
00537 }
00538 
00539 void KoDocument::slotAutoSave()
00540 {
00541     if ( isModified() && d->modifiedAfterAutosave && !d->m_bLoading )
00542     {
00543         connect( this, SIGNAL( sigProgress( int ) ), shells().current(), SLOT( slotProgress( int ) ) );
00544         emit sigStatusBarMessage( i18n("Autosaving...") );
00545         d->m_autosaving = true;
00546         bool ret = saveNativeFormat( autoSaveFile( m_file ) );
00547         setModified( true );
00548         if ( ret ) {
00549             d->modifiedAfterAutosave = false;
00550             d->m_autoSaveTimer.stop(); // until the next change
00551         }
00552         d->m_autosaving = false;
00553         emit sigClearStatusBarMessage();
00554         disconnect( this, SIGNAL( sigProgress( int ) ), shells().current(), SLOT( slotProgress( int ) ) );
00555         if ( !ret )
00556             emit sigStatusBarMessage( i18n("Error during autosave! Partition full?") );
00557     }
00558 }
00559 
00560 KAction *KoDocument::action( const QDomElement &element ) const
00561 {
00562     // First look in the document itself
00563     KAction* act = KParts::ReadWritePart::action( element );
00564     if ( act )
00565         return act;
00566 
00567     Q_ASSERT( d->m_bSingleViewMode );
00568     // Then look in the first view (this is for the single view mode)
00569     if ( !d->m_views.isEmpty() )
00570         return d->m_views.getFirst()->action( element );
00571     else
00572         return 0L;
00573 }
00574 
00575 QDomDocument KoDocument::domDocument() const
00576 {
00577     // When embedded into e.g. konqueror, we want the view's GUI (hopefully a reduced one)
00578     // to be used.
00579     Q_ASSERT( d->m_bSingleViewMode );
00580     if ( d->m_views.isEmpty() )
00581         return QDomDocument();
00582     else
00583         return d->m_views.getFirst()->domDocument();
00584 }
00585 
00586 void KoDocument::setManager( KParts::PartManager *manager )
00587 {
00588     KParts::ReadWritePart::setManager( manager );
00589     if ( d->m_bSingleViewMode && d->m_views.count() == 1 )
00590         d->m_views.getFirst()->setPartManager( manager );
00591 
00592     if ( manager )
00593     {
00594         QPtrListIterator<KoDocumentChild> it( d->m_children );
00595         for (; it.current(); ++it )
00596             if ( it.current()->document() )
00597                 manager->addPart( it.current()->document(), false );
00598     }
00599 }
00600 
00601 void KoDocument::setReadWrite( bool readwrite )
00602 {
00603     KParts::ReadWritePart::setReadWrite( readwrite );
00604 
00605     QPtrListIterator<KoView> vIt( d->m_views );
00606     for (; vIt.current(); ++vIt )
00607         vIt.current()->updateReadWrite( readwrite );
00608 
00609     QPtrListIterator<KoDocumentChild> dIt( d->m_children );
00610     for (; dIt.current(); ++dIt )
00611         if ( dIt.current()->document() )
00612             dIt.current()->document()->setReadWrite( readwrite );
00613 
00614     setAutoSave( d->m_autoSaveDelay );
00615 }
00616 
00617 void KoDocument::setAutoSave( int delay )
00618 {
00619     d->m_autoSaveDelay = delay;
00620     if ( isReadWrite() && !isEmbedded() && d->m_autoSaveDelay > 0 )
00621         d->m_autoSaveTimer.start( d->m_autoSaveDelay * 1000 );
00622     else
00623         d->m_autoSaveTimer.stop();
00624 }
00625 
00626 void KoDocument::addView( KoView *view )
00627 {
00628     if ( !view )
00629         return;
00630 
00631     d->m_views.append( view );
00632     view->updateReadWrite( isReadWrite() );
00633 }
00634 
00635 void KoDocument::removeView( KoView *view )
00636 {
00637     d->m_views.removeRef( view );
00638 }
00639 
00640 const QPtrList<KoView>& KoDocument::views() const
00641 {
00642     return d->m_views;
00643 }
00644 
00645 int KoDocument::viewCount() const
00646 {
00647     return d->m_views.count();
00648 }
00649 
00650 void KoDocument::insertChild( KoDocumentChild *child )
00651 {
00652     setModified( true );
00653 
00654     d->m_children.append( child );
00655 
00656     connect( child, SIGNAL( changed( KoChild * ) ),
00657              this, SLOT( slotChildChanged( KoChild * ) ) );
00658     connect( child, SIGNAL( destroyed() ),
00659              this, SLOT( slotChildDestroyed() ) );
00660 
00661     // It may be that insertChild is called without the KoDocumentChild
00662     // having a KoDocument attached, yet. This happens for example
00663     // when KPresenter loads a document with embedded objects. For those
00664     // KPresenterChild objects are allocated and insertChild is called.
00665     // Later in loadChildren() KPresenter iterates over the child list
00666     // and calls loadDocument for each child. That's exactly where we
00667     // will try to do what we cannot do now: Register the child document
00668     // at the partmanager (Simon)
00669     if ( manager() && !isSingleViewMode() && child->document() )
00670         manager()->addPart( child->document(), false );
00671 }
00672 
00673 void KoDocument::slotChildChanged( KoChild *c )
00674 {
00675     assert( c->inherits( "KoDocumentChild" ) );
00676     emit childChanged( static_cast<KoDocumentChild *>( c ) );
00677 }
00678 
00679 void KoDocument::slotChildDestroyed()
00680 {
00681     setModified( true );
00682 
00683     const KoDocumentChild *child = static_cast<const KoDocumentChild *>( sender() );
00684     d->m_children.removeRef( child );
00685 }
00686 
00687 const QPtrList<KoDocumentChild>& KoDocument::children() const
00688 {
00689     return d->m_children;
00690 }
00691 
00692 KParts::Part *KoDocument::hitTest( QWidget *widget, const QPoint &globalPos )
00693 {
00694     QPtrListIterator<KoView> it( d->m_views );
00695     for (; it.current(); ++it )
00696         if ( static_cast<QWidget *>(it.current()) == widget )
00697         {
00698             KoView* view = it.current();
00699             d->hitTestView = view; // koffice-1.x hack
00700             QPoint canvasPos( view->canvas()->mapFromGlobal( globalPos ) );
00701             canvasPos.rx() += view->canvasXOffset();
00702             canvasPos.ry() += view->canvasYOffset();
00703 
00704             KParts::Part *part = view->hitTest( canvasPos );
00705             d->hitTestView = 0;
00706             if ( part )
00707                 return part;
00708         }
00709 
00710     return 0L;
00711 }
00712 
00713 KoView* KoDocument::hitTestView()
00714 {
00715     return d->hitTestView;
00716 }
00717 
00718 KoDocument* KoDocument::hitTest( const QPoint &pos, const QWMatrix &matrix )
00719 {
00720     // Call KoDocumentChild::hitTest for any child document
00721     QPtrListIterator<KoDocumentChild> it( d->m_children );
00722     for (; it.current(); ++it )
00723     {
00724         KoDocument *doc = it.current()->hitTest( pos, matrix );
00725         if ( doc )
00726             return doc;
00727     }
00728 
00729     // Unless we hit an embedded document, the hit is on this document itself.
00730     return this;
00731 }
00732 
00733 KoDocumentChild *KoDocument::child( KoDocument *doc )
00734 {
00735     QPtrListIterator<KoDocumentChild> it( d->m_children );
00736     for (; it.current(); ++it )
00737         if ( it.current()->document() == doc )
00738             return it.current();
00739 
00740     return 0L;
00741 }
00742 
00743 KoDocumentInfo *KoDocument::documentInfo() const
00744 {
00745     return d->m_docInfo;
00746 }
00747 
00748 void KoDocument::setViewBuildDocument( KoView *view, const QDomDocument &doc )
00749 {
00750     if ( d->m_views.find( view ) == -1 )
00751         return;
00752 
00753     uint viewIdx = d->m_views.at();
00754 
00755     if ( d->m_viewBuildDocuments.count() == viewIdx )
00756         d->m_viewBuildDocuments.append( doc );
00757     else if ( d->m_viewBuildDocuments.count() > viewIdx )
00758         d->m_viewBuildDocuments[ viewIdx ] = doc;
00759 }
00760 
00761 QDomDocument KoDocument::viewBuildDocument( KoView *view )
00762 {
00763     QDomDocument res;
00764 
00765     if ( d->m_views.find( view ) == -1 )
00766         return res;
00767 
00768     uint viewIdx = d->m_views.at();
00769 
00770     if ( viewIdx >= d->m_viewBuildDocuments.count() )
00771         return res;
00772 
00773     res = d->m_viewBuildDocuments[ viewIdx ];
00774 
00775     // make this entry empty. otherwise we get a segfault in QMap ;-(
00776     d->m_viewBuildDocuments[ viewIdx ] = QDomDocument();
00777 
00778     return res;
00779 }
00780 
00781 void KoDocument::paintEverything( QPainter &painter, const QRect &rect, bool transparent, KoView *view, double zoomX, double zoomY )
00782 {
00783     paintContent( painter, rect, transparent, zoomX, zoomY );
00784     paintChildren( painter, rect, view, zoomX, zoomY );
00785 }
00786 
00787 void KoDocument::paintChildren( QPainter &painter, const QRect &/*rect*/, KoView *view, double zoomX, double zoomY )
00788 {
00789     QPtrListIterator<KoDocumentChild> it( d->m_children );
00790     for (; it.current(); ++it )
00791     {
00792         // #### todo: paint only if child is visible inside rect
00793         painter.save();
00794         paintChild( it.current(), painter, view, zoomX, zoomY );
00795         painter.restore();
00796     }
00797 }
00798 
00799 void KoDocument::paintChild( KoDocumentChild *child, QPainter &painter, KoView *view, double zoomX, double zoomY )
00800 {
00801     if ( child->isDeleted() )
00802         return;
00803 
00804     // QRegion rgn = painter.clipRegion();
00805 
00806     child->transform( painter );
00807     child->document()->paintEverything( painter, child->contentRect(), child->isTransparent(), view, zoomX, zoomY );
00808 
00809     if ( view && view->partManager() )
00810     {
00811         // ### do we need to apply zoomX and zoomY here ?
00812         KParts::PartManager *manager = view->partManager();
00813 
00814         painter.scale( 1.0 / child->xScaling(), 1.0 / child->yScaling() );
00815 
00816         int w = int( (double)child->contentRect().width() * child->xScaling() );
00817         int h = int( (double)child->contentRect().height() * child->yScaling() );
00818         if ( ( manager->selectedPart() == (KParts::Part *)child->document() &&
00819                manager->selectedWidget() == (QWidget *)view ) ||
00820              ( manager->activePart() == (KParts::Part *)child->document() &&
00821                manager->activeWidget() == (QWidget *)view ) )
00822         {
00823             // painter.setClipRegion( rgn );
00824             painter.setClipping( FALSE );
00825 
00826             painter.setPen( black );
00827             painter.fillRect( -5, -5, w + 10, 5, white );
00828             painter.fillRect( -5, h, w + 10, 5, white );
00829             painter.fillRect( -5, -5, 5, h + 10, white );
00830             painter.fillRect( w, -5, 5, h + 10, white );
00831             painter.fillRect( -5, -5, w + 10, 5, BDiagPattern );
00832             painter.fillRect( -5, h, w + 10, 5, BDiagPattern );
00833             painter.fillRect( -5, -5, 5, h + 10, BDiagPattern );
00834             painter.fillRect( w, -5, 5, h + 10, BDiagPattern );
00835 
00836             if ( manager->selectedPart() == (KParts::Part *)child->document() &&
00837                  manager->selectedWidget() == (QWidget *)view )
00838             {
00839                 QColor color;
00840                 if ( view->koDocument() == this )
00841                     color = black;
00842                 else
00843                     color = gray;
00844                 painter.fillRect( -5, -5, 5, 5, color );
00845                 painter.fillRect( -5, h, 5, 5, color );
00846                 painter.fillRect( w, h, 5, 5, color );
00847                 painter.fillRect( w, -5, 5, 5, color );
00848                 painter.fillRect( w / 2 - 3, -5, 5, 5, color );
00849                 painter.fillRect( w / 2 - 3, h, 5, 5, color );
00850                 painter.fillRect( -5, h / 2 - 3, 5, 5, color );
00851                 painter.fillRect( w, h / 2 - 3, 5, 5, color );
00852             }
00853 
00854             painter.setClipping( TRUE );
00855         }
00856     }
00857 }
00858 
00859 bool KoDocument::isModified() const
00860 {
00861     if ( KParts::ReadWritePart::isModified() )
00862     {
00863         //kdDebug(30003)<<k_funcinfo<<" Modified doc='"<<url().url()<<"' extern="<<isStoredExtern()<<endl;
00864         return true;
00865     }
00866     // Then go through internally stored children (considered to be part of this doc)
00867     QPtrListIterator<KoDocumentChild> it = children();
00868     for (; it.current(); ++it )
00869     {
00870         KoDocument *doc = it.current()->document();
00871         if ( doc && !it.current()->isStoredExtern() && !it.current()->isDeleted() && doc->isModified() )
00872             return true;
00873     }
00874     return false;
00875 }
00876 
00877 bool KoDocument::saveChildren( KoStore* _store )
00878 {
00879     //kdDebug(30003)<<k_funcinfo<<" checking children of doc='"<<url().url()<<"'"<<endl;
00880     int i = 0;
00881     QPtrListIterator<KoDocumentChild> it( children() );
00882     for( ; it.current(); ++it ) {
00883         KoDocument* childDoc = it.current()->document();
00884         if (childDoc && !it.current()->isDeleted())
00885         {
00886             if ( !childDoc->isStoredExtern() )
00887             {
00888                 //kdDebug(30003) << "KoDocument::saveChildren internal url: /" << i << endl;
00889                 if ( !childDoc->saveToStore( _store, QString::number( i++ ) ) )
00890                     return FALSE;
00891 
00892                 if (!isExporting ())
00893                     childDoc->setModified( false );
00894             }
00895             //else kdDebug(30003)<<k_funcinfo<<" external (don't save) url:" << childDoc->url().url()<<endl;
00896         }
00897     }
00898     return true;
00899 }
00900 
00901 bool KoDocument::saveChildrenOasis( KoStore* store, KoXmlWriter* manifestWriter )
00902 {
00903     //kdDebug(30003)<<k_funcinfo<<" checking children of doc='"<<url().url()<<"'"<<endl;
00904     QPtrListIterator<KoDocumentChild> it( children() );
00905     for( ; it.current(); ++it ) {
00906         KoDocument* childDoc = it.current()->document();
00907         if ( childDoc && !it.current()->isDeleted() )
00908         {
00909             if ( !it.current()->saveOasis( store, manifestWriter ) )
00910                 return false;
00911             if ( !childDoc->isStoredExtern() && !isExporting () )
00912                 childDoc->setModified( false );
00913         }
00914     }
00915     return true;
00916 }
00917 
00918 bool KoDocument::saveExternalChildren()
00919 {
00920     if ( d->m_doNotSaveExtDoc )
00921     {
00922         //kdDebug(30003)<<k_funcinfo<<" Don't save external docs in doc='"<<url().url()<<"'"<<endl;
00923         d->m_doNotSaveExtDoc = false;
00924         return true;
00925     }
00926 
00927     //kdDebug(30003)<<k_funcinfo<<" checking children of doc='"<<url().url()<<"'"<<endl;
00928     KoDocumentChild *ch;
00929     QPtrListIterator<KoDocumentChild> it = children();
00930     for (; (ch = it.current()); ++it )
00931     {
00932         if ( !ch->isDeleted() )
00933         {
00934             KoDocument* doc = ch->document();
00935             if ( doc && doc->isStoredExtern() && doc->isModified() )
00936             {
00937                 kdDebug(30003)<<" save external doc='"<<url().url()<<"'"<<endl;
00938                 doc->setDoNotSaveExtDoc(); // Only save doc + it's internal children
00939                 if ( !doc->save() )
00940                     return false; // error
00941             }
00942             //kdDebug(30003)<<k_funcinfo<<" not modified doc='"<<url().url()<<"'"<<endl;
00943             // save possible external docs inside doc
00944             if ( doc && !doc->saveExternalChildren() )
00945                 return false;
00946         }
00947     }
00948     return true;
00949 }
00950 
00951 bool KoDocument::saveNativeFormat( const QString & file )
00952 {
00953     d->lastErrorMessage = QString::null;
00954     //kdDebug(30003) << "Saving to store" << endl;
00955 
00956     KoStore::Backend backend = KoStore::Auto;
00957 #if 0
00958     if ( d->m_specialOutputFlag == SaveAsKOffice1dot1 )
00959     {
00960         kdDebug(30003) << "Saving as KOffice-1.1 format, using a tar.gz" << endl;
00961         backend = KoStore::Tar; // KOffice-1.0/1.1 used tar.gz for the native mimetype
00963     }
00964     else
00965 #endif
00966         if ( d->m_specialOutputFlag == SaveAsDirectoryStore )
00967     {
00968         backend = KoStore::Directory;
00969         kdDebug(30003) << "Saving as uncompressed XML, using directory store." << endl;
00970     }
00971     else if ( d->m_specialOutputFlag == SaveAsFlatXML )
00972     {
00973         kdDebug(30003) << "Saving as a flat XML file." << endl;
00974         QFile f( file );
00975         if ( f.open( IO_WriteOnly | IO_Translate ) )
00976         {
00977             bool success = saveToStream( &f );
00978             f.close();
00979             return success;
00980         }
00981         else
00982             return false;
00983     }
00984 
00985     kdDebug(30003) << "KoDocument::saveNativeFormat nativeFormatMimeType=" << nativeFormatMimeType() << endl;
00986     // OLD: bool oasis = d->m_specialOutputFlag == SaveAsOASIS;
00987     // OLD: QCString mimeType = oasis ? nativeOasisMimeType() : nativeFormatMimeType();
00988     QCString mimeType = d->outputMimeType;
00989     QCString nativeOasisMime = nativeOasisMimeType();
00990     bool oasis = !mimeType.isEmpty() && ( mimeType == nativeOasisMime || mimeType == nativeOasisMime + "-template" );
00991     // TODO: use std::auto_ptr or create store on stack [needs API fixing],
00992     // to remove all the 'delete store' in all the branches
00993     KoStore* store = KoStore::createStore( file, KoStore::Write, mimeType, backend );
00994     if ( store->bad() )
00995     {
00996         d->lastErrorMessage = i18n( "Could not create the file for saving" ); // more details needed?
00997         delete store;
00998         return false;
00999     }
01000 
01001     if ( oasis )
01002     {
01003         kdDebug(30003) << "Saving to OASIS format" << endl;
01004         // Tell KoStore not to touch the file names
01005         store->disallowNameExpansion();
01006         KoOasisStore oasisStore( store );
01007         KoXmlWriter* manifestWriter = oasisStore.manifestWriter( mimeType );
01008 
01009         if ( !saveOasis( store, manifestWriter ) )
01010         {
01011             kdDebug(30003) << "saveOasis failed" << endl;
01012             delete store;
01013             return false;
01014         }
01015 
01016         // Save embedded objects
01017         if ( !saveChildrenOasis( store, manifestWriter ) )
01018         {
01019             kdDebug(30003) << "saveChildrenOasis failed" << endl;
01020             delete store;
01021             return false;
01022         }
01023 
01024         if ( store->open( "meta.xml" ) )
01025         {
01026             if ( !d->m_docInfo->saveOasis( store ) || !store->close() ) {
01027                 delete store;
01028                 return false;
01029             }
01030             manifestWriter->addManifestEntry( "meta.xml", "text/xml" );
01031         }
01032         else
01033         {
01034             d->lastErrorMessage = i18n( "Not able to write '%1'. Partition full?" ).arg( "meta.xml" );
01035             delete store;
01036             return false;
01037         }
01038 
01039         if ( store->open( "Thumbnails/thumbnail.png" ) )
01040         {
01041             if ( !saveOasisPreview( store, manifestWriter ) || !store->close() ) {
01042                 d->lastErrorMessage = i18n( "Error while trying to write '%1'. Partition full?" ).arg( "Thumbnails/thumbnail.png" );
01043                 delete store;
01044                 return false;
01045             }
01046             // No manifest entry!
01047         }
01048         else
01049         {
01050             d->lastErrorMessage = i18n( "Not able to write '%1'. Partition full?" ).arg( "Thumbnails/thumbnail.png" );
01051             delete store;
01052             return false;
01053         }
01054 
01055         // Write out manifest file
01056         if ( !oasisStore.closeManifestWriter() )
01057         {
01058             d->lastErrorMessage = i18n( "Error while trying to write '%1'. Partition full?" ).arg( "META-INF/manifest.xml" );
01059             delete store;
01060             return false;
01061         }
01062 
01063         delete store;
01064     }
01065     else
01066     {
01067         // Save internal children first since they might get a new url
01068         if ( !saveChildren( store ) && !oasis )
01069         {
01070             if ( d->lastErrorMessage.isEmpty() )
01071                 d->lastErrorMessage = i18n( "Error while saving embedded documents" ); // more details needed
01072             delete store;
01073             return false;
01074         }
01075 
01076         kdDebug(30003) << "Saving root" << endl;
01077         if ( store->open( "root" ) )
01078         {
01079             KoStoreDevice dev( store );
01080             if ( !saveToStream( &dev ) || !store->close() )
01081             {
01082                 kdDebug(30003) << "saveToStream failed" << endl;
01083                 delete store;
01084                 return false;
01085             }
01086         }
01087         else
01088         {
01089             d->lastErrorMessage = i18n( "Not able to write '%1'. Partition full?" ).arg( "maindoc.xml" );
01090             delete store;
01091             return false;
01092         }
01093         if ( store->open( "documentinfo.xml" ) )
01094         {
01095             QDomDocument doc = d->m_docInfo->save();
01096             KoStoreDevice dev( store );
01097 
01098             QCString s = doc.toCString(); // this is already Utf8!
01099             (void)dev.writeBlock( s.data(), s.size()-1 );
01100             (void)store->close();
01101         }
01102 
01103         if ( store->open( "preview.png" ) )
01104         {
01105             // ### TODO: missing error checking (The partition could be full!)
01106             savePreview( store );
01107             (void)store->close();
01108         }
01109 
01110         if ( !completeSaving( store ) )
01111         {
01112             delete store;
01113             return false;
01114         }
01115         kdDebug(30003) << "Saving done of url: " << url().url() << endl;
01116         delete store;
01117     }
01118     if ( !saveExternalChildren() )
01119     {
01120         return false;
01121     }
01122     return true;
01123 }
01124 
01125 bool KoDocument::saveToStream( QIODevice * dev )
01126 {
01127     QDomDocument doc = saveXML();
01128     // Save to buffer
01129     QCString s = doc.toCString(); // utf8 already
01130     // We use QCString::size()-1 here, not the official QCString::length
01131     // It works here, as we are not modifying QCString as QByteArray
01132     int nwritten = dev->writeBlock( s.data(), s.size()-1 );
01133     if ( nwritten != (int)s.size()-1 )
01134         kdWarning(30003) << "KoDocument::saveToStream wrote " << nwritten << "   - expected " << s.size()-1 << endl;
01135     return nwritten == (int)s.size()-1;
01136 }
01137 
01138 // Called for embedded documents
01139 bool KoDocument::saveToStore( KoStore* _store, const QString & _path )
01140 {
01141     kdDebug(30003) << "Saving document to store " << _path << endl;
01142 
01143     // Use the path as the internal url
01144     if ( _path.startsWith( STORE_PROTOCOL ) )
01145         m_url = KURL( _path );
01146     else // ugly hack to pass a relative URI
01147         m_url = KURL( INTERNAL_PREFIX +  _path );
01148 
01149     // To make the children happy cd to the correct directory
01150     _store->pushDirectory();
01151     _store->enterDirectory( _path );
01152 
01153     // Save childen first since they might get a new url
01154     if ( !saveChildren( _store ) )
01155         return false;
01156 
01157     // In the current directory we're the king :-)
01158     if ( _store->open( "root" ) )
01159     {
01160         KoStoreDevice dev( _store );
01161         if ( !saveToStream( &dev ) )
01162         {
01163             _store->close();
01164             return false;
01165         }
01166         if ( !_store->close() )
01167             return false;
01168     }
01169 
01170     if ( !completeSaving( _store ) )
01171         return false;
01172 
01173     // Now that we're done leave the directory again
01174     _store->popDirectory();
01175 
01176     kdDebug(30003) << "Saved document to store" << endl;
01177 
01178     return true;
01179 }
01180 
01181 bool KoDocument::saveOasisPreview( KoStore* store, KoXmlWriter* manifestWriter )
01182 {
01183     const QPixmap pix = generatePreview( QSize( 128, 128 ) );
01184     QImage preview ( pix.convertToImage().convertDepth( 32, Qt::ColorOnly ) );
01185     if ( !preview.hasAlphaBuffer() )
01186     {
01187         preview.setAlphaBuffer( true );
01188     }
01189     // ### TODO: freedesktop.org Thumbnail specification (date...)
01190     KoStoreDevice io ( store );
01191     if ( !io.open( IO_WriteOnly ) )
01192         return false;
01193     if ( ! preview.save( &io, "PNG", 0 ) )
01194         return false;
01195     io.close();
01196     manifestWriter->addManifestEntry( "Thumbnails/", "" );
01197     manifestWriter->addManifestEntry( "Thumbnails/thumbnail.png", "" );
01198     return true;
01199 }
01200 
01201 bool KoDocument::savePreview( KoStore* store )
01202 {
01203     QPixmap pix = generatePreview(QSize(256, 256));
01204     // Reducing to 8bpp reduces file sizes quite a lot.
01205     const QImage preview ( pix.convertToImage().convertDepth( 8, Qt::AvoidDither | Qt::DiffuseDither) );
01206     KoStoreDevice io ( store );
01207     if ( !io.open( IO_WriteOnly ) )
01208         return false;
01209     if ( ! preview.save( &io, "PNG" ) ) // ### TODO What is -9 in quality terms?
01210         return false;
01211     io.close();
01212     return true;
01213 }
01214 
01215 QPixmap KoDocument::generatePreview( const QSize& size )
01216 {
01217     double docWidth, docHeight;
01218     int pixmapSize = QMAX(size.width(), size.height());
01219 
01220     if (m_pageLayout.ptWidth > 1.0) {
01221         docWidth = m_pageLayout.ptWidth / 72 * KoGlobal::dpiX();
01222         docHeight = m_pageLayout.ptHeight / 72 * KoGlobal::dpiY();
01223 
01224     } else {
01225         // If we don't have a page layout, just draw the top left hand corner
01226         docWidth = 500.0;
01227         docHeight = 500.0;
01228     }
01229 
01230     double ratio = docWidth / docHeight;
01231 
01232     QPixmap pix;
01233     int previewWidth, previewHeight;
01234     if (ratio > 1.0)
01235     {
01236         previewWidth = (int) pixmapSize;
01237         previewHeight = (int) (pixmapSize / ratio);
01238     }
01239     else
01240     {
01241         previewWidth = (int) (pixmapSize * ratio);
01242         previewHeight = (int) pixmapSize;
01243     }
01244 
01245     pix.resize((int)docWidth, (int)docHeight);
01246 
01247     pix.fill( QColor( 245, 245, 245 ) );
01248 
01249     QRect rc(0, 0, pix.width(), pix.height());
01250 
01251     QPainter p;
01252     p.begin(&pix);
01253     paintEverything(p, rc, false);
01254     p.end();
01255 
01256     // ### TODO: why re-convert it to a QPixmap, when mostly it will be re-converted back to a QImage in the calling function
01257     pix.convertFromImage(pix.convertToImage().smoothScale(previewWidth, previewHeight));
01258 
01259     return pix;
01260 }
01261 
01262 QString KoDocument::autoSaveFile( const QString & path ) const
01263 {
01264     // set local again as it can happen that it gets resetted
01265     // so that all saved numbers have a . and not e.g a , as a 
01266     // decimal seperator
01267     setlocale( LC_NUMERIC, "C" );
01268 
01269     // Using the extension allows to avoid relying on the mime magic when opening
01270     KMimeType::Ptr mime = KMimeType::mimeType( nativeFormatMimeType() );
01271     QString extension = mime->property( "X-KDE-NativeExtension" ).toString();
01272     if ( path.isEmpty() )
01273     {
01274         // Never saved? Use a temp file in $HOME then
01275         // Yes, two open unnamed docs will overwrite each other's autosave file,
01276         // but hmm, we can only do something if that's in the same process anyway...
01277         QString ret = QDir::homeDirPath() + "/." + QString::fromLatin1(instance()->instanceName()) + ".autosave" + extension;
01278         return ret;
01279     }
01280     else
01281     {
01282         KURL url( path );
01283         Q_ASSERT( url.isLocalFile() );
01284         QString dir = url.directory(false);
01285         QString filename = url.fileName();
01286         return dir + "." + filename + ".autosave" + extension;
01287     }
01288 }
01289 
01290 bool KoDocument::checkAutoSaveFile()
01291 {
01292     QString asf = autoSaveFile( QString::null ); // the one in $HOME
01293     //kdDebug(30003) << "asf=" << asf << endl;
01294     if ( QFile::exists( asf ) )
01295     {
01296         QDateTime date = QFileInfo(asf).lastModified();
01297         QString dateStr = date.toString(Qt::LocalDate);
01298         int res = KMessageBox::warningYesNoCancel(
01299             0, i18n( "An autosaved file for an unnamed document exists in %1.\nThis file is dated %2\nDo you want to open it?" )
01300             .arg(asf, dateStr) );
01301         switch(res) {
01302         case KMessageBox::Yes : {
01303             KURL url;
01304             url.setPath( asf );
01305             bool ret = openURL( url );
01306             if ( ret )
01307                 resetURL();
01308             return ret;
01309         }
01310         case KMessageBox::No :
01311             QFile::remove( asf );
01312             return false;
01313         default: // Cancel
01314             return false;
01315         }
01316     }
01317     return false;
01318 }
01319 
01320 bool KoDocument::import( const KURL & _url )
01321 {
01322     bool ret;
01323 
01324     kdDebug (30003) << "KoDocument::import url=" << _url.url() << endl;
01325     d->m_isImporting = true;
01326 
01327     // open...
01328     ret = openURL (_url);
01329 
01330     // reset m_url & m_file (kindly? set by KParts::openURL()) to simulate a
01331     // File --> Import
01332     if (ret)
01333     {
01334         kdDebug (30003) << "KoDocument::import success, resetting url" << endl;
01335         resetURL ();
01336         setTitleModified ();
01337     }
01338 
01339     d->m_isImporting = false;
01340 
01341     return ret;
01342 }
01343 
01344 bool KoDocument::openURL( const KURL & _url )
01345 {
01346     kdDebug(30003) << "KoDocument::openURL url=" << _url.url() << endl;
01347     d->lastErrorMessage = QString::null;
01348 
01349     // Reimplemented, to add a check for autosave files and to improve error reporting
01350     if ( !_url.isValid() )
01351     {
01352         d->lastErrorMessage = i18n( "Malformed URL\n%1" ).arg( _url.url() ); // ## used anywhere ?
01353         return false;
01354     }
01355     if ( !closeURL() )
01356         return false;
01357 
01358     KURL url( _url );
01359     bool autosaveOpened = false;
01360     d->m_bLoading = true;
01361     if ( url.isLocalFile() && d->m_shouldCheckAutoSaveFile )
01362     {
01363         QString file = url.path();
01364         QString asf = autoSaveFile( file );
01365         if ( QFile::exists( asf ) )
01366         {
01367             //kdDebug(30003) << "KoDocument::openURL asf=" << asf << endl;
01368             // ## TODO compare timestamps ?
01369             int res = KMessageBox::warningYesNoCancel( 0,
01370                                                        i18n( "An autosaved file exists for this document.\nDo you want to open it instead?" ));
01371             switch(res) {
01372                 case KMessageBox::Yes :
01373                     url.setPath( asf );
01374                     autosaveOpened = true;
01375                     break;
01376                 case KMessageBox::No :
01377                     QFile::remove( asf );
01378                     break;
01379                 default: // Cancel
01380                     d->m_bLoading = false;
01381                     return false;
01382             }
01383         }
01384     }
01385 
01386     bool ret = KParts::ReadWritePart::openURL( url );
01387 
01388     if ( autosaveOpened )
01389         resetURL(); // Force save to act like 'Save As'
01390     else
01391     {
01392         // We have no koffice shell when we are being embedded as a readonly part.
01393         //if ( d->m_shells.isEmpty() )
01394         //    kdWarning(30003) << "KoDocument::openURL no shell yet !" << endl;
01395         // Add to recent actions list in our shells
01396         QPtrListIterator<KoMainWindow> it( d->m_shells );
01397         for (; it.current(); ++it )
01398             it.current()->addRecentURL( _url );
01399     }
01400     return ret;
01401 }
01402 
01403 bool KoDocument::openFile()
01404 {
01405     //kdDebug(30003) << "KoDocument::openFile for " << m_file << endl;
01406     if ( !QFile::exists(m_file) )
01407     {
01408         QApplication::restoreOverrideCursor();
01409         if ( d->m_autoErrorHandlingEnabled )
01410             // Maybe offer to create a new document with that name ?
01411             KMessageBox::error(0L, i18n("The file %1 does not exist.").arg(m_file) );
01412         d->m_bLoading = false;
01413         return false;
01414     }
01415 
01416     QApplication::setOverrideCursor( waitCursor );
01417 
01418     d->m_specialOutputFlag = 0;
01419     QCString _native_format = nativeFormatMimeType();
01420 
01421     KURL u;
01422     u.setPath( m_file );
01423     QString typeName = KMimeType::findByURL( u, 0, true )->name();
01424 
01425     // Allow to open backup files, don't keep the mimetype application/x-trash.
01426     if ( typeName == "application/x-trash" )
01427     {
01428         QString path = u.path();
01429         QStringList patterns = KMimeType::mimeType( typeName )->patterns();
01430         // Find the extension that makes it a backup file, and remove it
01431         for( QStringList::Iterator it = patterns.begin(); it != patterns.end(); ++it ) {
01432             QString ext = *it;
01433             if ( !ext.isEmpty() && ext[0] == '*' )
01434             {
01435                 ext.remove(0, 1);
01436                 if ( path.endsWith( ext ) ) {
01437                     path.truncate( path.length() - ext.length() );
01438                     break;
01439                 }
01440             }
01441         }
01442         typeName = KMimeType::findByPath( path, 0, true )->name();
01443     }
01444 
01445     // Special case for flat XML files (e.g. using directory store)
01446     if ( u.fileName() == "maindoc.xml" || u.fileName() == "content.xml" || typeName == "inode/directory" )
01447     {
01448         typeName = _native_format; // Hmm, what if it's from another app? ### Check mimetype
01449         d->m_specialOutputFlag = SaveAsDirectoryStore;
01450         kdDebug(30003) << "KoDocument::openFile loading " << u.fileName() << ", using directory store for " << m_file << "; typeName=" << typeName << endl;
01451     }
01452     kdDebug(30003) << "KoDocument::openFile " << m_file << " type:" << typeName << endl;
01453 
01454     QString importedFile = m_file;
01455 
01456     if ( !isNativeFormat( typeName.latin1() ) ) {
01457         if ( !d->filterManager )
01458             d->filterManager = new KoFilterManager( this );
01459         KoFilter::ConversionStatus status;
01460         importedFile = d->filterManager->import( m_file, status );
01461         if ( status != KoFilter::OK )
01462         {
01463             QApplication::restoreOverrideCursor();
01464 
01465             QString msg;
01466             switch( status )
01467             {
01468                 case KoFilter::OK: break;
01469 
01470                 case KoFilter::CreationError:
01471                     msg = i18n( "Creation error" ); break;
01472 
01473                 case KoFilter::FileNotFound:
01474                     msg = i18n( "File not found" ); break;
01475 
01476                 case KoFilter::StorageCreationError:
01477                     msg = i18n( "Cannot create storage" ); break;
01478 
01479                 case KoFilter::BadMimeType:
01480                     msg = i18n( "Bad MIME type" ); break;
01481 
01482                 case KoFilter::EmbeddedDocError:
01483                     msg = i18n( "Error in embedded document" ); break;
01484 
01485                 case KoFilter::WrongFormat:
01486                     msg = i18n( "Format not recognized" ); break;
01487 
01488                 case KoFilter::NotImplemented:
01489                     msg = i18n( "Not implemented" ); break;
01490 
01491                 case KoFilter::ParsingError:
01492                     msg = i18n( "Parsing error" ); break;
01493 
01494                 case KoFilter::PasswordProtected:
01495                     msg = i18n( "Document is password protected" ); break;
01496 
01497                 case KoFilter::InternalError:
01498                 case KoFilter::UnexpectedEOF:
01499                 case KoFilter::UnexpectedOpcode:
01500                 case KoFilter::StupidError: // ?? what is this ??
01501                 case KoFilter::UsageError:
01502                     msg = i18n( "Internal error" ); break;
01503 
01504                 case KoFilter::OutOfMemory:
01505                     msg = i18n( "Out of memory" ); break;
01506 
01507                 case KoFilter::UserCancelled:
01508                 case KoFilter::BadConversionGraph:
01509                     // intentionally we do not prompt the error message here
01510                     break;
01511 
01512                 default: msg = i18n( "Unknown error" ); break;
01513             }
01514 
01515             if( d->m_autoErrorHandlingEnabled && !msg.isEmpty())
01516             {
01517                 QString errorMsg( i18n( "Could not open\n%2.\nReason: %1" ) );
01518                 QString docUrl = url().prettyURL( 0, KURL::StripFileProtocol );
01519                 KMessageBox::error( 0L, errorMsg.arg(msg).arg(docUrl) );
01520             }
01521 
01522             d->m_bLoading = false;
01523             return false;
01524         }
01525         kdDebug(30003) << "KoDocument::openFile - importedFile '" << importedFile
01526                        << "', status: " << static_cast<int>( status ) << endl;
01527     }
01528 
01529     QApplication::restoreOverrideCursor();
01530 
01531     bool ok = true;
01532 
01533     if (!importedFile.isEmpty()) // Something to load (tmp or native file) ?
01534     {
01535         // The filter, if any, has been applied. It's all native format now.
01536         if ( !loadNativeFormat( importedFile ) )
01537         {
01538             ok = false;
01539             if ( d->m_autoErrorHandlingEnabled )
01540             {
01541                 showLoadingErrorDialog();
01542             }
01543         }
01544     }
01545 
01546     if ( importedFile != m_file )
01547     {
01548         // We opened a temporary file (result of an import filter)
01549         // Set document URL to empty - we don't want to save in /tmp !
01550         // But only if in readwrite mode (no saving problem otherwise)
01551         // --
01552         // But this isn't true at all.  If this is the result of an
01553         // import, then importedFile=temporary_file.kwd and
01554         // m_file/m_url=foreignformat.ext so m_url is correct!
01555         // So don't resetURL() or else the caption won't be set when
01556         // foreign files are opened (an annoying bug).
01557         // - Clarence
01558         //
01559 #if 0
01560         if ( isReadWrite() )
01561             resetURL();
01562 #endif
01563 
01564         // remove temp file - uncomment this to debug import filters
01565         if(!importedFile.isEmpty()) {
01566             QFile::remove( importedFile );
01567     }
01568     }
01569 
01570     if ( ok && d->m_bSingleViewMode )
01571     {
01572         // See addClient below
01573         KXMLGUIFactory* guiFactory = factory();
01574         if( guiFactory ) // 0L when splitting views in konq, for some reason
01575             guiFactory->removeClient( this );
01576 
01577         if ( !d->m_views.isEmpty() )
01578         {
01579             // We already had a view (this happens when doing reload in konqueror)
01580             KoView* v = d->m_views.first();
01581             if( guiFactory )
01582                 guiFactory->removeClient( v );
01583             removeView( v );
01584             delete v;
01585             Q_ASSERT( d->m_views.isEmpty() );
01586         }
01587 
01588         KoView *view = createView( d->m_wrapperWidget );
01589         d->m_wrapperWidget->setKoView( view );
01590         view->show();
01591 
01592         // Ok, now we have a view, so action() and domDocument() will work as expected
01593         // -> rebuild GUI
01594         if ( guiFactory )
01595             guiFactory->addClient( this );
01596     }
01597 
01598     if ( ok )
01599     {
01600         setMimeTypeAfterLoading( typeName );
01601     }
01602     d->m_bLoading = false;
01603     return ok;
01604 }
01605 
01606 // shared between openFile and koMainWindow's "create new empty document" code
01607 void KoDocument::setMimeTypeAfterLoading( const QString& mimeType )
01608 {
01609     d->mimeType = mimeType.latin1();
01610 
01611     d->outputMimeType = d->mimeType;
01612 
01613     const bool needConfirm = !isNativeFormat( d->mimeType );
01614     setConfirmNonNativeSave( false, needConfirm  );
01615     setConfirmNonNativeSave( true, needConfirm );
01616 }
01617 
01618 // The caller must call store->close() if loadAndParse returns true.
01619 bool KoDocument::oldLoadAndParse(KoStore* store, const QString& filename, QDomDocument& doc)
01620 {
01621     //kdDebug(30003) << "oldLoadAndParse: Trying to open " << filename << endl;
01622 
01623     if (!store->open(filename))
01624     {
01625         kdWarning(30003) << "Entry " << filename << " not found!" << endl;
01626         d->lastErrorMessage = i18n( "Could not find %1" ).arg( filename );
01627         return false;
01628     }
01629     // Error variables for QDomDocument::setContent
01630     QString errorMsg;
01631     int errorLine, errorColumn;
01632     bool ok = doc.setContent( store->device(), &errorMsg, &errorLine, &errorColumn );
01633     if ( !ok )
01634     {
01635         kdError(30003) << "Parsing error in " << filename << "! Aborting!" << endl
01636             << " In line: " << errorLine << ", column: " << errorColumn << endl
01637             << " Error message: " << errorMsg << endl;
01638         d->lastErrorMessage = i18n( "Parsing error in %1 at line %2, column %3\nError message: %4" )
01639                               .arg( filename ).arg( errorLine ).arg( errorColumn )
01640                               .arg( i18n ( "QXml", errorMsg.utf8() ) );
01641         store->close();
01642         return false;
01643     }
01644     kdDebug(30003) << "File " << filename << " loaded and parsed" << endl;
01645     return true;
01646 }
01647 
01648 bool KoDocument::loadNativeFormat( const QString & file )
01649 {
01650     QFileInfo fileInfo( file );
01651     if ( !fileInfo.exists() ) // check duplicated from openURL, but this is useful for templates
01652     {
01653         d->lastErrorMessage = i18n("The file %1 does not exist.").arg(file);
01654         return false;
01655     }
01656     if ( !fileInfo.isFile() )
01657     {
01658         d->lastErrorMessage = i18n( "%1 is not a file." ).arg(file);
01659         return false;
01660     }
01661 
01662     QApplication::setOverrideCursor( waitCursor );
01663 
01664     kdDebug(30003) << "KoDocument::loadNativeFormat( " << file << " )" << endl;
01665 
01666     QFile in;
01667     bool isRawXML = false;
01668     if ( d->m_specialOutputFlag != SaveAsDirectoryStore ) // Don't try to open a directory ;)
01669     {
01670         in.setName(file);
01671         if ( !in.open( IO_ReadOnly ) )
01672         {
01673             QApplication::restoreOverrideCursor();
01674             d->lastErrorMessage = i18n( "Could not open the file for reading (check read permissions)." );
01675             return false;
01676         }
01677 
01678         // Try to find out whether it is a mime multi part file
01679         char buf[5];
01680         if ( in.readBlock( buf, 4 ) < 4 )
01681         {
01682             QApplication::restoreOverrideCursor();
01683             in.close();
01684             d->lastErrorMessage = i18n( "Could not read the beginning of the file." );
01685             return false;
01686         }
01687         // ### TODO: allow UTF-16
01688         isRawXML = (strncasecmp( buf, "<?xm", 4 ) == 0);
01689         if ( !isRawXML ) {
01690             // Still check for broken MathML files, which seem to be rather common
01691             in.reset();
01692             // Remove spaces
01693             do {
01694                 if ( in.readBlock( buf , 1 ) < 1 )
01695                 {
01696                     QApplication::restoreOverrideCursor();
01697                     in.close();
01698                     d->lastErrorMessage = i18n( "Could not read the beginning of the file." );
01699                     return false;
01700                 }
01701             } while ( QChar( buf[0] ).isSpace() );
01702             if ( buf[0] == '<' ) { // First not-space character
01703                 if ( in.readBlock( buf , 4 ) < 4 )
01704                 {
01705                     QApplication::restoreOverrideCursor();
01706                     in.close();
01707                     d->lastErrorMessage = i18n( "Could not read the beginning of the file." );
01708                     return false;
01709                 }
01710                 isRawXML = (strncasecmp( buf, "math", 4 ) == 0); // file begins with <math ?
01711             }
01712         }
01713         //kdDebug(30003) << "PATTERN=" << buf << endl;
01714     }
01715     // Is it plain XML?
01716     if ( isRawXML )
01717     {
01718         in.at(0);
01719         QString errorMsg;
01720         int errorLine;
01721         int errorColumn;
01722         QDomDocument doc;
01723         bool res;
01724         if ( doc.setContent( &in, true, &errorMsg, &errorLine, &errorColumn ) )
01725         {
01726             res = loadXML( &in, doc );
01727             if ( res )
01728                 res = completeLoading( 0L );
01729         }
01730         else
01731         {
01732             kdError (30003) << "Parsing Error! Aborting! (in KoDocument::loadNativeFormat (QFile))" << endl
01733                             << "  Line: " << errorLine << " Column: " << errorColumn << endl
01734                             << "  Message: " << errorMsg << endl;
01735             d->lastErrorMessage = i18n( "parsing error in the main document at line %1, column %2\nError message: %3" )
01736                                   .arg( errorLine ).arg( errorColumn ).arg( i18n ( errorMsg.utf8() ) );
01737             res=false;
01738         }
01739 
01740         QApplication::restoreOverrideCursor();
01741         in.close();
01742         m_bEmpty = false;
01743         return res;
01744     } else
01745     { // It's a koffice store (tar.gz, zip, directory, etc.)
01746         in.close();
01747 
01748         return loadNativeFormatFromStore( file );
01749     }
01750 }
01751 
01752 bool KoDocument::loadNativeFormatFromStore( const QString& file )
01753 {
01754     KoStore::Backend backend = (d->m_specialOutputFlag == SaveAsDirectoryStore) ? KoStore::Directory : KoStore::Auto;
01755     KoStore * store = KoStore::createStore( file, KoStore::Read, "", backend );
01756 
01757     if ( store->bad() )
01758     {
01759         d->lastErrorMessage = i18n( "Not a valid KOffice file: %1" ).arg( file );
01760         delete store;
01761         QApplication::restoreOverrideCursor();
01762         return false;
01763     }
01764 
01765     bool oasis = true;
01766     // OASIS/OOo file format?
01767     if ( store->hasFile( "content.xml" ) )
01768     {
01769         store->disallowNameExpansion();
01770 
01771         KoOasisStore oasisStore( store );
01772         // We could check the 'mimetype' file, but let's skip that and be tolerant.
01773 
01774         if ( !loadOasisFromStore( store ) ) {
01775             delete store;
01776             QApplication::restoreOverrideCursor();
01777             return false;
01778         }
01779 
01780     } else if ( store->hasFile( "root" ) ) // Fallback to "old" file format (maindoc.xml)
01781     {
01782         oasis = false;
01783 
01784         QDomDocument doc;
01785         bool ok = oldLoadAndParse( store, "root", doc );
01786         if ( ok )
01787             ok = loadXML( store->device(), doc );
01788         if ( !ok )
01789         {
01790             delete store;
01791             QApplication::restoreOverrideCursor();
01792             return false;
01793         }
01794         store->close();
01795 
01796         if ( !loadChildren( store ) )
01797         {
01798             kdError(30003) << "ERROR: Could not load children" << endl;
01799             // Don't abort, proceed nonetheless
01800         }
01801 
01802     } else
01803     {
01804         kdError(30003) << "ERROR: No maindoc.xml" << endl;
01805         d->lastErrorMessage = i18n( "Invalid document: no file 'maindoc.xml'." );
01806         delete store;
01807         QApplication::restoreOverrideCursor();
01808         return false;
01809     }
01810 
01811     if ( oasis && store->hasFile( "meta.xml" ) ) {
01812         QDomDocument metaDoc;
01813         KoOasisStore oasisStore( store );
01814         if ( oasisStore.loadAndParse( "meta.xml", metaDoc, d->lastErrorMessage ) ) {
01815             d->m_docInfo->loadOasis( metaDoc );
01816         }
01817     }
01818     else if ( !oasis && store->hasFile( "documentinfo.xml" ) )
01819     {
01820         QDomDocument doc;
01821         if ( oldLoadAndParse( store, "documentinfo.xml", doc ) ) {
01822             store->close();
01823             d->m_docInfo->load( doc );
01824         }
01825     }
01826     else
01827     {
01828         //kdDebug( 30003 ) << "cannot open document info" << endl;
01829         delete d->m_docInfo;
01830         d->m_docInfo = new KoDocumentInfo( this, "document info" );
01831     }
01832 
01833     bool res = completeLoading( store );
01834     delete store;
01835     QApplication::restoreOverrideCursor();
01836     m_bEmpty = false;
01837     return res;
01838 }
01839 
01840 // For embedded documents
01841 bool KoDocument::loadFromStore( KoStore* _store, const QString& url )
01842 {
01843     if ( _store->open( url ) )
01844     {
01845         QDomDocument doc;
01846         doc.setContent( _store->device() );
01847         if ( !loadXML( _store->device(), doc ) )
01848         {
01849             _store->close();
01850             return false;
01851         }
01852         _store->close();
01853     } else {
01854         kdWarning() << "couldn't open " << url << endl;
01855     }
01856 
01857     _store->pushDirectory();
01858     // Store as document URL
01859     if ( url.startsWith( STORE_PROTOCOL ) ) {
01860         m_url = KURL( url );
01861     } else {
01862         m_url = KURL( INTERNAL_PREFIX + url );
01863         _store->enterDirectory( url );
01864     }
01865 
01866     if ( !loadChildren( _store ) )
01867     {
01868         kdError(30003) << "ERROR: Could not load children" << endl;
01869 #if 0
01870         return false;
01871 #endif
01872     }
01873 
01874     bool result = completeLoading( _store );
01875 
01876     // Restore the "old" path
01877     _store->popDirectory();
01878 
01879     return result;
01880 }
01881 
01882 bool KoDocument::loadOasisFromStore( KoStore* store )
01883 {
01884     KoOasisStyles oasisStyles;
01885     QDomDocument contentDoc;
01886     QDomDocument settingsDoc;
01887     KoOasisStore oasisStore( store );
01888     bool ok = oasisStore.loadAndParse( "content.xml", contentDoc, d->lastErrorMessage );
01889     if ( !ok )
01890         return false;
01891 
01892     QDomDocument stylesDoc;
01893     (void)oasisStore.loadAndParse( "styles.xml", stylesDoc, d->lastErrorMessage );
01894     // Load styles from style.xml
01895     oasisStyles.createStyleMap( stylesDoc, true );
01896     // Also load styles from content.xml
01897     oasisStyles.createStyleMap( contentDoc, false );
01898 
01899     // TODO post 1.4, pass manifestDoc to the apps so that they don't have to do it themselves
01900     // (when calling KoDocumentChild::loadOasisDocument)
01901     //QDomDocument manifestDoc;
01902     //KoOasisStore oasisStore( store );
01903     //if ( !oasisStore.loadAndParse( "tar:/META-INF/manifest.xml", manifestDoc, d->lastErrorMessage ) )
01904     //    return false;
01905 
01906     if ( store->hasFile( "settings.xml" ) ) {
01907         (void)oasisStore.loadAndParse( "settings.xml", settingsDoc, d->lastErrorMessage );
01908     }
01909     if ( !loadOasis( contentDoc, oasisStyles, settingsDoc, store ) )
01910         return false;
01911 
01912     return true;
01913 }
01914 
01915 bool KoDocument::isInOperation() const
01916 {
01917     return d->m_numOperations > 0;
01918 }
01919 
01920 void KoDocument::emitBeginOperation()
01921 {
01922 
01923     /* if we're already in an operation, don't send the signal again */
01924     if (!isInOperation())
01925         emit sigBeginOperation();
01926     d->m_numOperations++;
01927 }
01928 
01929 void KoDocument::emitEndOperation()
01930 {
01931     d->m_numOperations--;
01932 
01933     /* don't end the operation till we've cleared all the nested operations */
01934     if (d->m_numOperations == 0)
01935         emit sigEndOperation();
01936     else if (d->m_numOperations < 0)
01937         /* ignore 'end' calls with no matching 'begin' call */
01938         d->m_numOperations = 0;
01939 }
01940 
01941 
01942 bool KoDocument::isStoredExtern() const
01943 {
01944     return !storeInternal() && hasExternURL();
01945 }
01946 
01947 void KoDocument::setModified( bool mod )
01948 {
01949     if ( isAutosaving() ) // ignore setModified calls due to autosaving
01950         return;
01951 
01952     //kdDebug(30003)<<k_funcinfo<<" url:" << m_url.path() << endl;
01953     //kdDebug(30003)<<k_funcinfo<<" mod="<<mod<<" MParts mod="<<KParts::ReadWritePart::isModified()<<" isModified="<<isModified()<<endl;
01954 
01955     if ( mod && !d->modifiedAfterAutosave ) {
01956         // First change since last autosave -> start the autosave timer
01957         setAutoSave( d->m_autoSaveDelay );
01958     }
01959     d->modifiedAfterAutosave = mod;
01960 
01961     if ( mod == isModified() )
01962         return;
01963 
01964     KParts::ReadWritePart::setModified( mod );
01965 
01966     if ( mod ) {
01967         m_bEmpty = FALSE;
01968     } else {
01969         // When saving this document, all non-external child documents get saved too.
01970         QPtrListIterator<KoDocumentChild> it = children();
01971         for (; it.current(); ++it )
01972         {
01973             KoDocument *doc = it.current()->document();
01974             if ( doc && !it.current()->isStoredExtern() && !it.current()->isDeleted() && doc->isModified() )
01975                 doc->setModified( false );
01976         }
01977     }
01978 
01979     // This influences the title
01980     setTitleModified();
01981     emit modified( mod );
01982 }
01983 
01984 void KoDocument::setDoNotSaveExtDoc( bool on )
01985 {
01986     d->m_doNotSaveExtDoc = on;
01987 }
01988 
01989 int KoDocument::queryCloseDia()
01990 {
01991     //kdDebug(30003)<<k_funcinfo<<endl;
01992 
01993     QString name;
01994     if ( documentInfo() )
01995     {
01996         name = documentInfo()->title();
01997     }
01998     if ( name.isEmpty() )
01999         name = url().fileName();
02000 
02001     if ( name.isEmpty() )
02002         name = i18n( "Untitled" );
02003 
02004     int res = KMessageBox::warningYesNoCancel( 0L,
02005                     i18n( "<p>The document <b>'%1'</b> has been modified.</p><p>Do you want to save it?</p>" ).arg(name));
02006 
02007     switch(res)
02008     {
02009         case KMessageBox::Yes :
02010             setDoNotSaveExtDoc(); // Let save() only save myself and my internal docs
02011             save(); // NOTE: External files always in native format. ###TODO: Handle non-native format
02012             setModified( false ); // Now when queryClose() is called by closeEvent it won't do anything.
02013             break;
02014         case KMessageBox::No :
02015             removeAutoSaveFiles();
02016             setModified( false ); // Now when queryClose() is called by closeEvent it won't do anything.
02017             break;
02018         default : // case KMessageBox::Cancel :
02019             return res; // cancels the rest of the files
02020     }
02021     return res;
02022 }
02023 
02024 int KoDocument::queryCloseExternalChildren()
02025 {
02026     //kdDebug(30003)<<k_funcinfo<<" checking for children in: "<<url().url()<<endl;
02027     setDoNotSaveExtDoc(false);
02028     QPtrListIterator<KoDocumentChild> it( children() );
02029     for (; it.current(); ++it )
02030     {
02031         if ( !it.current()->isDeleted() )
02032         {
02033             KoDocument *doc = it.current()->document();
02034             if ( doc )
02035             {
02036         bool foo = doc->isStoredExtern();
02037         kdDebug(36001) << "========== isStoredExtern() returned "
02038                    << foo << " ==========" << endl;
02039 
02040                 if ( foo ) //###TODO: Handle non-native mimetype docs
02041                 {
02042                     {
02043                         kdDebug(30003)<<k_funcinfo<<" found modified child: "<<doc->url().url()<<" extern="<<doc->isStoredExtern()<<endl;
02044                         if ( doc->queryCloseDia() == KMessageBox::Cancel )
02045                             return  KMessageBox::Cancel;
02046                     }
02047                 }
02048                 if ( doc->queryCloseExternalChildren() == KMessageBox::Cancel )
02049                     return KMessageBox::Cancel;
02050             }
02051         }
02052     }
02053     return KMessageBox::Ok;
02054 }
02055 
02056 void KoDocument::setTitleModified( const QString caption, bool mod )
02057 {
02058     //kdDebug(30003)<<k_funcinfo<<" url: "<<url().url()<<" caption: "<<caption<<" mod: "<<mod<<endl;
02059     KoDocument *doc = dynamic_cast<KoDocument *>( parent() );
02060     if ( doc )
02061     {
02062         doc->setTitleModified( caption, mod );
02063         return;
02064     }
02065     // we must be root doc so update caption in all related windows
02066     QPtrListIterator<KoMainWindow> it( d->m_shells );
02067     for (; it.current(); ++it )
02068     {
02069         it.current()->updateCaption();
02070         it.current()->updateReloadFileAction(this);
02071         it.current()->updateVersionsFileAction(this);
02072     }
02073 }
02074 
02075 void KoDocument::setTitleModified()
02076 {
02077     //kdDebug(30003)<<k_funcinfo<<" url: "<<url().url()<<" extern: "<<isStoredExtern()<<" current: "<<d->m_current<<endl;
02078     KoDocument *doc = dynamic_cast<KoDocument *>( parent() );
02079     QString caption;
02080     if ( (url().isEmpty() || isStoredExtern()) && d->m_current )
02081     {
02082         // Get caption from document info (title(), in about page)
02083         if ( documentInfo() )
02084         {
02085             KoDocumentInfoPage * page = documentInfo()->page( QString::fromLatin1("about") );
02086             if (page)
02087                 caption = static_cast<KoDocumentInfoAbout *>(page)->title();
02088         }
02089         if ( caption.isEmpty() )
02090             caption = url().prettyURL( 0, KURL::StripFileProtocol );             // Fall back to document URL
02091 
02092         //kdDebug(30003)<<k_funcinfo<<" url: "<<url().url()<<" caption: "<<caption<<endl;
02093         if ( doc )
02094         {
02095             doc->setTitleModified( caption, isModified() );
02096             return;
02097         }
02098         else
02099         {
02100             // we must be root doc so update caption in all related windows
02101             setTitleModified( caption, isModified() );
02102             return;
02103         }
02104     }
02105     if ( doc )
02106     {
02107         // internal doc or not current doc, so pass on the buck
02108         doc->setTitleModified();
02109     }
02110 }
02111 
02112 bool KoDocument::loadChildren( KoStore* )
02113 {
02114     return true;
02115 }
02116 
02117 bool KoDocument::completeLoading( KoStore* )
02118 {
02119     return true;
02120 }
02121 
02122 bool KoDocument::completeSaving( KoStore* )
02123 {
02124     return true;
02125 }
02126 
02127 QDomDocument KoDocument::createDomDocument( const QString& tagName, const QString& version ) const
02128 {
02129     return createDomDocument( instance()->instanceName(), tagName, version );
02130 }
02131 
02132 //static
02133 QDomDocument KoDocument::createDomDocument( const QString& appName, const QString& tagName, const QString& version )
02134 {
02135     QDomImplementation impl;
02136     QString url = QString("http://www.koffice.org/DTD/%1-%1.dtd").arg(appName).arg(version);
02137     QDomDocumentType dtype = impl.createDocumentType( tagName,
02138                                                       QString("-//KDE//DTD %1 %1//EN").arg(appName).arg(version),
02139                                                       url );
02140     // The namespace URN doesn't need to include the version number.
02141     QString namespaceURN = QString("http://www.koffice.org/DTD/%1").arg(appName);
02142     QDomDocument doc = impl.createDocument( namespaceURN, tagName, dtype );
02143     doc.insertBefore( doc.createProcessingInstruction( "xml", "version=\"1.0\" encoding=\"UTF-8\"" ), doc.documentElement() );
02144     return doc;
02145 }
02146 
02147 KoXmlWriter* KoDocument::createOasisXmlWriter( QIODevice* dev, const char* rootElementName )
02148 {
02149     KoXmlWriter* writer = new KoXmlWriter( dev );
02150     writer->startDocument( rootElementName );
02151     writer->startElement( rootElementName );
02152     writer->addAttribute( "xmlns:office", KoXmlNS::office );
02153     writer->addAttribute( "xmlns:meta", KoXmlNS::meta );
02154 
02155     if ( qstrcmp( rootElementName, "office:document-meta" ) != 0 ) {
02156         writer->addAttribute( "xmlns:config", KoXmlNS::config );
02157         writer->addAttribute( "xmlns:text", KoXmlNS::text );
02158         writer->addAttribute( "xmlns:table", KoXmlNS::table );
02159         writer->addAttribute( "xmlns:draw", KoXmlNS::draw );
02160         writer->addAttribute( "xmlns:presentation", KoXmlNS::presentation );
02161         writer->addAttribute( "xmlns:dr3d", KoXmlNS::dr3d );
02162         writer->addAttribute( "xmlns:chart", KoXmlNS::chart );
02163         writer->addAttribute( "xmlns:form", KoXmlNS::form );
02164         writer->addAttribute( "xmlns:script", KoXmlNS::script );
02165         writer->addAttribute( "xmlns:style", KoXmlNS::style );
02166         writer->addAttribute( "xmlns:number", KoXmlNS::number );
02167         writer->addAttribute( "xmlns:math", KoXmlNS::math );
02168         writer->addAttribute( "xmlns:svg", KoXmlNS::svg );
02169         writer->addAttribute( "xmlns:fo", KoXmlNS::fo );
02170         writer->addAttribute( "xmlns:koffice", KoXmlNS::koffice );
02171     }
02172     // missing: office:version="1.0"
02173 
02174     writer->addAttribute( "xmlns:dc", KoXmlNS::dc );
02175     writer->addAttribute( "xmlns:xlink", KoXmlNS::xlink );
02176     return writer;
02177 }
02178 
02179 QDomDocument KoDocument::saveXML()
02180 {
02181     kdError(30003) << "KoDocument::saveXML not implemented" << endl;
02182     d->lastErrorMessage = i18n( "Internal error: saveXML not implemented" );
02183     return QDomDocument();
02184 }
02185 
02186 KService::Ptr KoDocument::nativeService()
02187 {
02188     if ( !m_nativeService )
02189         m_nativeService = readNativeService( instance() );
02190 
02191     return m_nativeService;
02192 }
02193 
02194 QCString KoDocument::nativeFormatMimeType() const
02195 {
02196     KService::Ptr service = const_cast<KoDocument *>(this)->nativeService();
02197     if ( !service )
02198         return QCString();
02199     QCString nativeMimeType = service->property( "X-KDE-NativeMimeType" ).toString().latin1();
02200     if ( nativeMimeType.isEmpty() ) {
02201         // shouldn't happen, let's find out why it happened
02202         if ( !service->serviceTypes().contains( "KOfficePart" ) )
02203             kdWarning(30003) << "Wrong desktop file, KOfficePart isn't mentionned" << endl;
02204         else if ( !KServiceType::serviceType( "KOfficePart" ) )
02205             kdWarning(30003) << "The KOfficePart service type isn't installed!" << endl;
02206     }
02207     return nativeMimeType;
02208 }
02209 
02210 QCString KoDocument::nativeOasisMimeType() const
02211 {
02212     KService::Ptr service = const_cast<KoDocument *>(this)->nativeService();
02213     if ( !service )
02214         return QCString();
02215     return service->property( "X-KDE-NativeOasisMimeType" ).toString().latin1();
02216 }
02217 
02218 
02219 //static
02220 KService::Ptr KoDocument::readNativeService( KInstance *instance )
02221 {
02222     QString instname = instance ? instance->instanceName() : kapp->instanceName();
02223 
02224     // The new way is: we look for a foopart.desktop in the kde_services dir.
02225     QString servicepartname = instname + "part.desktop";
02226     KService::Ptr service = KService::serviceByDesktopPath( servicepartname );
02227     if ( service )
02228         kdDebug(30003) << servicepartname << " found." << endl;
02229     if ( !service )
02230     {
02231         // The old way is kept as fallback for compatibility, but in theory this is really never used anymore.
02232 
02233         // Try by path first, so that we find the global one (which has the native mimetype)
02234         // even if the user created a kword.desktop in ~/.kde/share/applnk or any subdir of it.
02235         // If he created it under ~/.kde/share/applnk/Office/ then no problem anyway.
02236         service = KService::serviceByDesktopPath( QString::fromLatin1("Office/%1.desktop").arg(instname) );
02237     }
02238     if ( !service )
02239         service = KService::serviceByDesktopName( instname );
02240 
02241     return service;
02242 }
02243 
02244 QCString KoDocument::readNativeFormatMimeType( KInstance *instance ) //static
02245 {
02246     KService::Ptr service = readNativeService( instance );
02247     if ( !service )
02248         return QCString();
02249 
02250     if ( service->property( "X-KDE-NativeMimeType" ).toString().isEmpty() )
02251     {
02252         // It may be that the servicetype "KOfficePart" is missing, which leads to this property not being known
02253         if ( KServiceType::serviceType( "KOfficePart" ) == 0L )
02254             kdError(30003) << "The serviceType KOfficePart is missing. Check that you have a kofficepart.desktop file in the share/servicetypes directory." << endl;
02255         else {
02256             QString instname = instance ? instance->instanceName() : kapp->instanceName();
02257             if ( instname != "koshell" ) // hack for koshell
02258                 kdWarning(30003) << service->desktopEntryPath() << ": no X-KDE-NativeMimeType entry!" << endl;
02259         }
02260     }
02261 
02262     return service->property( "X-KDE-NativeMimeType" ).toString().latin1();
02263 }
02264 
02265 QStringList KoDocument::readExtraNativeMimeTypes( KInstance *instance ) //static
02266 {
02267     KService::Ptr service = readNativeService( instance );
02268     if ( !service )
02269         return QStringList();
02270     return service->property( "X-KDE-ExtraNativeMimeTypes" ).toStringList();
02271 }
02272 
02273 void KoDocument::setupXmlReader( QXmlSimpleReader& reader, bool namespaceProcessing )
02274 {
02275     if ( namespaceProcessing )
02276     {
02277         reader.setFeature( "http://xml.org/sax/features/namespaces", TRUE );
02278         reader.setFeature( "http://xml.org/sax/features/namespace-prefixes", FALSE );
02279     }
02280     else
02281     {
02282         reader.setFeature( "http://xml.org/sax/features/namespaces", FALSE );
02283         reader.setFeature( "http://xml.org/sax/features/namespace-prefixes", TRUE );
02284     }
02285     reader.setFeature( "http://trolltech.com/xml/features/report-whitespace-only-CharData", TRUE );
02286 }
02287 
02288 
02289 bool KoDocument::isNativeFormat( const QCString& mimetype ) const
02290 {
02291     if ( mimetype == nativeFormatMimeType() )
02292         return true;
02293     return extraNativeMimeTypes().contains( mimetype );
02294 }
02295 
02296 QStringList KoDocument::extraNativeMimeTypes() const
02297 {
02298     QStringList lst;
02299     // This implementation is temporary while we treat both koffice-1.3 and OASIS formats as native.
02300     // But it's good to have this virtual method, in case some app want to
02301     // support more than one native format.
02302     KService::Ptr service = const_cast<KoDocument *>(this)->nativeService();
02303     if ( !service ) // can't happen
02304         return lst;
02305     return service->property( "X-KDE-ExtraNativeMimeTypes" ).toStringList();
02306 }
02307 
02308 int KoDocument::supportedSpecialFormats() const
02309 {
02310     // Apps which support special output flags can add reimplement and add to this.
02311     // E.g. this is how did "saving in the 1.1 format".
02312     // SaveAsDirectoryStore is a given since it's implemented by KoDocument itself.
02313     return SaveAsDirectoryStore;
02314 }
02315 
02316 void KoDocument::addShell( KoMainWindow *shell )
02317 {
02318     if ( d->m_shells.findRef( shell ) == -1 )
02319     {
02320         //kdDebug(30003) << "addShell: shell " << (void*)shell << " added to doc " << this << endl;
02321         d->m_shells.append( shell );
02322     }
02323 }
02324 
02325 void KoDocument::removeShell( KoMainWindow *shell )
02326 {
02327     //kdDebug(30003) << "removeShell: shell " << (void*)shell << " removed from doc " << this << endl;
02328     d->m_shells.removeRef( shell );
02329 }
02330 
02331 const QPtrList<KoMainWindow>& KoDocument::shells() const
02332 {
02333     return d->m_shells;
02334 }
02335 
02336 int KoDocument::shellCount() const
02337 {
02338     return d->m_shells.count();
02339 }
02340 
02341 DCOPObject * KoDocument::dcopObject()
02342 {
02343     if ( !d->m_dcopObject )
02344         d->m_dcopObject = new KoDocumentIface( this );
02345     return d->m_dcopObject;
02346 }
02347 
02348 QCString KoDocument::dcopObjectId() const
02349 {
02350     return const_cast<KoDocument *>(this)->dcopObject()->objId();
02351 }
02352 
02353 void KoDocument::setErrorMessage( const QString& errMsg )
02354 {
02355     d->lastErrorMessage = errMsg;
02356 }
02357 
02358 QString KoDocument::errorMessage() const
02359 {
02360     return d->lastErrorMessage;
02361 }
02362 
02363 void KoDocument::showSavingErrorDialog()
02364 {
02365     if ( d->lastErrorMessage.isEmpty() )
02366     {
02367         KMessageBox::error( 0L, i18n( "Could not save\n%1" ).arg( m_file ) );
02368     }
02369     else if ( d->lastErrorMessage != "USER_CANCELED" )
02370     {
02371         KMessageBox::error( 0L, i18n( "Could not save %1\nReason: %2" ).arg( m_file, d->lastErrorMessage ) );
02372     }
02373 }
02374 
02375 void KoDocument::showLoadingErrorDialog()
02376 {
02377     if ( d->lastErrorMessage.isEmpty() )
02378     {
02379         KMessageBox::error( 0L, i18n( "Could not open\n%1" ).arg( url().prettyURL( 0, KURL::StripFileProtocol ) ) );
02380     }
02381     else if ( d->lastErrorMessage != "USER_CANCELED" )
02382     {
02383         KMessageBox::error( 0L, i18n( "Could not open %1\nReason: %2" ).arg( url().prettyURL( 0, KURL::StripFileProtocol ), d->lastErrorMessage ) );
02384     }
02385 }
02386 
02387 bool KoDocument::isAutosaving() const
02388 {
02389     return d->m_autosaving;
02390 }
02391 
02392 bool KoDocument::isLoading() const
02393 {
02394     return d->m_bLoading;
02395 }
02396 
02397 void KoDocument::removeAutoSaveFiles()
02398 {
02399         // Eliminate any auto-save file
02400         QString asf = autoSaveFile( m_file ); // the one in the current dir
02401         if ( QFile::exists( asf ) )
02402             QFile::remove( asf );
02403         asf = autoSaveFile( QString::null ); // and the one in $HOME
02404         if ( QFile::exists( asf ) )
02405             QFile::remove( asf );
02406 }
02407 
02408 void KoDocument::setBackupFile( bool _b )
02409 {
02410     d->m_backupFile = _b;
02411 }
02412 
02413 bool KoDocument::backupFile()const
02414 {
02415     return d->m_backupFile;
02416 }
02417 
02418 
02419 void KoDocument::setBackupPath( const QString & _path)
02420 {
02421     d->m_backupPath = _path;
02422 }
02423 
02424 QString KoDocument::backupPath()const
02425 {
02426     return d->m_backupPath;
02427 }
02428 
02429 void KoDocument::setCurrent( bool on )
02430 {
02431     //kdDebug(30003)<<k_funcinfo<<" url: "<<url().url()<<" set to: "<<on<<endl;
02432     KoDocument *doc = dynamic_cast<KoDocument *>( parent() );
02433     if ( doc )
02434     {
02435         if ( !isStoredExtern() )
02436         {
02437             // internal doc so set next external to current (for safety)
02438             doc->setCurrent( true );
02439             return;
02440         }
02441         // only externally stored docs shall have file name in title
02442         d->m_current = on;
02443         if ( !on )
02444         {
02445             doc->setCurrent( true );    // let my next external parent take over
02446             return;
02447         }
02448         doc->forceCurrent( false ); // everybody else should keep off
02449     }
02450     else
02451         d->m_current = on;
02452 
02453     setTitleModified();
02454 }
02455 
02456 void KoDocument::forceCurrent( bool on )
02457 {
02458     //kdDebug(30003)<<k_funcinfo<<" url: "<<url().url()<<" force to: "<<on<<endl;
02459     d->m_current = on;
02460     KoDocument *doc = dynamic_cast<KoDocument *>( parent() );
02461     if ( doc )
02462     {
02463         doc->forceCurrent( false );
02464     }
02465 }
02466 
02467 bool KoDocument::isCurrent() const
02468 {
02469     return d->m_current;
02470 }
02471 
02472 bool KoDocument::storeInternal() const
02473 {
02474     return d->m_storeInternal;
02475 }
02476 
02477 void KoDocument::setStoreInternal( bool i )
02478 {
02479     d->m_storeInternal = i;
02480     //kdDebug(30003)<<k_funcinfo<<"="<<d->m_storeInternal<<" doc: "<<url().url()<<endl;
02481 }
02482 
02483 bool KoDocument::hasExternURL() const
02484 {
02485     return !url().protocol().isEmpty() && url().protocol() != STORE_PROTOCOL && url().protocol() != INTERNAL_PROTOCOL;
02486 }
02487 
02488 void KoDocument::slotStarted( KIO::Job* job )
02489 {
02490     if ( job )
02491     {
02492         job->setWindow( d->m_shells.current() );
02493     }
02494 }
02495 
02496 static const struct {
02497     const char* localName;
02498     const char* documentType;
02499 } TN2DTArray[] = {
02500     { "text", I18N_NOOP( "a word processing" ) },
02501     { "spreadsheet", I18N_NOOP( "a spreadsheet" ) },
02502     { "presentation", I18N_NOOP( "a presentation" ) },
02503     { "chart", I18N_NOOP( "a chart" ) },
02504     { "drawing", I18N_NOOP( "a drawing" ) }
02505 };
02506 static const unsigned int numTN2DT = sizeof( TN2DTArray ) / sizeof( *TN2DTArray );
02507 
02508 QString KoDocument::tagNameToDocumentType( const QString& localName )
02509 {
02510     for ( unsigned int i = 0 ; i < numTN2DT ; ++i )
02511         if ( localName == TN2DTArray[i].localName )
02512             return i18n( TN2DTArray[i].documentType );
02513     return localName;
02514 }
02515 
02516 QValueList<KoTextDocument *> KoDocument::allTextDocuments() const
02517 {
02518     return QValueList<KoTextDocument *>();
02519 }
02520 
02521 KoPageLayout KoDocument::pageLayout(int /*pageNumber*/) const
02522 {
02523     return m_pageLayout;
02524 }
02525 
02526 KoUnit::Unit KoDocument::unit() const
02527 {
02528     return d->m_unit;
02529 }
02530 
02531 void KoDocument::setUnit( KoUnit::Unit unit )
02532 {
02533     if ( d->m_unit != unit )
02534     {
02535         d->m_unit = unit;
02536         emit unitChanged( unit );
02537     }
02538 }
02539 
02540 QString KoDocument::unitName() const
02541 {
02542     return KoUnit::unitName( unit() );
02543 }
02544 
02545 void KoDocument::showStartUpWidget( KoMainWindow* parent, bool alwaysShow )
02546 {
02547     if(!alwaysShow) {
02548         KConfigGroup cfgGrp( instance()->config(), "TemplateChooserDialog" );
02549         QString fullTemplateName = cfgGrp.readPathEntry( "AlwaysUseTemplate" );
02550 
02551         if( !fullTemplateName.isEmpty() ) {
02552             openTemplate( fullTemplateName );
02553             shells().getFirst()->setRootDocument( this );
02554             return;
02555         }
02556     }
02557 
02558     if(d->m_startUpWidget){
02559         d->m_startUpWidget->show();
02560     } else {
02561         d->m_startUpWidget = createOpenPane( parent->centralWidget(), instance(), templateType() );
02562     }
02563 
02564     parent->setDocToOpen( this );
02565     parent->factory()->container("mainToolBar", parent)->hide();
02566 }
02567 
02568 void KoDocument::openExistingFile( const QString& file )
02569 {
02570     KURL url( file );
02571     bool ok = openURL( url );
02572     setModified( false );
02573 
02574     if( ok )
02575         QTimer::singleShot( 0, this, SLOT( deleteOpenPane() ) );
02576 }
02577 
02578 void KoDocument::openTemplate( const QString& file )
02579 {
02580     bool ok = loadNativeFormat( file );
02581     setModified( false );
02582 
02583     if ( ok ) {
02584         deleteOpenPane();
02585         resetURL();
02586         setEmpty();
02587     } else {
02588         showLoadingErrorDialog();
02589         initEmpty();
02590     }
02591 }
02592 
02593 void KoDocument::initEmpty()
02594 {
02595     setEmpty();
02596     setModified(false);
02597 }
02598 
02599 void KoDocument::startCustomDocument() {
02600     deleteOpenPane();
02601 }
02602 
02603 KoOpenPane* KoDocument::createOpenPane( QWidget* parent, KInstance* instance,
02604                                         const QString& templateType )
02605 {
02606     KoOpenPane* openPane = new KoOpenPane( parent, instance, templateType );
02607     QWidget *customDoc = createCustomDocumentWidget(openPane);
02608     if(customDoc) {
02609         openPane->setCustomDocumentWidget( customDoc );
02610         connect( customDoc, SIGNAL( documentSelected() ), this, SLOT( startCustomDocument() ) );
02611     }
02612     openPane->show();
02613 
02614     connect( openPane, SIGNAL( openExistingFile( const QString& ) ),
02615              this, SLOT( openExistingFile( const QString& ) ) );
02616     connect( openPane, SIGNAL( openTemplate( const QString& ) ),
02617              this, SLOT( openTemplate( const QString& ) ) );
02618 
02619     return openPane;
02620 }
02621 
02622 void KoDocument::setTemplateType( const QString& _templateType )
02623 {
02624     d->m_templateType = _templateType;
02625 }
02626 
02627 QString KoDocument::templateType() const
02628 {
02629     return d->m_templateType;
02630 }
02631 
02632 void KoDocument::deleteOpenPane()
02633 {
02634     if( d->m_startUpWidget ) {
02635         d->m_startUpWidget->hide();
02636         QTimer::singleShot(1000, this, SLOT(deleteOpenPaneDelayed()));
02637 
02638         shells().getFirst()->factory()->container("mainToolBar", shells().getFirst())->show();
02639         shells().getFirst()->setRootDocument( this );
02640     } else {
02641       emit closeEmbedInitDialog();
02642     }
02643 }
02644 
02645 void KoDocument::deleteOpenPaneDelayed()
02646 {
02647     delete d->m_startUpWidget;
02648     d->m_startUpWidget = 0;
02649 }
02650 
02651 QWidget* KoDocument::createCustomDocumentWidget(QWidget */*parent*/) {
02652     return 0;
02653 }
02654 
02655 bool KoDocument::showEmbedInitDialog(QWidget* parent)
02656 {
02657     KDialogBase dlg(parent, "EmbedInitDialog", true, i18n("Embedding Object"), 0, KDialogBase::NoDefault);
02658     KoOpenPane* pane = createOpenPane(&dlg, instance(), templateType());
02659     pane->layout()->setMargin(0);
02660     dlg.setMainWidget(pane);
02661     dlg.setInitialSize(dlg.configDialogSize("EmbedInitDialog"));
02662     connect(this, SIGNAL(closeEmbedInitDialog()), &dlg, SLOT(slotOk()));
02663 
02664     bool ok = dlg.exec() == QDialog::Accepted;
02665 
02666     dlg.saveDialogSize("EmbedInitDialog");
02667 
02668     return ok;
02669 }
02670 
02671 #include "KoDocument_p.moc"
02672 #include "KoDocument.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys